The MCP plugin_add tool cannot grant derived_names, so an agent can never add a package that needs it #106
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#106
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of #103, which shipped the grant path through the CLI. The MCP tool was left untouched only because
crates/mcp-server/src/server.rswas held by a concurrent lane.Current behaviour: fail-closed and correct, but a dead end
grant: ["requested"]does resolvederived_names: truethroughplan_grant— that part works. Butplugin_addthen drops the bool and callsconform::check(..., false). So C1 runs without the authority the package needs, the verdict fails, and the add is refused.That is at least not silent: the refusal names
fact.span_name_mismatchand the withheld-grant witness explains it. But there is no answer an agent can give that gets past it, which is the same defect class #103 fixed for the CLI, and the same class asplugin_add's old poll instruction naming a state that could never become true.The fix
Three lines: thread
grant.derived_namesintoconform::check_with_grantand into.with_derived_names(..)on the approval.check_with_grantalready exists and already records the answer on the verdict, sorequire_verdict_covering_grantwill accept the result.The test
An MCP-leg e2e adding the ruby package with
grant: ["requested"]and asserting the file indexes — mutated by reverting the thread-through, which must go red at the add, not merely at a later query.Also worth checking in the same pass: the tool's
notemust not name a state that this path cannot reach.crates/mcp-server/tests/tool_notes_name_reachable_states.rsalready grades that property and should cover whatever the note says aboutderived_names.Related
Follow-up to #103. Same family as #104 (re-grant does not reindex) and #105 (aggregate cost of declining).
Fixed. And the second mutation found a quieter defect this issue did not name.
plan_grant's answer is now threaded intoconform::check_with_grant,Approval::with_derived_names, andrequire_verdict_covering_grant(replacingrequire_passing_verdict, matchingcmd_add).The payload gains
derived_names+derived_names_semanticson both the approved and theinstalled_inertreplies. That second placement matters:Grant::renderreturns capabilities and bridges only, so an emptygrantedlist says nothing about this authority — and silence there would read as "not granted" when it might be granted, which is the absent-reads-as-negative shape the project refuses.The test, and its anti-vacuity half
the_mcp_add_can_grant_derived_namesinplugin_add_mcp_e2e.rs, driving a new fixture packagede.h-dv.mcpderivedwhose extractor returns a realcode_index_abi::Encoderframe carrying a derived-name ref —Gammaat the span ofalpha, same length and in range, so the only check it can fail is name-equals-bytes. That construction is what makes the test about this authority rather than about validation in general.Paired with the same package under
grant: ["none"], which must be refused. Without that half, C1's dependence on the authority would be assumed rather than measured.Mutations, both RUN
1 — revert
check_with_grant→check. RED at the add:2 — drop
.with_derived_names(..). RED, and it exposed a defect this issue does not name and I would not have predicted: the add succeeds and the record silently drops the authority.An operator answering yes, an add reporting success, and a stored record saying no. That is worse than the refusal this issue was filed about, because a refusal is visible.
One thing NOT independently graded, stated rather than claimed
Swapping
require_verdict_covering_grantback torequire_passing_verdictstays green. At this call site the verdict's authority and the grant's are the same bool by construction, so the stronger check has nothing extra to catch here. It is kept for front-end parity withcmd_add— and disclosed as untested rather than counted as covered.tool_notes_name_reachable_states.rsstill passes; the note names noderived_namesstate, so there is nothing there to become unreachable.