From 4ebd241d88e0f65125b3097a6d3aeccd4c294eb6 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 14 Sep 2026 04:57:55 +0200 Subject: [PATCH] Register the State Hub Forgejo derivation-read routing lane. Pointer-only catalog entry so warden route find "state hub read private repository" resolves. ops-warden routes and does not execute. MASON-WP-0003-T03. Assistant: grok Assistant-Session: 01a09dc1-b21e-77e1-919e-fcad2f82b267 --- registry/generated/high-risk-data-paths.yaml | 13 +- registry/routing/catalog.yaml | 31 +++++ .../state-hub-forge-derivation-read.md | 120 ++++++++++++++++++ 3 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 wiki/playbooks/state-hub-forge-derivation-read.md diff --git a/registry/generated/high-risk-data-paths.yaml b/registry/generated/high-risk-data-paths.yaml index 8bc63da..25561e6 100644 --- a/registry/generated/high-risk-data-paths.yaml +++ b/registry/generated/high-risk-data-paths.yaml @@ -10,12 +10,12 @@ # declares it, and is null where the field set has not been established -- # null means unknown, never 'one field'. -generated_at: "2026-09-10T05:54:39Z" +generated_at: "2026-09-14T02:57:04Z" source: ops-warden/registry/routing/catalog.yaml -catalog_revision: "406446f7bb38efadf85849756c067a124902a2ec" -catalog_revision_date: "2026-09-10T07:54:39+02:00" -catalog_dirty: false -high_risk_lane_count: 24 +catalog_revision: "73e40af6ca27ca547eb42782d2ceb1a5cc8c3534" +catalog_revision_date: "2026-09-14T02:47:32+02:00" +catalog_dirty: true +high_risk_lane_count: 27 concrete_path_count: 15 # Graded high but not a single KV address -- a routing pattern, a broker @@ -30,6 +30,9 @@ no_concrete_path: - openbao-platform-admin-login - openbao-shamir-recovery-ceremony - ops-warden-warden-sign-token + - secrets-engine-approval-client-login + - secrets-engine-requester-login + - state-hub-forge-derivation-read paths: - id: agent-harness-binky-mail-approle diff --git a/registry/routing/catalog.yaml b/registry/routing/catalog.yaml index f8c66f4..da27413 100644 --- a/registry/routing/catalog.yaml +++ b/registry/routing/catalog.yaml @@ -684,6 +684,37 @@ entries: - "Verify capabilities-safe on the data path (`bao token capabilities`); run a restore drill against a re-encrypted artifact." - "After rotation, clear EXPOSED taint: remove custom_metadata exposed_at/exposed_version (see `warden taint railiance-backup-offsite-lane`)." + - id: state-hub-forge-derivation-read + title: Forgejo read-only token for State Hub projection derivation + risk: high + workload_ref: + applicability: applicable + unknown_reason: "state-hub has not published an authoritative workload identity declaration; Kubernetes auth role state-hub-forge-derivation binds ServiceAccount state-hub/state-hub." + need_keywords: [state-hub, statehub, forge, forgejo, derivation, derive, projection, private, repository, clone, FORGE_READ_TOKEN, ADR-012, work-records, unreadable, kubernetes-auth] + owner_repo: ops-mason + subsystem: OpenBao + Forgejo + warden_executes: false + wiki_ref: wiki/playbooks/state-hub-forge-derivation-read.md#worker-checklist + canon_ref: ops-mason/plans/state-hub-forge-derivation-read.md + reviewed: "2026-09-14" + status: active + delegation: + mode: native + intended_owner: ops-mason + reviewed: "2026-09-14" + verified: owner-confirmed + auth_method: "Kubernetes auth (role state-hub-forge-derivation, ServiceAccount state-hub/state-hub) from the in-cluster state-hub workload" + path_template: "platform/workloads/state-hub/forge-derivation (field FORGE_READ_TOKEN)" + rotation: + method: rotate + owner: ops-mason + automatable: false + steps: + - "Mint a replacement read-only token in Forgejo — repository read, organisation-wide, no other scope." + - "Deliver it to platform/workloads/state-hub/forge-derivation, field FORGE_READ_TOKEN, via paste_once_provision. ops-mason does not handle the value." + - "Revoke the previous token in Forgejo." + - "Confirm a derivation pass still reads a known private repository; rotation must not require a chart change or a redeploy." + - id: forgejo-admin-api-token title: Forgejo operator/admin API token (PAT) need_keywords: [forgejo, admin, pat, package, prune, FORGEJO_ADMIN_TOKEN, forgejo-package-prune, forgejo-tegwick, webhook, forgejo-npm] diff --git a/wiki/playbooks/state-hub-forge-derivation-read.md b/wiki/playbooks/state-hub-forge-derivation-read.md new file mode 100644 index 0000000..5bcc9a2 --- /dev/null +++ b/wiki/playbooks/state-hub-forge-derivation-read.md @@ -0,0 +1,120 @@ +# State Hub Forge Derivation Read Token + +Date: 2026-08-26 (policy and auth role built and verified 2026-08-27; catalog active 2026-09-14) +Catalog: `state-hub-forge-derivation-read` (status `active`) +Owner: `ops-mason` (built under `ops-mason/plans/state-hub-forge-derivation-read.md`, approved 2026-08-26) + +Read-only Forgejo token so the State Hub can clone **private** repositories and +derive their work records. `CUST-ADR-012` makes the forge the projection source; +that premise held only for repositories central could read, and nine private +repositories were invisible to derivation entirely (`STATE-WP-0083-T04`, +2026-08-26). + +**This lane is a pointer.** ops-warden routes it and executes nothing: it issues +SSH certificates only and owns no secret store. The Kubernetes auth role, policy, +and KV path are ops-mason's build; the token value is minted by the forge owner +and delivered through `paste_once_provision`. The credential was delivered +2026-08-27; `STATE-WP-0084` mounted it into State Hub. + +**Ask first:** `warden plan "state hub read private repository" --json`. + +--- + +## OpenBao pointers + +| Field | Value | +| --- | --- | +| Mount | `platform` | +| Path | `platform/workloads/state-hub/forge-derivation` | +| Secret field | `FORGE_READ_TOKEN` | +| Policy | `workload-kv-read-state-hub-forge-derivation` (read on that path alone) | +| Auth | Kubernetes auth role `state-hub-forge-derivation`, bound to ServiceAccount `state-hub/state-hub` (`token_ttl=15m`, `token_max_ttl=30m`) | + +**Forgejo token scope:** repository **read**, organisation-wide. No push, no +administration, no other Forgejo resource. Approved at that breadth on +2026-08-26 — the maintenance cost of per-repository grants lands on whoever adds +a private repository later, and the leak radius (every private repository, +read-only) was accepted knowingly. Reasoning in the construction plan §6. + +**Not the admin PAT.** `forgejo-admin-api-token` is a site-admin credential +owned by `railiance-platform`. Reusing it here was considered and rejected: a +projection that only reads must not hold an identity that can write. + +--- + +## Worker checklist + +1. **Plan** (agents — always): + + ```bash + warden plan "state hub read private repository" --json + # expect lane=state-hub-forge-derivation-read + ``` + +2. **In-cluster consumers do nothing here.** The `state-hub` deployment receives + the credential as a Kubernetes Secret; `derive_from_forge()` picks it up on + its own. If derivation reports a repository as unreadable, the lane is the + thing to check — not the repository. + +3. **Never put the token in a clone URL.** Embedded userinfo lands in logs and + process listings. Use a credential helper or an HTTP header. + +4. **Reading the value directly** (operators, rare — verification only): + + ```bash + bao kv get -field=FORGE_READ_TOKEN platform/workloads/state-hub/forge-derivation + ``` + +--- + +## Verify the lane (capabilities-safe — never read the value) + +```bash +# Positive: the lane identity can read the data path +bao token capabilities platform/data/workloads/state-hub/forge-derivation +# → expect: read + +# Negative: it can read nothing else, including the admin lane +bao token capabilities platform/data/workloads/forgejo/forgejo-admin +# → expect: deny +``` + +Verified 2026-08-27 through a 2-minute test token, revoked after use: `read` on +its own path; `deny` on `forgejo-admin`, on the shared `llm-connect` provider +secrets, and on the parent metadata path (no listing). + +**Why Kubernetes auth and not an AppRole.** The construction plan proposed an +AppRole; the phase-4 live survey found `kubernetes/` auth already enabled on +this cluster, and the founder ruled for it on 2026-08-27. The pod authenticates +with its own projected ServiceAccount token, so this lane has no `role_id` +/`secret_id` pair to deliver, store, or rotate. The role binds to +`state-hub/state-hub` and deliberately **not** to `default`, which would grant +the lane to every pod in the namespace. + +The negative check is the one that matters. The whole argument for building this +lane instead of reusing `forgejo-admin-api-token` is that it cannot do what that +one can. + +--- + +## Rotation + +Re-mint in Forgejo, then overwrite the KV field. Rotation must not require a +chart change or a redeploy — if it does, the delivery in +`STATE-WP-0084-T02` is wrong and should be fixed rather than worked around. + +1. Mint a replacement read-only token in Forgejo (same scope: repository read, + organisation-wide). +2. Deliver it to `platform/workloads/state-hub/forge-derivation`, field + `FORGE_READ_TOKEN`, via `paste_once_provision`. +3. Revoke the previous token in Forgejo. +4. Confirm a derivation pass still reads a known private repository. + +--- + +## See also + +- `ops-mason/plans/state-hub-forge-derivation-read.md` — the construction plan +- `ops-mason/workplans/MASON-WP-0003-state-hub-forge-read-lane.md` — the build +- `state-hub/workplans/STATE-WP-0084-forge-read-for-private-repositories.md` — the consumer +- `wiki/playbooks/forgejo-admin-api-token.md` — the lane this one is deliberately not