diff --git a/src/node-host/invoke-system-run.test.ts b/src/node-host/invoke-system-run.test.ts index 0656b4a399c..75a2c286e2f 100644 --- a/src/node-host/invoke-system-run.test.ts +++ b/src/node-host/invoke-system-run.test.ts @@ -1275,6 +1275,8 @@ describe("handleSystemRunInvoke mac app exec host routing", () => { }); it("requires explicit approval for strict inline-eval carriers", async () => { + // The full carrier matrix lives in exec-inline-eval.test.ts; this is the + // handle-level smoke for strictInlineEval denial wiring. const cases = [ { command: ["python3", "-c", "print('hi')"], @@ -1284,22 +1286,6 @@ describe("handleSystemRunInvoke mac app exec host routing", () => { command: ["awk", 'BEGIN{system("id")}', "/dev/null"], expected: "awk inline program requires explicit approval in strictInlineEval mode", }, - { - command: ["find", ".", "-exec", "id", "{}", ";"], - expected: "find -exec requires explicit approval in strictInlineEval mode", - }, - { - command: ["xargs", "id"], - expected: "xargs inline command requires explicit approval in strictInlineEval mode", - }, - { - command: ["make", "-f", "evil.mk"], - expected: "make -f requires explicit approval in strictInlineEval mode", - }, - { - command: ["sed", "s/.*/id/e", "/dev/null"], - expected: "sed inline program requires explicit approval in strictInlineEval mode", - }, ] as const; setRuntimeConfigSnapshot({ tools: { @@ -1363,12 +1349,11 @@ describe("handleSystemRunInvoke mac app exec host routing", () => { }); it("does not persist allow-always approvals for strict inline-eval carriers", async () => { + // Persistence behavior is covered generically in exec-approvals tests; keep + // one flag carrier and one inline-program carrier wired through the handler. const cases = [ { executable: "python3", args: ["-c", "print('hi')"] }, { executable: "awk", args: ['BEGIN{system("id")}', "/dev/null"] }, - { executable: "find", args: [".", "-exec", "id", "{}", ";"] }, - { executable: "xargs", args: ["id"] }, - { executable: "sed", args: ["s/.*/id/e", "/dev/null"] }, ] as const; setRuntimeConfigSnapshot({ tools: { diff --git a/ui/src/ui/chat/slash-commands.ts b/ui/src/ui/chat/slash-commands.ts index af4b69d43af..4e30ec35bd4 100644 --- a/ui/src/ui/chat/slash-commands.ts +++ b/ui/src/ui/chat/slash-commands.ts @@ -332,9 +332,9 @@ function buildLocalSlashCommands(): SlashCommandDef[] { return [...builtins, ...UI_ONLY_COMMANDS]; } -function buildReservedLocalSlashNames(): Set { +function buildReservedLocalSlashNames(localCommands = buildLocalSlashCommands()): Set { const reserved = new Set(); - for (const command of buildLocalSlashCommands()) { + for (const command of localCommands) { reserved.add(normalizeLowercaseStringOrEmpty(command.name)); for (const alias of command.aliases ?? []) { const normalized = normalizeSlashIdentifier(alias); @@ -392,7 +392,7 @@ function replaceSlashCommands(next: SlashCommandDef[]) { function buildSlashCommandsFromEntries(entries: CommandEntry[]): SlashCommandDef[] { const local = buildLocalSlashCommands(); - const reservedLocalNames = buildReservedLocalSlashNames(); + const reservedLocalNames = buildReservedLocalSlashNames(local); const mapped = entries .slice(0, MAX_REMOTE_COMMANDS) .map((entry) => normalizeCommandEntry(entry, reservedLocalNames))