mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 03:51:25 +00:00
test(agents): dedupe exec preflight fixtures and cover quoted-path skip
This commit is contained in:
@@ -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:/);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user