Repository navigation
feat(capy): fence native MCP sends to binding-owned identities - #110
Conversation
Pre-merge checks:
|
There was a problem hiding this comment.
Approve on exact head 12deb81 against the Capy OAuth alias seam contract (Control #99).
Contract checks (code read at this head):
- Gate:
capyFallbackrequires!managed && !oauth && context.capy;routes.tsadditionally withholds the resolver for OAuth, required desktop calls and provider calls, so OAuth/managed contexts never see it. - Send-only:
{ capy: true }is opted in only bysend;read/inbox/leave/subscribeChannel/launch/desktop link reachparticipant()with no Capy path and refuse the name. - No participant rows, no auto-join:
capyActorruns before thejoin({})fallback and never inserts;agentForinCapyBindingsnever registers or recovers a token. - OAuth
participant()/assertActor/pinuntouched;ownsRemoteand the consent name check now exclude Capy metadata (including malformedcapy_binding_id/created_bymarkers), so neither OAuth pin nor native join recovery can adopt a binding-owned remote. Teardown keeps following onlycreated_by: "mcp-oauth"remotes. - Factory unchanged;
factory-/capy-prefixes are disjoint andviaFactoryis suppressed whenviaCapyapplies. - Admitted route/key recheck in
capyActor, and a second custody resolution after parent/address reads immediately before the write (token equality, refuse on change; 503 passes through). Idempotency key derivation needs no row. - No migration, flag, pin or server wiring (
server.tsuntouched; runtime capability stays false). 0046 remains unreserved.
Local checks on this head (typecheck + focused Node tests, one worker, serial):
npm run typecheck: exit 0test/capy-mcp-identity.test.ts: 6/6 passtest/capy-bindings.test.ts: 23/23 passtest/mcp-oauth-admission.test.ts: the full file cannot complete under my host's 4 GiB test memory guard (OOM-killed at test 18 of 40, identical on main 02e3f8b, so not a PR regression). The new test run alone by name pattern: 1/1 pass.- Exact-head CI "Typecheck and test" (run 42993364554): success. That run is the full-suite witness for this head.
Non-blocking: CAPY_REPLY_GUIDANCE says replies are addressed to the bound Capy thread, but until the delivery worker lands nothing reads them (inbox is refused for the identity). Dormant today since the server does not mount the resolver; consider wording it as future-tense or noting it in docs/capy.md when the delivery slice arrives.
Review-only: I do not merge.
🤖 Generated with Claude Code
|
Review5856472424 is addressed: CodeRabbit's visible title/description checks are inconclusive, with no code finding or location; its check is skipped. No hidden finding or rerun is being used as a gate. Required exact-head CI is green, and there are no unresolved review threads. Local full source regression: 1,170 pass/13 existing skips/0 fail, plus typecheck/build and six detected causal controls. This remains source proof; runtime/E2E are tracked in #99. |
An injected native MCP caller can send or reply as its own bound Capy agent without creating a generic participant alias. This is the next source slice for #99; the server does not supply the resolver yet and runtime capability remains false.
The hook is send-only and requires an unmanaged, non-OAuth person call naming a Capy agent. The existing binding service rechecks current ownership, manager membership, connection, generation and immutable remote identity. The send also checks the admitted Relay route/key and resolves custody again after parent/address reads, immediately before writing. Missing/changed custody refuses; verification outages remain errors. Idempotency and parent-DM validation are preserved.
Generic participant recovery and OAuth name availability now exclude Capy binding metadata, including malformed binding markers. An ordinary participant whose name starts with
capy-remains usable. OAuth actor/pin, Factory read/send behavior, Desktop links, channels and launch rights are unchanged.Validation:
npm ci; dependencies resolve inside this T7 checkout.node --import tsx --test --test-concurrency=1 test/*.test.tsthroughaw-heavy: 1,170 passed, 13 existing skips, 0 failed (1,183 total) on12deb81cc9994bc1902a91edbf45f60aa292a44e.npm run typecheckandnpm run buildthroughaw-heavy: clean on that same head.This adds no migration, flag, public route, provider callback, delivery worker or deployment. Replies are addressed to the bound thread; the receipt does not assert provider delivery. Double live verification needs latency measurement before mounting. OAuth-bound Capy, subscriptions/outbox, background history and real-account E2E remain tracked follow-ups.
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.