fix(binjovi): one owner for the Claude MCP client #711

Merged
binjovi-bot merged 1 commit from fix/retire-duplicate-claude-registrar into trunk 2026-09-13 14:45:54 +00:00
Owner

Ships with sean/ory #120. Reverts the registrar added in #699.

Two owners, one scope apart

This repository registered binjovi-claude-code, and so does sean/ory:

writer binjovi scopes repository.create
sean/ory manifests/stack/binjovi-mcp-claude-client.yaml 20 no
here, claude-code-oauth.yaml (#699) 21 yes

Whichever synced last won, so the scope came and went. The live client was
diffed against this registrar to confirm it: exactly one scope missing, every
other field identical.

The symptom was an MCP create_repository call refused with a bare forbidden
while the control plane's BINJOVI_MCP_POLICY plainly granted it — authorization
is the intersection of the policy binding and the token's scope claim, and
ory kept winning the scope.

Why removed rather than repaired

Binjovi names the owner itself:

Ory GitOps owns these public clients and fixes their sole audience to MCP

(Binjovi.MCPOAuth.Protocol, @managed_clients). Matching the two scope strings
would leave two writers that must be kept in step by hand — the same shape as the
ForgejoRepository duplication this fleet has been removing. sean/ory #120 adds
the scope where it belongs.

The Job orphans safely

The binjovi Kustomization is prune: false, so removing the file leaves
binjovi-claude-code-oauth-v1 in the cluster. ttlSecondsAfterFinished: 86400
reaps it within a day, and with nothing declaring it Flux does not recreate it —
the daily re-converge loop that tests/job-ttl-contract.sh documents runs down
instead of round. No tombstone needed.

Guard

The public-client assertions are replaced by one refutation — no manifest in this
component may register this client_id:

refute -rFq 'client_id=binjovi-claude-code' "$component"

Confirmed by reinstating the deleted file: the guard fails. tests/check.sh
green, 108 guards.

https://claude.ai/code/session_01JGe4pyhQ36AhgDfPJry4d3

Ships with `sean/ory` #120. Reverts the registrar added in #699. ## Two owners, one scope apart This repository registered `binjovi-claude-code`, and so does `sean/ory`: | writer | binjovi scopes | `repository.create` | |---|---|---| | `sean/ory` `manifests/stack/binjovi-mcp-claude-client.yaml` | 20 | no | | here, `claude-code-oauth.yaml` (#699) | 21 | yes | Whichever synced last won, so the scope came and went. The live client was diffed against this registrar to confirm it: **exactly one scope missing, every other field identical.** The symptom was an MCP `create_repository` call refused with a bare `forbidden` while the control plane's `BINJOVI_MCP_POLICY` plainly granted it — authorization is the **intersection** of the policy binding and the token's `scope` claim, and ory kept winning the scope. ## Why removed rather than repaired Binjovi names the owner itself: > Ory GitOps owns these public clients and fixes their sole audience to MCP (`Binjovi.MCPOAuth.Protocol`, `@managed_clients`). Matching the two scope strings would leave two writers that must be kept in step by hand — the same shape as the `ForgejoRepository` duplication this fleet has been removing. `sean/ory` #120 adds the scope where it belongs. ## The Job orphans safely The `binjovi` Kustomization is `prune: false`, so removing the file leaves `binjovi-claude-code-oauth-v1` in the cluster. `ttlSecondsAfterFinished: 86400` reaps it within a day, and with nothing declaring it Flux does not recreate it — the daily re-converge loop that `tests/job-ttl-contract.sh` documents runs down instead of round. No tombstone needed. ## Guard The public-client assertions are replaced by one refutation — no manifest in this component may register this `client_id`: ```bash refute -rFq 'client_id=binjovi-claude-code' "$component" ``` Confirmed by reinstating the deleted file: the guard fails. `tests/check.sh` green, 108 guards. https://claude.ai/code/session_01JGe4pyhQ36AhgDfPJry4d3
fix(binjovi): one owner for the Claude MCP client
All checks were successful
binjovi/ci Binjovi completed the frozen plan
681c91c05a
This repository registered binjovi-claude-code, and so does sean/ory.
Two owners of one Hydra client, disagreeing by exactly one scope: ory
declared 23 and this repository 24. Whichever synced last won, so
binjovi.repository.create came and went.

The symptom was an MCP create_repository call refused with a bare
`forbidden` while the control plane policy plainly granted it.
Authorization is the INTERSECTION of the policy binding and the token's
scope claim, and ory kept winning the scope. A diff of the live client
against this registrar showed one scope missing and every other field
identical.

Binjovi names the owner: "Ory GitOps owns these public clients and fixes
their sole audience to MCP" (Binjovi.MCPOAuth.Protocol). So this
registrar is removed, not repaired, and sean/ory #120 adds the scope
where it belongs.

The Job orphans safely. The binjovi Kustomization is prune: false, so
removing the file leaves the Job in the cluster, but
ttlSecondsAfterFinished reaps it within a day and nothing declares it
again. No tombstone is needed.

The public-client assertions are replaced by a refutation: no manifest in
this component may register this client_id. Confirmed by reinstating the
file, which fails the guard.

Claude-Session: https://claude.ai/code/session_01JGe4pyhQ36AhgDfPJry4d3
binjovi-bot deleted branch fix/retire-duplicate-claude-registrar 2026-09-13 14:45:55 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
sean/seanfarm!711
No description provided.