Repository navigation
feat: require server-side approval for every generated DELETE tool - #247
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
delete_useranddelete_account_role) now goes through the existing two-phase approval flow: the first call returns anapproval_requiredenvelope with a human-readable summary and a single-use token, and the call only executes afterconfirm_actionis invoked with that token.GeneratedToolgains an optionalsummary(args);generateToolssets it for DELETE operations only, built from the operation's OpenAPI summary, the resolved path params, and the customer scope (for exampleDelete user (id="abc") for customer xyz. This cannot be undone: DELETE /iam/v1/users/{id}.).executeToolHandlerresolves the gate fromWRITE_GATED_SUMMARIESor the generated tool'ssummary, so no dispatch code changed.confirm_actionis exposed again. It joinsHAND_WRITTEN_TOOLS(withcoversEndpoint: null) soserver.tsand the integration tool-surface test pick it up without a special case.destructiveHint, which is the reason thecreate_ticketgate was removed in Remove approval token dialog for create ticket #170. That decision is preserved and documented in the registry comment.Why
An external researcher pointed out that the approval mechanism was wired to zero tools while every non-GET generated tool relied on
destructiveHint, which is an advisory client-side annotation. A prompt-injected agent that ignores the hint could delete a platform user or disconnect an AWS account in one call. This is defense in depth (the API still enforces the caller's own permissions), but deletes are the irreversible subset and are the right place to draw the line. Credit: Syed Anas Mohiuddin.Transport notes
The stdio server enforces the gate as before (
MemoryApprovalStore,userKey = "stdio-local"). The remote Worker in the separate private repo already bindsuserKeyto the OAuth identity and passesgeneratedTools, so it picks the gate up when it bumps to this version. It must also re-listconfirm_actionin its tool surface, otherwise clients there receive an envelope they cannot confirm. That change is needed before this ships to the hosted endpoint.How validated
toolsHandler.test.ts: the three previously skipped gate tests are replaced with live ones against a synthetic generated DELETE tool (envelope without API call, confirm runs exactly once, distinct tokens, non-DELETE generated tools run directly).generateTools.test.ts: summary shape, and an assertion over the bundled spec that every DELETE has a summary and nothing else does.test/integration/stdio/approvalFlow.test.ts: un-skipped and rewritten arounddelete_alertwith an msw DELETE handler that records hits, proving no request leaves before confirmation and exactly one after.yarn check:dev,yarn test(911 passed), andyarn testintest/integration(184 passed) all green locally.🤖 Generated with Claude Code