test(exec): dedupe wrapper boundary regressions

This commit is contained in:
Peter Steinberger
2026-03-08 00:11:57 +00:00
parent 5f50823abf
commit 8a469a12b2
2 changed files with 31 additions and 64 deletions

View File

@@ -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", () => {

View File

@@ -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 });
}); });
}); });