From 4c0ada21caa28f2bdbad0953558330fbb5751154 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 27 Aug 2026 23:46:42 +0200 Subject: [PATCH] feat(mason): deliver and verify the forge read credential MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Assistant: claude-code Assistant-Model: opus Assistant-Process: 3377672@bnt-lap001 Assistant-Session: 15463ccf-238f-4e13-b163-93aa25c6d166 --- plans/state-hub-forge-derivation-read.md | 55 ++++++++++++++++++- ...MASON-WP-0003-state-hub-forge-read-lane.md | 19 +++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/plans/state-hub-forge-derivation-read.md b/plans/state-hub-forge-derivation-read.md index 795f37a..47a69eb 100644 --- a/plans/state-hub-forge-derivation-read.md +++ b/plans/state-hub-forge-derivation-read.md @@ -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. diff --git a/workplans/MASON-WP-0003-state-hub-forge-read-lane.md b/workplans/MASON-WP-0003-state-hub-forge-read-lane.md index a78d28c..be66601 100644 --- a/workplans/MASON-WP-0003-state-hub-forge-read-lane.md +++ b/workplans/MASON-WP-0003-state-hub-forge-read-lane.md @@ -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