Loading nixos/modules/services/web-apps/firefly-iii.nix +52 −39 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ let inherit (lib) optionalString mkDefault mkIf mkOption mkEnableOption literalExpression; inherit (lib.types) nullOr attrsOf oneOf str int bool path package enum submodule; inherit (lib.strings) concatMapStringsSep removePrefix toShellVars removeSuffix hasSuffix; inherit (lib.attrsets) attrValues genAttrs filterAttrs mapAttrs' nameValuePair; inherit (lib.strings) concatLines removePrefix toShellVars removeSuffix hasSuffix; inherit (lib.attrsets) mapAttrsToList attrValues genAttrs filterAttrs mapAttrs' nameValuePair; inherit (builtins) isInt isString toString typeOf; cfg = config.services.firefly-iii; Loading @@ -21,18 +21,10 @@ let (filterAttrs (n: v: hasSuffix "_FILE" n) cfg.settings); env-nonfile-values = filterAttrs (n: v: ! hasSuffix "_FILE" n) cfg.settings; envfile = pkgs.writeText "firefly-iii-env" '' ${toShellVars env-file-values} ${toShellVars env-nonfile-values} ''; fileenv-func = '' cp --no-preserve=mode ${envfile} /tmp/firefly-iii-env ${concatMapStringsSep "\n" (n: "${pkgs.replace-secret}/bin/replace-secret ${n} ${n} /tmp/firefly-iii-env") (attrValues env-file-values)} set -a . /tmp/firefly-iii-env ${toShellVars env-nonfile-values} ${concatLines (mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values)} set +a ''; Loading @@ -41,15 +33,13 @@ let ${optionalString (cfg.settings.DB_CONNECTION == "sqlite") "touch ${cfg.dataDir}/storage/database/database.sqlite"} ${artisan} migrate --seed --no-interaction --force ${artisan} firefly-iii:decrypt-all ${artisan} package:discover ${artisan} firefly-iii:upgrade-database ${artisan} firefly-iii:correct-database ${artisan} firefly-iii:report-integrity ${artisan} firefly-iii:laravel-passport-keys ${artisan} cache:clear mv /tmp/firefly-iii-env /run/phpfpm/firefly-iii-env ${artisan} view:cache ${artisan} route:cache ${artisan} config:cache ''; commonServiceConfig = { Loading Loading @@ -146,6 +136,7 @@ in { virtualHost = mkOption { type = str; default = "localhost"; description = '' The hostname at which you wish firefly-iii to be served. If you have enabled nginx using `services.firefly-iii.enableNginx` then this will Loading @@ -170,14 +161,15 @@ in { }; settings = mkOption { default = {}; description = '' Options for firefly-iii configuration. Refer to <https://github.com/firefly-iii/firefly-iii/blob/main/.env.example> for details on supported values. All <option>_FILE values supported by upstream are supported here. APP_URL will be set by `services.firefly-iii.virtualHost`, do not redefine it here. APP_URL will be the same as `services.firefly-iii.virtualHost` if the former is unset in `services.firefly-iii.settings`. ''; example = literalExpression '' { Loading @@ -192,7 +184,6 @@ in { DB_PASSWORD_FILE = "/var/secrets/firefly-iii-mysql-password.txt; } ''; default = {}; type = submodule { freeformType = attrsOf (oneOf [str int bool]); options = { Loading @@ -216,9 +207,9 @@ in { }; DB_PORT = mkOption { type = nullOr int; default = if cfg.settings.DB_CONNECTION == "sqlite" then null default = if cfg.settings.DB_CONNECTION == "pgsql" then 5432 else if cfg.settings.DB_CONNECTION == "mysql" then 3306 else 5432; else null; defaultText = '' `null` if DB_CONNECTION is "sqlite", `3306` if "mysql", `5432` if "pgsql" ''; Loading @@ -227,6 +218,21 @@ in { this value to be filled. ''; }; DB_HOST = mkOption { type = str; default = if cfg.settings.DB_CONNECTION == "pgsql" then "/run/postgresql" else "localhost"; defaultText = '' "localhost" if DB_CONNECTION is "sqlite" or "mysql", "/run/postgresql" if "pgsql". ''; description = '' The machine which hosts your database. This is left at the default value for "mysql" because we use the "DB_SOCKET" option to connect to a unix socket instead. "pgsql" requires that the unix socket location be specified here instead of at "DB_SOCKET". This option does not affect "sqlite". ''; }; APP_KEY_FILE = mkOption { type = path; description = '' Loading @@ -235,6 +241,20 @@ in { /dev/urandom | base64)" > /path/to/key-file`. ''; }; APP_URL = mkOption { type = str; default = if cfg.virtualHost == "localhost" then "http://${cfg.virtualHost}" else "https://${cfg.virtualHost}"; defaultText = '' http(s)://''${config.services.firefly-iii.virtualHost} ''; description = '' The APP_URL used by firefly-iii internally. Please make sure this URL matches the external URL of your Firefly III installation. It is used to validate specific requests and to generate URLs in emails. ''; }; }; }; }; Loading @@ -242,12 +262,6 @@ in { config = mkIf cfg.enable { services.firefly-iii = { settings = { APP_URL = cfg.virtualHost; }; }; services.phpfpm.pools.firefly-iii = { inherit user group; phpPackage = cfg.package.phpPackage; Loading @@ -262,29 +276,27 @@ in { } // cfg.poolConfig; }; systemd.services.phpfpm-firefly-iii.serviceConfig = { EnvironmentFile = "/run/phpfpm/firefly-iii-env"; ExecStartPost = "${pkgs.coreutils}/bin/rm /run/phpfpm/firefly-iii-env"; }; systemd.services.firefly-iii-setup = { after = [ "postgresql.service" "mysql.service" ]; requiredBy = [ "phpfpm-firefly-iii.service" ]; before = [ "phpfpm-firefly-iii.service" ]; serviceConfig = { ExecStart = firefly-iii-maintenance; RuntimeDirectory = "phpfpm"; RuntimeDirectoryPreserve = true; RemainAfterExit = true; } // commonServiceConfig; unitConfig.JoinsNamespaceOf = "phpfpm-firefly-iii.service"; restartTriggers = [ cfg.package ]; }; systemd.services.firefly-iii-cron = { after = [ "firefly-iii-setup.service" "postgresql.service" "mysql.service" ]; wants = [ "firefly-iii-setup.service" ]; description = "Daily Firefly III cron job"; script = '' ${fileenv-func} ${artisan} firefly-iii:cron ''; serviceConfig = commonServiceConfig; serviceConfig = { ExecStart = "${artisan} firefly-iii:cron"; } // commonServiceConfig; }; systemd.timers.firefly-iii-cron = { Loading @@ -295,6 +307,7 @@ in { Persistent = true; }; wantedBy = [ "timers.target" ]; restartTriggers = [ cfg.package ]; }; services.nginx = mkIf cfg.enableNginx { Loading nixos/tests/firefly-iii.nix +90 −7 Original line number Diff line number Diff line import ./make-test-python.nix ({ lib, pkgs, ... }: { import ./make-test-python.nix ({ lib, ... }: let db-pass = "Test2Test2"; app-key = "TestTestTestTestTestTestTestTest"; in { name = "firefly-iii"; meta.maintainers = [ lib.maintainers.savyajha ]; nodes.machine = { config, ... }: { nodes.fireflySqlite = { config, ... }: { environment.etc = { "firefly-iii-appkey".text = app-key; }; services.firefly-iii = { enable = true; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; }; }; }; nodes.fireflyPostgresql = { config, pkgs, ... }: { environment.etc = { "firefly-iii-appkey".text = app-key; "postgres-pass".text = db-pass; }; services.firefly-iii = { enable = true; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; DB_CONNECTION = "pgsql"; DB_DATABASE = "firefly"; DB_USERNAME = "firefly"; DB_PASSWORD_FILE = "/etc/postgres-pass"; }; }; services.postgresql = { enable = true; package = pkgs.postgresql_15; authentication = '' local all postgres peer local firefly firefly password ''; initialScript = pkgs.writeText "firefly-init.sql" '' CREATE USER "firefly" WITH LOGIN PASSWORD '${db-pass}'; CREATE DATABASE "firefly" WITH OWNER "firefly"; CREATE SCHEMA AUTHORIZATION firefly; ''; }; }; nodes.fireflyMysql = { config, pkgs, ... }: { environment.etc = { "firefly-iii-appkey".text = "TestTestTestTestTestTestTestTest"; "firefly-iii-appkey".text = app-key; "mysql-pass".text = db-pass; }; services.firefly-iii = { enable = true; virtualHost = "http://localhost"; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; DB_CONNECTION = "mysql"; DB_DATABASE = "firefly"; DB_USERNAME = "firefly"; DB_PASSWORD_FILE = "/etc/mysql-pass"; DB_SOCKET = "/run/mysqld/mysqld.sock"; }; }; services.mysql = { enable = true; package = pkgs.mariadb; initialScript = pkgs.writeText "firefly-init.sql" '' create database firefly DEFAULT CHARACTER SET utf8mb4; create user 'firefly'@'localhost' identified by '${db-pass}'; grant all on firefly.* to 'firefly'@'localhost'; ''; settings.mysqld.character-set-server = "utf8mb4"; }; }; testScript = '' machine.wait_for_unit("phpfpm-firefly-iii.service") machine.wait_for_unit("nginx.service") machine.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflySqlite.wait_for_unit("phpfpm-firefly-iii.service") fireflySqlite.wait_for_unit("nginx.service") fireflySqlite.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflySqlite.succeed("curl -fvvv -Ls http://localhost/v1/js/app.js") fireflySqlite.succeed("systemctl start firefly-iii-cron.service") fireflyPostgresql.wait_for_unit("phpfpm-firefly-iii.service") fireflyPostgresql.wait_for_unit("nginx.service") fireflyPostgresql.wait_for_unit("postgresql.service") fireflyPostgresql.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflyPostgresql.succeed("systemctl start firefly-iii-cron.service") fireflyMysql.wait_for_unit("phpfpm-firefly-iii.service") fireflyMysql.wait_for_unit("nginx.service") fireflyMysql.wait_for_unit("mysql.service") fireflyMysql.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflyMysql.succeed("systemctl start firefly-iii-cron.service") ''; }) pkgs/by-name/fi/firefly-iii/package.nix +4 −4 Original line number Diff line number Diff line Loading @@ -8,20 +8,20 @@ let pname = "firefly-iii"; version = "6.1.15"; version = "6.1.16"; phpPackage = php83; src = fetchFromGitHub { owner = "firefly-iii"; repo = "firefly-iii"; rev = "v${version}"; hash = "sha256-9Od8tR8X2OZ2hu81tHWDpBX8snWCRvTnlY1AwjIcMug="; hash = "sha256-1I4Wm10mmloqeWcpc4XloNATpvroiw6m8MiSVsoB6xo="; }; assets = buildNpmPackage { pname = "${pname}-assets"; inherit version src; npmDepsHash = "sha256-UVySgcj1tQLQIxlsZuig4ixkfxfsYWYPKWLz5zHA+Dg="; npmDepsHash = "sha256-Ff7pDKoXvyj/gR+ljQsCjtyzxzJ7/zN6hRMEAderqOg="; dontNpmBuild = true; installPhase = '' runHook preInstall Loading @@ -36,7 +36,7 @@ in phpPackage.buildComposerProject (finalAttrs: { inherit pname src version; vendorHash = "sha256-RDkAbTKj7M7lE8bVRxb+RR5CA6hJIMp61U0+aRtFE50="; vendorHash = "sha256-BanSEqE3KN46VtEZH0TVWUBrgPCwmd2TjheYq+e+lzo="; passthru = { inherit phpPackage; Loading Loading
nixos/modules/services/web-apps/firefly-iii.nix +52 −39 Original line number Diff line number Diff line Loading @@ -3,8 +3,8 @@ let inherit (lib) optionalString mkDefault mkIf mkOption mkEnableOption literalExpression; inherit (lib.types) nullOr attrsOf oneOf str int bool path package enum submodule; inherit (lib.strings) concatMapStringsSep removePrefix toShellVars removeSuffix hasSuffix; inherit (lib.attrsets) attrValues genAttrs filterAttrs mapAttrs' nameValuePair; inherit (lib.strings) concatLines removePrefix toShellVars removeSuffix hasSuffix; inherit (lib.attrsets) mapAttrsToList attrValues genAttrs filterAttrs mapAttrs' nameValuePair; inherit (builtins) isInt isString toString typeOf; cfg = config.services.firefly-iii; Loading @@ -21,18 +21,10 @@ let (filterAttrs (n: v: hasSuffix "_FILE" n) cfg.settings); env-nonfile-values = filterAttrs (n: v: ! hasSuffix "_FILE" n) cfg.settings; envfile = pkgs.writeText "firefly-iii-env" '' ${toShellVars env-file-values} ${toShellVars env-nonfile-values} ''; fileenv-func = '' cp --no-preserve=mode ${envfile} /tmp/firefly-iii-env ${concatMapStringsSep "\n" (n: "${pkgs.replace-secret}/bin/replace-secret ${n} ${n} /tmp/firefly-iii-env") (attrValues env-file-values)} set -a . /tmp/firefly-iii-env ${toShellVars env-nonfile-values} ${concatLines (mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values)} set +a ''; Loading @@ -41,15 +33,13 @@ let ${optionalString (cfg.settings.DB_CONNECTION == "sqlite") "touch ${cfg.dataDir}/storage/database/database.sqlite"} ${artisan} migrate --seed --no-interaction --force ${artisan} firefly-iii:decrypt-all ${artisan} package:discover ${artisan} firefly-iii:upgrade-database ${artisan} firefly-iii:correct-database ${artisan} firefly-iii:report-integrity ${artisan} firefly-iii:laravel-passport-keys ${artisan} cache:clear mv /tmp/firefly-iii-env /run/phpfpm/firefly-iii-env ${artisan} view:cache ${artisan} route:cache ${artisan} config:cache ''; commonServiceConfig = { Loading Loading @@ -146,6 +136,7 @@ in { virtualHost = mkOption { type = str; default = "localhost"; description = '' The hostname at which you wish firefly-iii to be served. If you have enabled nginx using `services.firefly-iii.enableNginx` then this will Loading @@ -170,14 +161,15 @@ in { }; settings = mkOption { default = {}; description = '' Options for firefly-iii configuration. Refer to <https://github.com/firefly-iii/firefly-iii/blob/main/.env.example> for details on supported values. All <option>_FILE values supported by upstream are supported here. APP_URL will be set by `services.firefly-iii.virtualHost`, do not redefine it here. APP_URL will be the same as `services.firefly-iii.virtualHost` if the former is unset in `services.firefly-iii.settings`. ''; example = literalExpression '' { Loading @@ -192,7 +184,6 @@ in { DB_PASSWORD_FILE = "/var/secrets/firefly-iii-mysql-password.txt; } ''; default = {}; type = submodule { freeformType = attrsOf (oneOf [str int bool]); options = { Loading @@ -216,9 +207,9 @@ in { }; DB_PORT = mkOption { type = nullOr int; default = if cfg.settings.DB_CONNECTION == "sqlite" then null default = if cfg.settings.DB_CONNECTION == "pgsql" then 5432 else if cfg.settings.DB_CONNECTION == "mysql" then 3306 else 5432; else null; defaultText = '' `null` if DB_CONNECTION is "sqlite", `3306` if "mysql", `5432` if "pgsql" ''; Loading @@ -227,6 +218,21 @@ in { this value to be filled. ''; }; DB_HOST = mkOption { type = str; default = if cfg.settings.DB_CONNECTION == "pgsql" then "/run/postgresql" else "localhost"; defaultText = '' "localhost" if DB_CONNECTION is "sqlite" or "mysql", "/run/postgresql" if "pgsql". ''; description = '' The machine which hosts your database. This is left at the default value for "mysql" because we use the "DB_SOCKET" option to connect to a unix socket instead. "pgsql" requires that the unix socket location be specified here instead of at "DB_SOCKET". This option does not affect "sqlite". ''; }; APP_KEY_FILE = mkOption { type = path; description = '' Loading @@ -235,6 +241,20 @@ in { /dev/urandom | base64)" > /path/to/key-file`. ''; }; APP_URL = mkOption { type = str; default = if cfg.virtualHost == "localhost" then "http://${cfg.virtualHost}" else "https://${cfg.virtualHost}"; defaultText = '' http(s)://''${config.services.firefly-iii.virtualHost} ''; description = '' The APP_URL used by firefly-iii internally. Please make sure this URL matches the external URL of your Firefly III installation. It is used to validate specific requests and to generate URLs in emails. ''; }; }; }; }; Loading @@ -242,12 +262,6 @@ in { config = mkIf cfg.enable { services.firefly-iii = { settings = { APP_URL = cfg.virtualHost; }; }; services.phpfpm.pools.firefly-iii = { inherit user group; phpPackage = cfg.package.phpPackage; Loading @@ -262,29 +276,27 @@ in { } // cfg.poolConfig; }; systemd.services.phpfpm-firefly-iii.serviceConfig = { EnvironmentFile = "/run/phpfpm/firefly-iii-env"; ExecStartPost = "${pkgs.coreutils}/bin/rm /run/phpfpm/firefly-iii-env"; }; systemd.services.firefly-iii-setup = { after = [ "postgresql.service" "mysql.service" ]; requiredBy = [ "phpfpm-firefly-iii.service" ]; before = [ "phpfpm-firefly-iii.service" ]; serviceConfig = { ExecStart = firefly-iii-maintenance; RuntimeDirectory = "phpfpm"; RuntimeDirectoryPreserve = true; RemainAfterExit = true; } // commonServiceConfig; unitConfig.JoinsNamespaceOf = "phpfpm-firefly-iii.service"; restartTriggers = [ cfg.package ]; }; systemd.services.firefly-iii-cron = { after = [ "firefly-iii-setup.service" "postgresql.service" "mysql.service" ]; wants = [ "firefly-iii-setup.service" ]; description = "Daily Firefly III cron job"; script = '' ${fileenv-func} ${artisan} firefly-iii:cron ''; serviceConfig = commonServiceConfig; serviceConfig = { ExecStart = "${artisan} firefly-iii:cron"; } // commonServiceConfig; }; systemd.timers.firefly-iii-cron = { Loading @@ -295,6 +307,7 @@ in { Persistent = true; }; wantedBy = [ "timers.target" ]; restartTriggers = [ cfg.package ]; }; services.nginx = mkIf cfg.enableNginx { Loading
nixos/tests/firefly-iii.nix +90 −7 Original line number Diff line number Diff line import ./make-test-python.nix ({ lib, pkgs, ... }: { import ./make-test-python.nix ({ lib, ... }: let db-pass = "Test2Test2"; app-key = "TestTestTestTestTestTestTestTest"; in { name = "firefly-iii"; meta.maintainers = [ lib.maintainers.savyajha ]; nodes.machine = { config, ... }: { nodes.fireflySqlite = { config, ... }: { environment.etc = { "firefly-iii-appkey".text = app-key; }; services.firefly-iii = { enable = true; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; }; }; }; nodes.fireflyPostgresql = { config, pkgs, ... }: { environment.etc = { "firefly-iii-appkey".text = app-key; "postgres-pass".text = db-pass; }; services.firefly-iii = { enable = true; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; DB_CONNECTION = "pgsql"; DB_DATABASE = "firefly"; DB_USERNAME = "firefly"; DB_PASSWORD_FILE = "/etc/postgres-pass"; }; }; services.postgresql = { enable = true; package = pkgs.postgresql_15; authentication = '' local all postgres peer local firefly firefly password ''; initialScript = pkgs.writeText "firefly-init.sql" '' CREATE USER "firefly" WITH LOGIN PASSWORD '${db-pass}'; CREATE DATABASE "firefly" WITH OWNER "firefly"; CREATE SCHEMA AUTHORIZATION firefly; ''; }; }; nodes.fireflyMysql = { config, pkgs, ... }: { environment.etc = { "firefly-iii-appkey".text = "TestTestTestTestTestTestTestTest"; "firefly-iii-appkey".text = app-key; "mysql-pass".text = db-pass; }; services.firefly-iii = { enable = true; virtualHost = "http://localhost"; enableNginx = true; settings = { APP_KEY_FILE = "/etc/firefly-iii-appkey"; LOG_CHANNEL = "stdout"; SITE_OWNER = "mail@example.com"; DB_CONNECTION = "mysql"; DB_DATABASE = "firefly"; DB_USERNAME = "firefly"; DB_PASSWORD_FILE = "/etc/mysql-pass"; DB_SOCKET = "/run/mysqld/mysqld.sock"; }; }; services.mysql = { enable = true; package = pkgs.mariadb; initialScript = pkgs.writeText "firefly-init.sql" '' create database firefly DEFAULT CHARACTER SET utf8mb4; create user 'firefly'@'localhost' identified by '${db-pass}'; grant all on firefly.* to 'firefly'@'localhost'; ''; settings.mysqld.character-set-server = "utf8mb4"; }; }; testScript = '' machine.wait_for_unit("phpfpm-firefly-iii.service") machine.wait_for_unit("nginx.service") machine.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflySqlite.wait_for_unit("phpfpm-firefly-iii.service") fireflySqlite.wait_for_unit("nginx.service") fireflySqlite.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflySqlite.succeed("curl -fvvv -Ls http://localhost/v1/js/app.js") fireflySqlite.succeed("systemctl start firefly-iii-cron.service") fireflyPostgresql.wait_for_unit("phpfpm-firefly-iii.service") fireflyPostgresql.wait_for_unit("nginx.service") fireflyPostgresql.wait_for_unit("postgresql.service") fireflyPostgresql.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflyPostgresql.succeed("systemctl start firefly-iii-cron.service") fireflyMysql.wait_for_unit("phpfpm-firefly-iii.service") fireflyMysql.wait_for_unit("nginx.service") fireflyMysql.wait_for_unit("mysql.service") fireflyMysql.succeed("curl -fvvv -Ls http://localhost/ | grep 'Firefly III'") fireflyMysql.succeed("systemctl start firefly-iii-cron.service") ''; })
pkgs/by-name/fi/firefly-iii/package.nix +4 −4 Original line number Diff line number Diff line Loading @@ -8,20 +8,20 @@ let pname = "firefly-iii"; version = "6.1.15"; version = "6.1.16"; phpPackage = php83; src = fetchFromGitHub { owner = "firefly-iii"; repo = "firefly-iii"; rev = "v${version}"; hash = "sha256-9Od8tR8X2OZ2hu81tHWDpBX8snWCRvTnlY1AwjIcMug="; hash = "sha256-1I4Wm10mmloqeWcpc4XloNATpvroiw6m8MiSVsoB6xo="; }; assets = buildNpmPackage { pname = "${pname}-assets"; inherit version src; npmDepsHash = "sha256-UVySgcj1tQLQIxlsZuig4ixkfxfsYWYPKWLz5zHA+Dg="; npmDepsHash = "sha256-Ff7pDKoXvyj/gR+ljQsCjtyzxzJ7/zN6hRMEAderqOg="; dontNpmBuild = true; installPhase = '' runHook preInstall Loading @@ -36,7 +36,7 @@ in phpPackage.buildComposerProject (finalAttrs: { inherit pname src version; vendorHash = "sha256-RDkAbTKj7M7lE8bVRxb+RR5CA6hJIMp61U0+aRtFE50="; vendorHash = "sha256-BanSEqE3KN46VtEZH0TVWUBrgPCwmd2TjheYq+e+lzo="; passthru = { inherit phpPackage; Loading