@n8n-as-code/n8nac 2026.3.1 → 2026.3.2-next.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n8n-as-code/n8nac",
3
- "version": "2026.3.1",
3
+ "version": "2026.3.2-next.3",
4
4
  "description": "OpenClaw plugin for n8n-as-code — create and manage n8n workflows from OpenClaw",
5
5
  "keywords": [
6
6
  "n8n",
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Build a minimal environment for child processes.
3
+ * Only passes the vars needed for npx/node to operate, deliberately excluding
4
+ * any sensitive credentials that the parent (agent host) may hold in its env
5
+ * (e.g. LLM API keys), preventing accidental credential forwarding.
6
+ */
7
+ export function getChildEnv(): NodeJS.ProcessEnv {
8
+ const env: NodeJS.ProcessEnv = {};
9
+
10
+ // Matches var names that look like credentials anywhere in the name — these are never forwarded
11
+ // even if they match another allowlist prefix (e.g. NODE_AUTH_TOKEN, npm_config_*:_authToken,
12
+ // npm_config_authority is intentionally over-blocked since we prefer false-positives to leaks).
13
+ const secretPattern = /(?:auth|token|password|secret|apikey|api_key|_key)/i;
14
+
15
+ for (const key of Object.keys(process.env)) {
16
+ const upperKey = key.toUpperCase();
17
+ if (
18
+ // Basic system vars needed by node/npx (case-insensitive, including Windows-specific ones)
19
+ /^(PATH|HOME|USERPROFILE|HOMEDRIVE|HOMEPATH|TMPDIR|TMP|TEMP|LANG|LC_ALL|SHELL|TERM|TERM_PROGRAM|NODE_PATH|NODE_OPTIONS|SYSTEMROOT|COMSPEC|PATHEXT)$/.test(
20
+ upperKey,
21
+ ) ||
22
+ // npm execution/config vars required by npx — but NOT auth/token vars
23
+ // (e.g. excludes npm_config_//registry.npmjs.org/:_authToken)
24
+ (key.startsWith("npm_") && !secretPattern.test(key)) ||
25
+ // Specific safe NODE_* vars (deliberately NOT a prefix match to exclude NODE_AUTH_TOKEN)
26
+ /^NODE_(ENV|NO_WARNINGS|ICU_DATA)$/.test(upperKey) ||
27
+ // n8n-as-code specific vars
28
+ key.startsWith("N8N_AS_CODE_")
29
+ ) {
30
+ env[key] = process.env[key];
31
+ }
32
+ }
33
+ return env;
34
+ }
package/src/cli.ts CHANGED
@@ -3,6 +3,7 @@ import { spawn } from "node:child_process";
3
3
  import type { ChildProcess, ChildProcessWithoutNullStreams } from "node:child_process";
4
4
  import * as p from "@clack/prompts";
5
5
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
6
+ import { getChildEnv } from "./child-env.js";
6
7
  import { isWorkspaceInitialized } from "./workspace.js";
7
8
 
8
9
  type CliProgram = Parameters<Parameters<OpenClawPluginApi["registerCli"]>[0]>[0]["program"];
@@ -24,14 +25,14 @@ function runN8nac(
24
25
  opts: {
25
26
  cwd: string;
26
27
  timeout: number;
27
- env?: NodeJS.ProcessEnv;
28
+ stdinInput?: string;
28
29
  stdio?: "pipe" | "inherit";
29
30
  },
30
31
  ): Promise<RunResult> {
31
32
  return new Promise((resolve) => {
32
33
  const baseOptions = {
33
34
  cwd: opts.cwd,
34
- env: { ...process.env, ...opts.env },
35
+ env: getChildEnv(),
35
36
  };
36
37
 
37
38
  const child: ChildProcess | ChildProcessWithoutNullStreams =
@@ -65,6 +66,11 @@ function runN8nac(
65
66
  });
66
67
  }
67
68
 
69
+ if (opts.stdinInput !== undefined && "stdin" in child && child.stdin) {
70
+ child.stdin.write(`${opts.stdinInput}\n`);
71
+ child.stdin.end();
72
+ }
73
+
68
74
  const timer = setTimeout(() => {
69
75
  timedOut = true;
70
76
  child.kill("SIGTERM");
@@ -154,10 +160,10 @@ export function registerN8nAcCli({ program, workspaceDir }: CliOpts): void {
154
160
  const authSpinner = p.spinner();
155
161
  authSpinner.start("Saving credentials…");
156
162
 
157
- const authResult = await runN8nac(["init-auth", "--host", host], {
163
+ const authResult = await runN8nac(["init-auth", "--host", host, "--api-key-stdin"], {
158
164
  cwd: workspaceDir,
159
165
  timeout: 60_000,
160
- env: { N8N_API_KEY: apiKey },
166
+ stdinInput: apiKey,
161
167
  });
162
168
 
163
169
  if (authResult.exitCode !== 0) {
package/src/tool.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { Type } from "@sinclair/typebox";
3
+ import { getChildEnv } from "./child-env.js";
3
4
  import { isWorkspaceInitialized } from "./workspace.js";
4
5
 
5
6
  // ---------------------------------------------------------------------------
@@ -100,13 +101,13 @@ type RunResult = {
100
101
  function runNpx(
101
102
  args: string[],
102
103
  cwd: string,
103
- env?: NodeJS.ProcessEnv,
104
+ stdinInput?: string,
104
105
  ): Promise<RunResult> {
105
106
  return new Promise((resolve) => {
106
107
  const child = spawn("npx", ["--yes", "n8nac", ...args], {
107
108
  cwd,
108
- env: { ...process.env, ...env },
109
109
  stdio: "pipe",
110
+ env: getChildEnv(),
110
111
  });
111
112
 
112
113
  let stdout = "";
@@ -131,6 +132,11 @@ function runNpx(
131
132
  stderr += chunk.toString();
132
133
  });
133
134
 
135
+ if (stdinInput !== undefined) {
136
+ child.stdin.write(`${stdinInput}\n`);
137
+ child.stdin.end();
138
+ }
139
+
134
140
  const timer = setTimeout(() => {
135
141
  timedOut = true;
136
142
  child.kill("SIGTERM");
@@ -250,7 +256,7 @@ export function createN8nAcTool(opts: { workspaceDir: string }) {
250
256
  if (!host || !key) {
251
257
  return ok({ error: "n8nHost and n8nApiKey are required for init_auth" });
252
258
  }
253
- const r = await runNpx(["init-auth", "--host", host], workspaceDir, { N8N_API_KEY: key });
259
+ const r = await runNpx(["init-auth", "--host", host, "--api-key-stdin"], workspaceDir, key);
254
260
  if (r.exitCode !== 0) {
255
261
  return ok({ error: r.stderr || r.stdout, exitCode: r.exitCode });
256
262
  }