Repository navigation
fix(v2): resolve host permission rules per real tool name - #469
ranxianglei wants to merge 3 commits into
Conversation
Issue #459: the V2 resolver hard-coded the literal "compress" so all five ACP tools shared one permission decision, and options.permission declared an inert "compress" for every tool. Resolve each tool under its own name (OpenCode ordered last-match semantics preserved), declare options.permission per tool name, and make fail-closed ask/deny messages plus result metadata name the actual tool. Behavior for compress itself is byte-identical; V1 path and nudge gating untouched.
Review follow-up on #469: the PR documented per-tool rule resolution in README.md only; mirror the same sentence in README.zh-CN.md so both readings stay aligned.
[bot] 🏷 Review complete: APPROVE on code quality — but flagging a routing conflict you already decided. Details below; verdict and a question for you at the end. ① Original issue (#459) — direction valid, root cause correctReproduced the failure mode against the base commit ( ② Regression review — existing behaviors on touched paths
No regressions found. All intentional changes are disclosed in the PR body with old→new and rationale. ③ Code reviewClean. Optional ④ Test effectivenessReal tests that bite: I ran the new suite against pre-fix code and watched it fail (5/12), satisfying the "must fail when the bug is present" bar. Assertions are meaningful — content equality ( ⑤ Diff cleanliness6 files, all on-topic (2 source, 1 test, 1 README, 2 devlog). No version bump (correct for a non-release branch), no unrelated churn. Devlog REQ+WORKLOG present; no DESIGN.md needed (no architecture/data-flow change). Verification & caveats
|
Problem
Issue #459 (MAJOR): on the V2 line every ACP tool resolved its permission under the hard-coded literal
"compress"—resolveEffectiveCompressPermission()calledresolveV2Permission(v2Rules, "compress")regardless of which tool executed, and all five tools declared inertoptions.permission: "compress". A granular ruleset therefore produced the opposite of its intent:[{action:"compress",effect:"ask"}]refused four unrelated read-only tools with a message about the compress permission, whilecompressitself was never actually asked.Fix
lib/host-permissions.ts—resolveEffectiveCompressPermission()gains an optionaltoolNameparameter (default"compress") consulted only by the V2 ordered-rules branch. The legacy V1 branch stays keyed to thecompressconfig entry (V1 host configs have no per-tool entries for ACP tools).lib/v2/tools.ts—resolveToolPermission()receives the definition's real name;options.permissionnow carries each tool's own name (kept rather than deleted: measured inert today, but if the host ever honors it as the evaluation action, per-name values make granular host rules work end-to-end instead of mis-declaringcompress); fail-closed ask/deny messages and result metadata now name the actual tool.README.md— one sentence documenting per-tool rule resolution on V2.devlog/2026-09-29_v2-per-tool-permission/.Behavior changes (old → new)
decompress,search_context,acp_status,acp_context_recap): resolved under action"compress"→ resolved under its own name. Rules targeting those names now take effect; rules that previously leaked onto them no longer do. This is the fix.permissionfield / message text for non-compress tools: hard-coded"compress"→ the real tool name (previously misleading).compressitself is byte-identical (resolution input, message text, metadata); OpenCode ordered last-match semantics preserved (the issue's literal example[{compress:ask},{*:deny}]resolves to deny-for-all under last-match because the later*wins for every action — express intent by ordering the specific rule last); ACP's owncompress.permissionconfig gate remains a global gate over all ACP tools; fail-closedaskpreserved (OpenCode 2.0.3 exposes no native permission-request creation API to server plugins — DESIGN §8.1); V1 path and nudge gating (state.compressPermission) untouched.Tests
V2 resolves host rules per real tool name so one tool's rule never leaks (issue #459): deny/ask isolation across all five tool names, metadata accuracy, reverse granularity, including the issue's failure scenarios. Verified to FAIL against pre-fix code (5 of 12 failing pre-fix, 12/12 post-fix)."compress"while the fake tool was named"test"(they now target the tool's own name — which is exactly what the fix makes meaningful), plus the registrationoptionsassertion per tool name.tests/soft-block.test.ts, pre-existing in this sandbox only (it mkdirs into/tmp, which is read-only here); unrelated to this diff. Typecheck + build clean.compressconfirmed).Closes #459