From 6bda2431f4dc280995e3e7393e9cf412534c3a65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Wed, 25 Feb 2026 20:17:21 +0100 Subject: [PATCH 1/4] nixosTests.n8n: rename machine to machine_configured, tiny refactor --- nixos/tests/n8n.nix | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/nixos/tests/n8n.nix b/nixos/tests/n8n.nix index 270f63648904..77d488bf56e9 100644 --- a/nixos/tests/n8n.nix +++ b/nixos/tests/n8n.nix @@ -16,9 +16,8 @@ in node.pkgsReadOnly = false; - nodes.machine = - { ... }: - { + nodes = { + machine_configured = { services.n8n = { enable = true; customNodes = [ pkgs.n8n-nodes-carbonejs ]; @@ -49,52 +48,53 @@ in }; }; }; + }; testScript = '' - machine.wait_for_unit("n8n.service") - machine.wait_for_console_text("Editor is now accessible via") + machine_configured.wait_for_unit("n8n.service") + machine_configured.wait_for_console_text("Editor is now accessible via") # Test regular environment variables - machine.succeed("curl --fail -vvv http://localhost:${toString port}/") - machine.succeed("grep -qF ${webhookUrl} /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'HOME=/var/lib/n8n' /etc/systemd/system/n8n.service") - machine.fail("grep -qF 'GENERIC_TIMEZONE=' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'N8N_DIAGNOSTICS_ENABLED=false' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'N8N_TEMPLATES_ENABLED=false' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'DB_PING_INTERVAL_SECONDS=2' /etc/systemd/system/n8n.service") + machine_configured.succeed("curl --fail -vvv http://localhost:${toString port}/") + machine_configured.succeed("grep -qF ${webhookUrl} /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'HOME=/var/lib/n8n' /etc/systemd/system/n8n.service") + machine_configured.fail("grep -qF 'GENERIC_TIMEZONE=' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'N8N_DIAGNOSTICS_ENABLED=false' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'N8N_TEMPLATES_ENABLED=false' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'DB_PING_INTERVAL_SECONDS=2' /etc/systemd/system/n8n.service") # Test _FILE environment variables - machine.succeed("grep -qF 'LoadCredential=n8n_encryption_key_file:${secretFile}' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'N8N_ENCRYPTION_KEY_FILE=%d/n8n_encryption_key_file' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'LoadCredential=n8n_encryption_key_file:${secretFile}' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'N8N_ENCRYPTION_KEY_FILE=%d/n8n_encryption_key_file' /etc/systemd/system/n8n.service") # Test custom nodes - machine.succeed("grep -qF 'N8N_CUSTOM_EXTENSIONS=' /etc/systemd/system/n8n.service") - custom_extensions_dir = machine.succeed("grep -oP 'N8N_CUSTOM_EXTENSIONS=\\K[^\"]+' /etc/systemd/system/n8n.service").strip() - machine.succeed(f"test -L {custom_extensions_dir}/n8n-nodes-carbonejs") - machine.succeed(f"test -f {custom_extensions_dir}/n8n-nodes-carbonejs/package.json") + machine_configured.succeed("grep -qF 'N8N_CUSTOM_EXTENSIONS=' /etc/systemd/system/n8n.service") + custom_extensions_dir = machine_configured.succeed("grep -oP 'N8N_CUSTOM_EXTENSIONS=\\K[^\"]+' /etc/systemd/system/n8n.service").strip() + machine_configured.succeed(f"test -L {custom_extensions_dir}/n8n-nodes-carbonejs") + machine_configured.succeed(f"test -f {custom_extensions_dir}/n8n-nodes-carbonejs/package.json") # Test task runner integration on n8n service - machine.succeed("grep -qF 'N8N_RUNNERS_MODE=external' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'N8N_RUNNERS_BROKER_PORT=${toString brokerPort}' /etc/systemd/system/n8n.service") - machine.succeed("grep -qF 'LoadCredential=n8n_runners_auth_token_file:${authTokenFile}' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'N8N_RUNNERS_MODE=external' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'N8N_RUNNERS_BROKER_PORT=${toString brokerPort}' /etc/systemd/system/n8n.service") + machine_configured.succeed("grep -qF 'LoadCredential=n8n_runners_auth_token_file:${authTokenFile}' /etc/systemd/system/n8n.service") # Test task runner service - machine.wait_for_unit("n8n-task-runner.service") - machine.succeed("systemctl is-active n8n-task-runner.service") + machine_configured.wait_for_unit("n8n-task-runner.service") + machine_configured.succeed("systemctl is-active n8n-task-runner.service") # Test that both runner types are enabled - machine.succeed("grep -qF 'javascript python' /etc/systemd/system/n8n-task-runner.service") + machine_configured.succeed("grep -qF 'javascript python' /etc/systemd/system/n8n-task-runner.service") # Test common environment variables are passed to launcher - machine.succeed("grep -qF 'N8N_RUNNERS_MAX_CONCURRENCY=10' /etc/systemd/system/n8n-task-runner.service") - machine.succeed("grep -qF 'N8N_RUNNERS_TASK_BROKER_URI=http://127.0.0.1:${toString brokerPort}' /etc/systemd/system/n8n-task-runner.service") + machine_configured.succeed("grep -qF 'N8N_RUNNERS_MAX_CONCURRENCY=10' /etc/systemd/system/n8n-task-runner.service") + machine_configured.succeed("grep -qF 'N8N_RUNNERS_TASK_BROKER_URI=http://127.0.0.1:${toString brokerPort}' /etc/systemd/system/n8n-task-runner.service") # Test auth token is loaded via credentials - machine.succeed("grep -qF 'LoadCredential=n8n_runners_auth_token_file:${authTokenFile}' /etc/systemd/system/n8n-task-runner.service") + machine_configured.succeed("grep -qF 'LoadCredential=n8n_runners_auth_token_file:${authTokenFile}' /etc/systemd/system/n8n-task-runner.service") # Test launcher config file - config_path = machine.succeed("grep -oP 'N8N_RUNNERS_CONFIG_PATH=\\K[^[:space:]\"]+' /etc/systemd/system/n8n-task-runner.service").strip() - config = machine.succeed(f"cat {config_path}") + config_path = machine_configured.succeed("grep -oP 'N8N_RUNNERS_CONFIG_PATH=\\K[^[:space:]\"]+' /etc/systemd/system/n8n-task-runner.service").strip() + config = machine_configured.succeed(f"cat {config_path}") assert "NODE_FUNCTION_ALLOW_BUILTIN" in config, "JavaScript env-override not in config" assert "N8N_RUNNERS_STDLIB_ALLOW" in config, "Python env-override not in config" assert "N8N_RUNNERS_MAX_CONCURRENCY" in config, "Common allowed-env not in config" From 6922af6e7a6218c16f49787a0ccb7541afac10c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Wed, 25 Feb 2026 20:22:52 +0100 Subject: [PATCH 2/4] nixosTests.n8n: add simple config Currently fails. --- nixos/tests/n8n.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nixos/tests/n8n.nix b/nixos/tests/n8n.nix index 77d488bf56e9..3d2c1ad4d9c1 100644 --- a/nixos/tests/n8n.nix +++ b/nixos/tests/n8n.nix @@ -17,6 +17,9 @@ in node.pkgsReadOnly = false; nodes = { + machine_simple = { + services.n8n.enable = true; + }; machine_configured = { services.n8n = { enable = true; @@ -51,6 +54,11 @@ in }; testScript = '' + machine_simple.wait_for_unit("n8n.service") + machine_simple.wait_for_console_text("Editor is now accessible via") + machine_simple.succeed("curl --fail -vvv http://localhost:${toString port}/") + + machine_configured.wait_for_unit("n8n.service") machine_configured.wait_for_console_text("Editor is now accessible via") From 6a7650ebddf91d38b867cc35151be8fbebd6cf19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Wed, 25 Feb 2026 20:41:43 +0100 Subject: [PATCH 3/4] nixos/n8n: move N8N_RUNNERS_CONFIG_PATH option to the final environment Without this, the next commit would cause an infinite recursion error. --- nixos/modules/services/misc/n8n.nix | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/nixos/modules/services/misc/n8n.nix b/nixos/modules/services/misc/n8n.nix index 7e302a190a87..ed149ce75952 100644 --- a/nixos/modules/services/misc/n8n.nix +++ b/nixos/modules/services/misc/n8n.nix @@ -240,14 +240,6 @@ in (coercedTo bool builtins.toJSON str) ]); options = { - N8N_RUNNERS_CONFIG_PATH = lib.mkOption { - internal = true; - type = with lib.types; nullOr path; - default = launcherConfigFile; - description = '' - Path to the configuration file for the task runner launcher. - ''; - }; N8N_RUNNERS_AUTH_TOKEN_FILE = lib.mkOption { type = with lib.types; nullOr path; default = cfg.environment.N8N_RUNNERS_AUTH_TOKEN_FILE; @@ -401,7 +393,11 @@ in after = [ "n8n.service" ]; requires = [ "n8n.service" ]; wantedBy = [ "multi-user.target" ]; - environment = runnersEnv.regular // runnersEnv.fileBasedTransformed; + environment = { + N8N_RUNNERS_CONFIG_PATH = launcherConfigFile; + } + // runnersEnv.regular + // runnersEnv.fileBasedTransformed; serviceConfig = { Type = "simple"; ExecStart = "${lib.getExe runnersCfg.launcherPackage} ${lib.concatStringsSep " " runnerTypes}"; From 5ad853409cf18274ab2b061b2d83231e5a31a3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Wed, 25 Feb 2026 20:42:56 +0100 Subject: [PATCH 4/4] nixos/n8n: fix eval error with null environment variables --- nixos/modules/services/misc/n8n.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/misc/n8n.nix b/nixos/modules/services/misc/n8n.nix index ed149ce75952..30b1f284b10d 100644 --- a/nixos/modules/services/misc/n8n.nix +++ b/nixos/modules/services/misc/n8n.nix @@ -10,8 +10,9 @@ let # Partition environment variables into regular and file-based (_FILE suffix) envVarToCredName = varName: lib.toLower varName; partitionEnv = - env: + allEnv: let + env = lib.filterAttrs (_name: value: value != null) allEnv; regular = lib.filterAttrs (name: _value: !(lib.hasSuffix "_FILE" name)) env; fileBased = lib.filterAttrs (name: _value: lib.hasSuffix "_FILE" name) env; fileBasedTransformed = lib.mapAttrs' (