diff --git a/src/infra/exec-approvals-allow-always.test.ts b/src/infra/exec-approvals-allow-always.test.ts index 72db45a33ea..4f31e693ab8 100644 --- a/src/infra/exec-approvals-allow-always.test.ts +++ b/src/infra/exec-approvals-allow-always.test.ts @@ -61,6 +61,51 @@ describe("resolveAllowAlwaysPatterns", () => { ).toBe(true); } + function createShellScriptFixture() { + const dir = makeTempDir(); + const scriptsDir = path.join(dir, "scripts"); + fs.mkdirSync(scriptsDir, { recursive: true }); + const script = path.join(scriptsDir, "save_crystal.sh"); + fs.writeFileSync(script, "echo ok\n"); + const env = { PATH: `${dir}${path.delimiter}${process.env.PATH ?? ""}` }; + const safeBins = resolveSafeBins(undefined); + return { dir, scriptsDir, script, env, safeBins }; + } + + function expectPersistedShellScriptMatch(params: { + command: string; + script: string; + dir: string; + env: Record; + safeBins: ReturnType; + }) { + const first = evaluateShellAllowlist({ + command: params.command, + allowlist: [], + safeBins: params.safeBins, + cwd: params.dir, + env: params.env, + platform: process.platform, + }); + const persisted = resolveAllowAlwaysPatterns({ + segments: first.segments, + cwd: params.dir, + env: params.env, + platform: process.platform, + }); + expect(persisted).toEqual([params.script]); + + const second = evaluateShellAllowlist({ + command: params.command, + allowlist: [{ pattern: params.script }], + safeBins: params.safeBins, + cwd: params.dir, + env: params.env, + platform: process.platform, + }); + expect(second.allowlistSatisfied).toBe(true); + } + it("returns direct executable paths for non-shell segments", () => { const exe = path.join("/tmp", "openclaw-tool"); const patterns = resolveAllowAlwaysPatterns({ @@ -131,39 +176,14 @@ describe("resolveAllowAlwaysPatterns", () => { if (process.platform === "win32") { return; } - const dir = makeTempDir(); - const scriptsDir = path.join(dir, "scripts"); - fs.mkdirSync(scriptsDir, { recursive: true }); - const script = path.join(scriptsDir, "save_crystal.sh"); - fs.writeFileSync(script, "echo ok\n"); - - const safeBins = resolveSafeBins(undefined); - const env = { PATH: `${dir}${path.delimiter}${process.env.PATH ?? ""}` }; - const first = evaluateShellAllowlist({ + const { dir, scriptsDir, script, env, safeBins } = createShellScriptFixture(); + expectPersistedShellScriptMatch({ command: "bash scripts/save_crystal.sh", - allowlist: [], + script, + dir, + env, safeBins, - cwd: dir, - env, - platform: process.platform, }); - const persisted = resolveAllowAlwaysPatterns({ - segments: first.segments, - cwd: dir, - env, - platform: process.platform, - }); - expect(persisted).toEqual([script]); - - const second = evaluateShellAllowlist({ - command: "bash scripts/save_crystal.sh", - allowlist: [{ pattern: script }], - safeBins, - cwd: dir, - env, - platform: process.platform, - }); - expect(second.allowlistSatisfied).toBe(true); const other = path.join(scriptsDir, "other.sh"); fs.writeFileSync(other, "echo other\n"); @@ -182,51 +202,21 @@ describe("resolveAllowAlwaysPatterns", () => { if (process.platform === "win32") { return; } - const dir = makeTempDir(); - const scriptsDir = path.join(dir, "scripts"); - fs.mkdirSync(scriptsDir, { recursive: true }); - const script = path.join(scriptsDir, "save_crystal.sh"); - fs.writeFileSync(script, "echo ok\n"); - - const safeBins = resolveSafeBins(undefined); - const env = { PATH: `${dir}${path.delimiter}${process.env.PATH ?? ""}` }; - const first = evaluateShellAllowlist({ + const { dir, script, env, safeBins } = createShellScriptFixture(); + expectPersistedShellScriptMatch({ command: "/usr/bin/nice bash scripts/save_crystal.sh", - allowlist: [], + script, + dir, + env, safeBins, - cwd: dir, - env, - platform: process.platform, }); - const persisted = resolveAllowAlwaysPatterns({ - segments: first.segments, - cwd: dir, - env, - platform: process.platform, - }); - expect(persisted).toEqual([script]); - - const second = evaluateShellAllowlist({ - command: "/usr/bin/nice bash scripts/save_crystal.sh", - allowlist: [{ pattern: script }], - safeBins, - cwd: dir, - env, - platform: process.platform, - }); - expect(second.allowlistSatisfied).toBe(true); }); it("does not treat inline shell commands as persisted script paths", () => { if (process.platform === "win32") { return; } - const dir = makeTempDir(); - const scriptsDir = path.join(dir, "scripts"); - fs.mkdirSync(scriptsDir, { recursive: true }); - const script = path.join(scriptsDir, "save_crystal.sh"); - fs.writeFileSync(script, "echo ok\n"); - const env = { PATH: `${dir}${path.delimiter}${process.env.PATH ?? ""}` }; + const { dir, script, env } = createShellScriptFixture(); expectAllowAlwaysBypassBlocked({ dir, firstCommand: "bash scripts/save_crystal.sh", @@ -240,12 +230,7 @@ describe("resolveAllowAlwaysPatterns", () => { if (process.platform === "win32") { return; } - const dir = makeTempDir(); - const scriptsDir = path.join(dir, "scripts"); - fs.mkdirSync(scriptsDir, { recursive: true }); - const script = path.join(scriptsDir, "save_crystal.sh"); - fs.writeFileSync(script, "echo ok\n"); - const env = { PATH: `${dir}${path.delimiter}${process.env.PATH ?? ""}` }; + const { dir, script, env } = createShellScriptFixture(); expectAllowAlwaysBypassBlocked({ dir, firstCommand: "bash scripts/save_crystal.sh",