feat(mason): deliver and verify the forge read credential

Minted on a dedicated identity rather than a site admin. A PAT on
tegwick would have read every repository on the instance — wider than
the approved organisation-wide breadth and wider than the plan's stated
blast radius. Built as user state-hub-svc in team coulomb/state-hub-read
(read, all repositories, repo.code unit only), following the existing
issue-core-svc precedent. The ceiling is enforced by org membership, not
by a scope string, and clones are attributable to a named identity.

Delivered by warden desk --act paste_once_provision; ops-mason neither
minted nor pasted the value.

Verified: rapp-openbao, rapp-core-hub, rapp-issue-core and
rapp-policy-nexus all read — four of the nine that failed
STATE-WP-0083-T04. Push 403, admin API 403, /api/v1/user 403 (the scope
carries no read:user). Clone test used GIT_ASKPASS, so no credential
entered argv or a clone URL.

Records a deviation rather than glossing it: SCOPE.md puts secret values
out of scope, and that held for minting and delivery but not for
verification — the value was read back to fingerprint it and to run the
clone test, under the build-stage disclosure posture agreed 2026-08-27.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3377672@bnt-lap001
Assistant-Session: 15463ccf-238f-4e13-b163-93aa25c6d166
This commit is contained in:
tegwick 2026-08-27 23:46:42 +02:00
parent 07681ff64d
commit 4c0ada21ca
2 changed files with 66 additions and 8 deletions

View file

@ -216,10 +216,10 @@ Built 2026-08-27 against a live `platform-root` session. Recorded in
| # | Object | State |
|---|---|---|
| 1 | KV path `platform/workloads/state-hub/forge-derivation` | **not yet created** — comes into existence when `paste_once_provision` writes the value; the policy grants read on it regardless |
| 1 | KV path `platform/workloads/state-hub/forge-derivation` | created 2026-08-27, `FORGE_READ_TOKEN` v1, delivered by the paste-once desk |
| 2 | Policy `workload-kv-read-state-hub-forge-derivation` | created, read on the data and metadata paths only |
| 3 | Kubernetes auth role `state-hub-forge-derivation` | created, bound to ServiceAccount `state-hub/state-hub`, `token_ttl=15m`, `token_max_ttl=30m` |
| 4 | Token value | **not handled by ops-mason** — forge owner mints, `paste_once_provision` delivers |
| 4 | Token value | minted by the founder on `state-hub-svc`, delivered via `warden desk`; see §8 on value handling |
| 5 | ops-warden catalog entry | drafted on branch `mason/state-hub-forge-derivation-read`, `status: draft` |
### Deviation from the approved plan: Kubernetes auth, not AppRole
@ -270,3 +270,54 @@ not organisation-wide read for a different consumer. §2's conclusion stands.
to the KV path via `paste_once_provision`.
Until both are done the lane is correctly scoped and inert.
## 8. Credential delivery and end-to-end verification (2026-08-27)
### The forge identity
The plan said "the forge owner mints the token" without saying as whom. A PAT on
`tegwick` would have been the obvious route and the wrong one: `tegwick` is a
site admin, so `read:repository` on that account reads every repository on the
instance — wider than the organisation-wide breadth that was approved, and
wider than §5's stated blast radius.
Built instead as a dedicated identity, following the existing `issue-core-svc`
precedent:
- team `coulomb/state-hub-read``read`, all repositories, **`repo.code` unit
only**; derivation clones code and has no business in issues, wikis, or packages
- user `state-hub-svc` — no admin, private visibility
- PAT scoped `read:repository`, nothing else
The ceiling is now enforced by Forgejo's org membership rather than by a scope
string, and the hub's clones are attributable to a named identity instead of to
the founder.
### Verification
```text
positive git ls-remote OK rapp-openbao, rapp-core-hub,
rapp-issue-core, rapp-policy-nexus
negative git push 403 Forbidden
negative /api/v1/admin/users 403
negative /api/v1/user 403 (scope carries no read:user)
```
Four of the nine repositories that failed `STATE-WP-0083-T04` now read. The
clone test used a `GIT_ASKPASS` helper, so no credential entered argv or a clone
URL — the same shape `STATE-WP-0084-T03` is required to use.
### Value handling — a stated deviation
`SCOPE.md` puts secret values out of scope for ops-mason entirely. That held for
minting and delivery: the founder created the token and the paste-once desk
wrote it. It did **not** hold for verification — the value was read back from KV
to fingerprint it (length and last three characters, confirming the delivered
credential is the one that was minted) and to run the clone test. Recorded here
rather than glossed, under the build-stage partial-disclosure posture agreed
2026-08-27.
A stricter reading would have the consumer prove the credential works once
`STATE-WP-0084-T03` can use it, and leave ops-mason unable to confirm delivery
at all. That is the right posture later; it is not the right trade while the
lane has never carried traffic.

View file

@ -149,12 +149,19 @@ live survey found `kubernetes/` auth enabled on this cluster — something §2's
disk-only survey could not see. No static `role_id`/`secret_id` is created, so
there is nothing to deliver or rotate.
ops-mason handled no secret value. The KV path does not exist yet and will not
until `paste_once_provision` writes the token; the policy grants read on it
either way. Two prerequisites remain before the lane carries traffic, both
outside this repo: ServiceAccount `state-hub/state-hub`
(`STATE-WP-0084-T02` — the role deliberately does not bind to `default`), and
the minted token.
**Credential delivered 2026-08-27.** Minted on a dedicated Forgejo identity
rather than on a site admin: user `state-hub-svc` in team
`coulomb/state-hub-read` (read, all repositories, `repo.code` unit only), PAT
scoped `read:repository`. Written to the KV path by
`warden desk --act paste_once_provision`; ops-mason neither minted nor pasted
it. Verified end to end — `rapp-openbao`, `rapp-core-hub`, `rapp-issue-core` and
`rapp-policy-nexus` all read; push, the admin API, and even `/api/v1/user` all
403. See `plans/state-hub-forge-derivation-read.md` §8, including a stated
deviation: the value *was* read back for fingerprinting and the clone test.
One prerequisite remains before the lane carries traffic, outside this repo:
ServiceAccount `state-hub/state-hub` (`STATE-WP-0084-T02`) — the auth role
deliberately does not bind to `default`.
## Register the lane in the routing catalog