mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 12:37:40 +00:00
test(exec): dedupe wrapper boundary regressions
This commit is contained in:
@@ -41,30 +41,14 @@ describe("system run command helpers", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("extractShellCommandFromArgv unwraps known dispatch wrappers before shell wrappers", () => {
|
test("extractShellCommandFromArgv unwraps known dispatch wrappers before shell wrappers", () => {
|
||||||
expect(extractShellCommandFromArgv(["/usr/bin/nice", "/bin/bash", "-lc", "echo hi"])).toBe(
|
const cases = [
|
||||||
"echo hi",
|
["/usr/bin/nice", "/bin/bash", "-lc", "echo hi"],
|
||||||
);
|
["/usr/bin/timeout", "--signal=TERM", "5", "zsh", "-lc", "echo hi"],
|
||||||
expect(
|
["/usr/bin/env", "/usr/bin/env", "/usr/bin/env", "/usr/bin/env", "/bin/sh", "-c", "echo hi"],
|
||||||
extractShellCommandFromArgv([
|
];
|
||||||
"/usr/bin/timeout",
|
for (const argv of cases) {
|
||||||
"--signal=TERM",
|
expect(extractShellCommandFromArgv(argv)).toBe("echo hi");
|
||||||
"5",
|
}
|
||||||
"zsh",
|
|
||||||
"-lc",
|
|
||||||
"echo hi",
|
|
||||||
]),
|
|
||||||
).toBe("echo hi");
|
|
||||||
expect(
|
|
||||||
extractShellCommandFromArgv([
|
|
||||||
"/usr/bin/env",
|
|
||||||
"/usr/bin/env",
|
|
||||||
"/usr/bin/env",
|
|
||||||
"/usr/bin/env",
|
|
||||||
"/bin/sh",
|
|
||||||
"-c",
|
|
||||||
"echo hi",
|
|
||||||
]),
|
|
||||||
).toBe("echo hi");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("extractShellCommandFromArgv supports fish and pwsh wrappers", () => {
|
test("extractShellCommandFromArgv supports fish and pwsh wrappers", () => {
|
||||||
|
|||||||
@@ -858,13 +858,14 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
|
|||||||
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
|
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("denies env-wrapped shell payloads at the dispatch depth boundary", async () => {
|
async function expectNestedEnvShellDenied(params: {
|
||||||
if (process.platform === "win32") {
|
depth: number;
|
||||||
return;
|
markerName: string;
|
||||||
}
|
errorLabel: string;
|
||||||
|
}) {
|
||||||
const { runCommand, sendInvokeResult, sendNodeEvent } = createInvokeSpies({
|
const { runCommand, sendInvokeResult, sendNodeEvent } = createInvokeSpies({
|
||||||
runCommand: vi.fn(async () => {
|
runCommand: vi.fn(async () => {
|
||||||
throw new Error("runCommand should not be called for depth-boundary shell wrappers");
|
throw new Error(params.errorLabel);
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -877,11 +878,11 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
run: async ({ tempHome }) => {
|
run: async ({ tempHome }) => {
|
||||||
const marker = path.join(tempHome, "depth4-pwned.txt");
|
const marker = path.join(tempHome, params.markerName);
|
||||||
await runSystemInvoke({
|
await runSystemInvoke({
|
||||||
preferMacAppExecHost: false,
|
preferMacAppExecHost: false,
|
||||||
command: buildNestedEnvShellCommand({
|
command: buildNestedEnvShellCommand({
|
||||||
depth: 4,
|
depth: params.depth,
|
||||||
payload: `echo PWNED > ${marker}`,
|
payload: `echo PWNED > ${marker}`,
|
||||||
}),
|
}),
|
||||||
security: "allowlist",
|
security: "allowlist",
|
||||||
@@ -896,45 +897,27 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
|
|||||||
|
|
||||||
expect(runCommand).not.toHaveBeenCalled();
|
expect(runCommand).not.toHaveBeenCalled();
|
||||||
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
|
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
|
||||||
|
}
|
||||||
|
|
||||||
|
it("denies env-wrapped shell payloads at the dispatch depth boundary", async () => {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await expectNestedEnvShellDenied({
|
||||||
|
depth: 4,
|
||||||
|
markerName: "depth4-pwned.txt",
|
||||||
|
errorLabel: "runCommand should not be called for depth-boundary shell wrappers",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("denies nested env shell payloads when wrapper depth is exceeded", async () => {
|
it("denies nested env shell payloads when wrapper depth is exceeded", async () => {
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { runCommand, sendInvokeResult, sendNodeEvent } = createInvokeSpies({
|
await expectNestedEnvShellDenied({
|
||||||
runCommand: vi.fn(async () => {
|
depth: 5,
|
||||||
throw new Error("runCommand should not be called for nested env depth overflow");
|
markerName: "pwned.txt",
|
||||||
}),
|
errorLabel: "runCommand should not be called for nested env depth overflow",
|
||||||
});
|
});
|
||||||
|
|
||||||
await withTempApprovalsHome({
|
|
||||||
approvals: createAllowlistOnMissApprovals({
|
|
||||||
agents: {
|
|
||||||
main: {
|
|
||||||
allowlist: [{ pattern: "/usr/bin/env" }],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
run: async ({ tempHome }) => {
|
|
||||||
const marker = path.join(tempHome, "pwned.txt");
|
|
||||||
await runSystemInvoke({
|
|
||||||
preferMacAppExecHost: false,
|
|
||||||
command: buildNestedEnvShellCommand({
|
|
||||||
depth: 5,
|
|
||||||
payload: `echo PWNED > ${marker}`,
|
|
||||||
}),
|
|
||||||
security: "allowlist",
|
|
||||||
ask: "on-miss",
|
|
||||||
runCommand,
|
|
||||||
sendInvokeResult,
|
|
||||||
sendNodeEvent,
|
|
||||||
});
|
|
||||||
expect(fs.existsSync(marker)).toBe(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(runCommand).not.toHaveBeenCalled();
|
|
||||||
expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user