fix: scope PreToolUse hooks to their own tools - #155
Open
HadiHassan22 wants to merge 1 commit into
Open
HadiHassan22 wants to merge 1 commit into
HadiHassan22 wants to merge 1 commit into
Conversation
check-vgv-cli.sh never read its payload. It emitted a deny/allow decision for whatever tool invoked it, trusting the hooks.json matcher to scope it, so on a host where that matcher does not select correctly a Dart tool-version check denied unrelated MCP tool calls — and, when the CLI was present, silently auto-approved them. Both PreToolUse hooks now confirm from the payload that the call is their business before deciding. block-cli-workarounds.sh had the same fault with a narrower trigger: it filtered on .tool_input.command, a field name rather than the caller's identity, so any MCP tool carrying a command argument could be denied. Also fixes the CLI lookup, which is host-independent. very_good is installed to ~/.pub-cache/bin, which is not on a hook subprocess's PATH, so a present CLI was reported missing. Resolution now falls back to $PUB_CACHE/bin, and because the installed very_good is a shim that execs dart, a binary found but unreadable is reported as "unverifiable" rather than "not installed" — callers stand aside on an inconclusive check instead of denying a genuine call or warning at session start. Adds check-vgv-cli_test.sh and tool-scoping cases to the existing suite. Closes VeryGoodOpenSource#154 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Description
Fixes #154.
check-vgv-cli.shnever read its stdin payload. It rancheck_vgv_cliand emitted adeny/allowdecision for whatever tool invoked it, trusting thehooks.jsonmatcher toscope it. On a host where that matcher does not select correctly, a Dart tool-version check
denied unrelated MCP tool calls — reported from a TypeScript/Next.js project with no Dart in it.
The inverse is worse: when the CLI is present, the same blind path returned
allow, silentlyauto-approving unrelated MCP calls and bypassing the permission prompt.
What changed
Both
PreToolUsehooks now confirm from the payload that the call is their business.A matcher is a filter, not a guarantee, so each hook checks
tool_nameitself and exits 0 whenthe tool is not its own.
block-cli-workarounds.shhad the same fault with a narrower trigger. It filtered on.tool_input.command— a field name rather than the caller's identity — so any MCP tool carryinga
commandargument was inspected and could be denied:It now scopes on
tool_nameinstead, accepting the shell tool under either name hosts give it.When a host sends no
tool_nameat all it falls through to the command check, so enforcement isnever silently dropped.
The CLI lookup is fixed too, and this half is host-independent.
very_goodinstalls to~/.pub-cache/bin, which an interactive shell adds toPATHbut a hook subprocess does notnecessarily inherit — it is not in
/etc/paths. A present CLI was reported missing, producingboth a spurious deny on genuine Very Good CLI calls and a false warning at every session start.
Resolution now falls back to
$PUB_CACHE/bin.A pub-cache fallback alone is not enough: the installed
very_goodis ashshim that execsdart, so aPATHwithoutdartmakes the check inconclusive rather than negative.check_vgv_clinow returnsunverifiablefor that case. Callers stand aside on an inconclusivecheck instead of denying a genuine call or warning that the CLI is missing. A genuinely absent
CLI still denies and still warns, unchanged.
Tests
Adds
hooks/scripts/check-vgv-cli_test.sh(14 cases) and tool-scoping cases toblock-cli-workarounds_test.sh. Every case runs against a stubbedvery_goodon aPATHcontaining nothing else, so results do not depend on what is installed on the machine running
them. Registered in the Script Tests CI job. All three suites pass: 18, 32, 14.
Scope
This does not add Cursor support (#48), and deliberately does not touch the matcher — making
mcp__.*very-good-cli__.*match another host's naming is that issue's business. The change isthat the scripts no longer depend on the matcher being correct, plus a
PATHfix that affectsClaude Code identically. #126 workstream 4 factors these hooks for multi-host adaptation; scoping
on
tool_nameis a prerequisite for it.One
cspellword (Anson) was added: it is pre-existing inci.yamland this PR touches thatfile, which brings it into the spell check's changed-file set.
Known limitation, not addressed here
Cursor's
preToolUsepayload carries no server segment — a Very Good CLItestcall arrives asMCP:test, indistinguishable from any other server'stest. The guard therefore stands aside forgenuine Very Good CLI calls on that host, so the auto-approve is lost there. That is fail-safe: no
false denials, and the tools still work through normal permission handling. Restoring it needs
either matching bare tool names (
create,test, ...), which collide across MCP servers, orCursor's
beforeMCPExecutionevent. Called out in #154 as a follow-up rather than widened here.Type of Change
feat)fix)refactor)docs)ci)chore)🤖 Generated with Claude Code