docs(remediation): bank D-15 — token scope is not repository permission
f10-coder holds gitea-mosaicstack-f10-coder.token with write:repository scope and was verified at mint by 'repo access returns 200'. It cannot push: collaborator lookup 404s and its own token reports push:false, pull:true. Capability has three independent layers — token file (raw-API auth), tea login (tea path), repository permission (actual write authority) — and satisfying two proves nothing about the third. Scope bounds what a token may ATTEMPT; repository permission decides what the user may DO. The charter principle failing on the check meant to confirm capability: a 200 on a READ was accepted as evidence of WRITE. written-unverified treated as verified, by both provisioner and orchestrator, one layer above D-12. RM-50's pre-dispatch check must assert effective permission for the intended operation (permissions.push == true as that seat), not token existence or a read returning 200. A capability check that cannot fail on a seat lacking write permission is itself an inert gate. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
d0ad6e942b
commit
3477e933df
@@ -93,6 +93,44 @@ and must not be cited as merge evidence. Rely on reviewer clearance + real CI.
|
|||||||
Three independent live instances in a single session — format gate, agent context reset, queue guard —
|
Three independent live instances in a single session — format gate, agent context reset, queue guard —
|
||||||
is the class confirmed, not anecdote.
|
is the class confirmed, not anecdote.
|
||||||
|
|
||||||
|
### D-15 — token scope is not repository permission (a THIRD capability layer)
|
||||||
|
|
||||||
|
`f10-coder` was provisioned with `gitea-mosaicstack-f10-coder.token`, scopes `write:repository` +
|
||||||
|
`write:issue`, and the mint was verified by "repo access returns 200". It then failed to push:
|
||||||
|
|
||||||
|
```
|
||||||
|
remote: error: User permission denied for writing.
|
||||||
|
remote: error: pre-receive hook declined
|
||||||
|
```
|
||||||
|
|
||||||
|
Verified objectively rather than inferred (per the charter principle):
|
||||||
|
|
||||||
|
| probe | result |
|
||||||
|
| ------------------------------------------------------ | ------------------------------------------- |
|
||||||
|
| `GET /repos/mosaicstack/stack/collaborators/f10-coder` | **404** — not a collaborator |
|
||||||
|
| repo permissions as seen by **its own token** | `admin: false`, `push: false`, `pull: true` |
|
||||||
|
|
||||||
|
**Capability has at least three independent layers, and satisfying two proves nothing about the third:**
|
||||||
|
|
||||||
|
1. **Token file exists** → raw-API authentication works (D-11b).
|
||||||
|
2. **`tea` login exists** → tea-dependent wrapper paths work (D-13).
|
||||||
|
3. **Repository permission granted** (collaborator/team membership) → _writes_ are actually authorised.
|
||||||
|
|
||||||
|
A token can carry `write:repository` scope and still be refused, because **scope bounds what a token
|
||||||
|
may attempt; repository permission decides what the user may do.** They are different systems.
|
||||||
|
|
||||||
|
**This is the charter principle failing on the very check meant to confirm capability.** The mint was
|
||||||
|
validated by an HTTP 200 on a _read_. A 200 proves reachability; it does not prove the property that
|
||||||
|
was required, which was **write**. Both the provisioner and I accepted it — the same
|
||||||
|
`written-unverified` treated as `verified` as D-12, one layer up, on a check whose entire purpose was
|
||||||
|
verification.
|
||||||
|
|
||||||
|
**Requirements.** RM-50's pre-dispatch capability check must probe the **effective permission for the
|
||||||
|
operation intended** — for push authority, assert `permissions.push == true` as that seat, not token
|
||||||
|
existence and not a 200 on a read. RM-04's registry reconciliation covers all three layers, with a
|
||||||
|
must-fail control for each. A capability check that cannot fail on a seat lacking write permission is
|
||||||
|
itself an inert gate.
|
||||||
|
|
||||||
### D-14 — a ruled decision did not propagate to the authoritative record
|
### D-14 — a ruled decision did not propagate to the authoritative record
|
||||||
|
|
||||||
DECISION-1 (the corrected choke-point wire-in target) was ruled by the coordinator and applied to
|
DECISION-1 (the corrected choke-point wire-in target) was ruled by the coordinator and applied to
|
||||||
|
|||||||
Reference in New Issue
Block a user