test(agents): dedupe exec preflight fixtures and cover quoted-path skip

This commit is contained in:
Peter Steinberger
2026-02-21 19:29:41 +00:00
parent 8f11868cc2
commit 8f1b467646

View File

@@ -6,80 +6,97 @@ import { createExecTool } from "./bash-tools.exec.js";
const isWin = process.platform === "win32"; const isWin = process.platform === "win32";
describe("exec script preflight", () => { const describeNonWin = isWin ? describe.skip : describe;
async function withTempDir(prefix: string, run: (dir: string) => Promise<void>) {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
try {
await run(dir);
} finally {
await fs.rm(dir, { recursive: true, force: true });
}
}
describeNonWin("exec script preflight", () => {
it("blocks shell env var injection tokens in python scripts before execution", async () => { it("blocks shell env var injection tokens in python scripts before execution", async () => {
if (isWin) { await withTempDir("openclaw-exec-preflight-", async (tmp) => {
return; const pyPath = path.join(tmp, "bad.py");
}
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-exec-preflight-")); await fs.writeFile(
const pyPath = path.join(tmp, "bad.py"); pyPath,
[
"import json",
"# model accidentally wrote shell syntax:",
"payload = $DM_JSON",
"print(payload)",
].join("\n"),
"utf-8",
);
await fs.writeFile( const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
pyPath,
[
"import json",
"# model accidentally wrote shell syntax:",
"payload = $DM_JSON",
"print(payload)",
].join("\n"),
"utf-8",
);
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" }); await expect(
tool.execute("call1", {
await expect( command: "python bad.py",
tool.execute("call1", { workdir: tmp,
command: "python bad.py", }),
workdir: tmp, ).rejects.toThrow(/exec preflight: detected likely shell variable injection \(\$DM_JSON\)/);
}), });
).rejects.toThrow(/exec preflight: detected likely shell variable injection \(\$DM_JSON\)/);
}); });
it("blocks obvious shell-as-js output before node execution", async () => { it("blocks obvious shell-as-js output before node execution", async () => {
if (isWin) { await withTempDir("openclaw-exec-preflight-", async (tmp) => {
return; const jsPath = path.join(tmp, "bad.js");
}
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-exec-preflight-")); await fs.writeFile(
const jsPath = path.join(tmp, "bad.js"); jsPath,
['NODE "$TMPDIR/hot.json"', "console.log('hi')"].join("\n"),
"utf-8",
);
await fs.writeFile( const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
jsPath,
['NODE "$TMPDIR/hot.json"', "console.log('hi')"].join("\n"),
"utf-8",
);
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" }); await expect(
tool.execute("call1", {
command: "node bad.js",
workdir: tmp,
}),
).rejects.toThrow(
/exec preflight: (detected likely shell variable injection|JS file starts with shell syntax)/,
);
});
});
await expect( it("skips preflight when script token is quoted and unresolved by fast parser", async () => {
tool.execute("call1", { await withTempDir("openclaw-exec-preflight-", async (tmp) => {
command: "node bad.js", const jsPath = path.join(tmp, "bad.js");
await fs.writeFile(jsPath, "const value = $DM_JSON;", "utf-8");
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
const result = await tool.execute("call-quoted", {
command: 'node "bad.js"',
workdir: tmp, workdir: tmp,
}), });
).rejects.toThrow( const text = result.content.find((block) => block.type === "text")?.text ?? "";
/exec preflight: (detected likely shell variable injection|JS file starts with shell syntax)/, expect(text).not.toMatch(/exec preflight:/);
); });
}); });
it("skips preflight file reads for script paths outside the workdir", async () => { it("skips preflight file reads for script paths outside the workdir", async () => {
if (isWin) { await withTempDir("openclaw-exec-preflight-parent-", async (parent) => {
return; const outsidePath = path.join(parent, "outside.js");
} const workdir = path.join(parent, "workdir");
await fs.mkdir(workdir, { recursive: true });
await fs.writeFile(outsidePath, "const value = $DM_JSON;", "utf-8");
const parent = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-exec-preflight-parent-")); const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
const outsidePath = path.join(parent, "outside.js");
const workdir = path.join(parent, "workdir");
await fs.mkdir(workdir, { recursive: true });
await fs.writeFile(outsidePath, "const value = $DM_JSON;", "utf-8");
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" }); const result = await tool.execute("call-outside", {
command: "node ../outside.js",
const result = await tool.execute("call-outside", { workdir,
command: "node ../outside.js", });
workdir, const text = result.content.find((block) => block.type === "text")?.text ?? "";
expect(text).not.toMatch(/exec preflight:/);
}); });
const text = result.content.find((block) => block.type === "text")?.text ?? "";
expect(text).not.toMatch(/exec preflight:/);
}); });
}); });