test(security): assert block stops further tool calls, allow lets them through

Gap caught by user: the review-flow tests verified the decision path
(POST, file write, agent_error emission) but not the actual security
property — that Block stops subsequent tool calls and Allow lets them
continue.

Mock-claude tool_result_injection scenario now emits a second tool_use
~8s after the injected tool_result, targeting post-block-followup.
example.com. If block really blocks, that event never reaches the
chat feed (SIGTERM killed the subprocess before it emitted). If allow
really allows, it does.

Allow test asserts the followup tool_use DOES appear → session lives.
Block test asserts the followup tool_use does NOT appear after 12s →
kill actually stopped further work. Both tests previously proved the
control plane (decision file → agent poll → agent_error); they now
prove the data plane too.

Test timeout bumped 60s → 90s to accommodate the 12s quiet window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-20 22:03:29 +08:00
co-authored by Claude Opus 4.7
parent 53202b5a14
commit 2b4a2c7840
2 changed files with 70 additions and 7 deletions
+22 -5
View File
@@ -133,11 +133,28 @@ process.on('SIGTERM', () => {
],
},
});
// Stay alive up to 120s waiting for the user's review decision to
// propagate back through the kill file. On Allow, we just exit cleanly
// after a short delay. On Block, SIGTERM handler exits 143.
await sleep(120000);
emit({ type: 'result', result: 'mock-claude: review decision timeout' });
// Wait long enough for the review decision to propagate (BLOCK path
// SIGTERMs us here — see handler at top). On ALLOW the review loop
// unblocks and we continue with a second tool_use to a sensitive
// domain. If block actually blocks, this second event never reaches
// the chat feed (test asserts on that). If allow actually allows, it
// does.
await sleep(8000);
emit({
type: 'assistant',
message: {
content: [
{
type: 'tool_use',
id: 'toolu_02_followup',
name: 'Bash',
input: { command: '$B goto https://post-block-followup.example.com/' },
},
],
},
});
await sleep(500);
emit({ type: 'result', result: 'mock-claude: post-review followup complete' });
process.exit(0);
}