mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-13 02:01:16 +00:00
* Exec approvals: detect command carriers in strict inline eval * Exec approvals: cover carrier option edge cases * Exec approvals: cover make and find carriers * Exec approvals: catch attached eval flags * Exec approvals: keep sed -E out of inline eval * Exec approvals: treat sed in-place flags as optional
83 lines
4.3 KiB
TypeScript
83 lines
4.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
describeInterpreterInlineEval,
|
|
detectInterpreterInlineEvalArgv,
|
|
isInterpreterLikeAllowlistPattern,
|
|
} from "./exec-inline-eval.js";
|
|
|
|
describe("exec inline eval detection", () => {
|
|
it.each([
|
|
{ argv: ["python3", "-c", "print('hi')"], expected: "python3 -c" },
|
|
{ argv: ["/usr/bin/node", "--eval", "console.log('hi')"], expected: "node --eval" },
|
|
{ argv: ["perl", "-E", "say 1"], expected: "perl -e" },
|
|
{ argv: ["osascript", "-e", "beep"], expected: "osascript -e" },
|
|
{ argv: ["awk", "BEGIN { print 1 }"], expected: "awk inline program" },
|
|
{ argv: ["gawk", "-F", ",", "{print $1}", "data.csv"], expected: "gawk inline program" },
|
|
] as const)("detects interpreter eval flags for %j", ({ argv, expected }) => {
|
|
const hit = detectInterpreterInlineEvalArgv([...argv]);
|
|
expect(hit).not.toBeNull();
|
|
expect(describeInterpreterInlineEval(hit!)).toBe(expected);
|
|
});
|
|
|
|
it.each([
|
|
{ argv: ["awk", 'BEGIN{system("id")}', "/dev/null"], expected: "awk inline program" },
|
|
{
|
|
argv: ["awk", "-F", ",", 'BEGIN{system("id")}', "/dev/null"],
|
|
expected: "awk inline program",
|
|
},
|
|
{ argv: ["gawk", "-e", 'BEGIN{system("id")}', "/dev/null"], expected: "gawk -e" },
|
|
{
|
|
argv: ["gawk", "-f", "library.awk", '--source=BEGIN{system("id")}', "/dev/null"],
|
|
expected: "gawk --source",
|
|
},
|
|
{ argv: ["find", ".", "-exec", "id", "{}", ";"], expected: "find -exec" },
|
|
{ argv: ["find", "--", ".", "-exec", "id", "{}", ";"], expected: "find -exec" },
|
|
{ argv: ["find", ".", "-ok", "id", "{}", ";"], expected: "find -ok" },
|
|
{ argv: ["find", ".", "-okdir", "id", "{}", ";"], expected: "find -okdir" },
|
|
{ argv: ["xargs", "id"], expected: "xargs inline command" },
|
|
{ argv: ["xargs", "-I", "{}", "sh", "-c", "id"], expected: "xargs inline command" },
|
|
{ argv: ["xargs", "--replace", "id"], expected: "xargs inline command" },
|
|
{ argv: ["make", "-f", "evil.mk"], expected: "make -f" },
|
|
{ argv: ["make", "-E", "$(shell id)"], expected: "make -E" },
|
|
{ argv: ["make", "-E$(shell id)"], expected: "make -E" },
|
|
{ argv: ["make", "--eval=$(shell id)"], expected: "make --eval" },
|
|
{ argv: ["sed", "s/.*/id/e", "/dev/null"], expected: "sed inline program" },
|
|
{ argv: ["gsed", "-e", "s/.*/id/e", "/dev/null"], expected: "gsed -e" },
|
|
{ argv: ["sed", "-es/.*/id/e", "/dev/null"], expected: "sed -e" },
|
|
] as const)("detects command carriers for %j", ({ argv, expected }) => {
|
|
const hit = detectInterpreterInlineEvalArgv([...argv]);
|
|
expect(hit).not.toBeNull();
|
|
expect(describeInterpreterInlineEval(hit!)).toBe(expected);
|
|
});
|
|
|
|
it("ignores normal script execution", () => {
|
|
expect(detectInterpreterInlineEvalArgv(["python3", "script.py"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["node", "script.js"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["awk", "-f", "script.awk", "data.csv"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["find", ".", "-name", "*.ts"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["xargs", "-0"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["make", "test"])).toBeNull();
|
|
expect(detectInterpreterInlineEvalArgv(["sed", "-f", "script.sed", "input.txt"])).toBeNull();
|
|
expect(
|
|
detectInterpreterInlineEvalArgv(["sed", "-i", "-f", "script.sed", "input.txt"]),
|
|
).toBeNull();
|
|
expect(
|
|
detectInterpreterInlineEvalArgv(["sed", "-E", "-f", "script.sed", "input.txt"]),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("matches interpreter-like allowlist patterns", () => {
|
|
expect(isInterpreterLikeAllowlistPattern("/usr/bin/python3")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("**/node")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("/usr/bin/awk")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("**/gawk")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("/usr/bin/mawk")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("nawk")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("**/find")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("xargs.exe")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("/usr/bin/gmake")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("**/gsed")).toBe(true);
|
|
expect(isInterpreterLikeAllowlistPattern("/usr/bin/rg")).toBe(false);
|
|
});
|
|
});
|