Repository navigation
ci(gate): grant the serena server and fail an enabled server with no grant - #198
Conversation
CLOUD-35 Make `pr.rs` consume `ruleset.rs` instead of hardcoding checks and merge method
Why Acceptance
Refinement — Ready (incomplete — the derive-don't-hardcode constraint is right, but no computable gate exists until the Refinement gate: Definition of Ready & Done. This body carries only specializations.
Open questions blocking Ready:
Both are answerable the moment CLOUD-54 is refined, and neither is answerable before it. Per the gate document, refinement may proceed around a blocker but implementation may not — and here the blocker removes the artifact and the predicate, not just the schedule, so the honest state is Backlog with the dependency recorded rather than a Ready block asserting a gate that goes red on landing. Canceled — the derive-don't-hardcode constraint belongs to CLOUD-54; this issue has no predicate of its own. Both open questions above are answered by measurement, without CLOUD-54 being refined first. §2 — no
A hardcoded merge method and a derived one are the same bytes. No substring predicate separates them in either direction, so neither tightening the pattern nor scoping the glob rescues the gate. The separating predicate is the comparison effective pair == host-derived pair, which is a reader rather than a banned shape, and that reader is CLOUD-54's. §1 — zero authoritative artifacts, confirmed against the tree. The constraint is already authoritative as house-style §9, "reconstruct, don't hardcode," so an issue restating it holds a second copy of a rule that has one home (DoR §1). Its precedence — Unique acceptance folded into CLOUD-54, which owns the CLOUD-270 Grant the serena MCP server, and fail an enabled server that no allow rule names
Why
Refinement — Ready Refinement gate: Definition of Ready & Done. This body carries only specializations.
Out of scope. A connector re-registering under |
…grant `.mcp.json` declares serena and `enabledMcpjsonServers` turns it on, but no allow rule named it, so every Serena call prompted for approval — including the `mem:` reads AGENTS.md mandates at their triggers, and the memory-write path `memory-guard` deliberately redirects to the Serena tools. The only grant was a git-ignored `settings.local.json`, which dies with the container; an `allow` there is also a widening that house-style §8 bars from an override layer. `mcp-allow-check` could not see it. Its one predicate caught an allow rule whose glob the CLI skips — a grant matching no tool — and had nothing to say about the mirror case, a server with no grant at all. Both fail silently with an approval prompt as the only symptom. `ungranted-enabled-server` closes the second: every name in `enabledMcpjsonServers` must be matched by an allow rule whose server segment equals it. The grant is `mcp__serena__*` rather than the nine read-only tool names, so the write and destructive tools are pre-approved too. Refs: CLOUD-270
d5b185f to
50fa038
Compare
|
/fast-forward |
.mcp.jsondeclares the serena MCP server and.claude/settings.jsonturns it onthrough
enabledMcpjsonServers, but nopermissions.allowrule named it — so everySerena call prompted for approval, including the
mem:reads AGENTS.md mandates attheir triggers and the memory-write path
memory-guarddeliberately redirects to theSerena tools. The only grant in place was a git-ignored
settings.local.json: it dieswith the container, and an
allowthere is a widening that house-style §8's raise-onlyrule bars from an override layer.
mcp-allow-checkhad nothing to say about it. Its one predicate caught an allow rulewhose glob reaches the server segment — a grant the CLI skips, so it matches no tool —
and could not see the mirror case, a server with no grant at all. Both fail the same
way: silently, with an approval prompt as the only symptom.
What changed
.claude/settings.jsongrantsmcp__serena__*.mise-tasks/mcp-allow-checkgains a second predicate,ungranted-enabled-server:every name in
enabledMcpjsonServersmust be matched by an allow rule whose serversegment equals it. Still a pure function of the settings file — no network, no live
MCP state — so the hook, CI and the bats suite answer identically.
tests/mcp-allow-check.batscovers it, including that an absent key and a booleantrueare both no-ops, since a gate may only assert what it can enumerate.For a reviewer
The grant is the whole server rather than the nine read-only tool names, so
write_memory,rename_memory,replace_symbol_body,replace_in_filesandsafe_delete_symbolare pre-approved, and a tool serena adds upstream arrivespre-approved rather than asking. That is a deliberate widening past house-style §5's
absence-means-ask; narrowing it to the read-only set is a one-line change and the gate
accepts either shape.
The suite's existing "this repo's own settings pass the gate today" case is what ties
the predicate to the real file — drop the grant and it goes red.
A connector re-registering as
mcp__<uuid>__*(CLOUD-178) stays uncovered: a repo gatemay only assert the portable name, and the UUID is account-specific.
Refs: CLOUD-270
https://claude.ai/code/session_01DfV8M9dF49ZRgyic5FaRsA