feat(routing): propose state-hub-forge-derivation-read lane (draft)

warden route find "state hub read private repository" returned nothing,
which is why the need had to be reasoned out from first principles
instead of looked up.

Pointer-only (warden_executes: false): ops-mason builds the AppRole,
policy, and KV path under MASON-WP-0003; the forge owner mints the
value; paste_once_provision delivers it. ops-warden routes and executes
nothing.

Graded high on breadth, not on write authority — the token is read-only
but organisation-wide, so a leak reads every private repository.
Approved at that breadth 2026-08-26 (ops-mason plan §6).

status: draft until MASON-WP-0003-T02 has created the structure and the
negative capability check passes.

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-26 21:56:44 +02:00
parent 0fc581ffb9
commit 3a4333d850
2 changed files with 145 additions and 0 deletions

View file

@ -574,6 +574,44 @@ 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
# Organisation-wide repository read: if the value leaks, every private
# repository is readable. Read-only, no write, no admin, no persistence —
# but the breadth is the grade (approved knowingly 2026-08-26).
risk: high
workload_ref:
applicability: applicable
unknown_reason: "The state-hub deployment has no authoritative workload identity declaration yet; the AppRole is the identity until it does."
need_keywords: [state-hub, statehub, forge, forgejo, derivation, derive, projection, private, repository, clone, FORGE_READ_TOKEN, ADR-012, work-records, unreadable]
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-08-26"
status: draft
delegation:
mode: native
intended_owner: ops-mason
blocked_on: "Entry proposed ahead of the build (MASON-WP-0003-T03). Promote to active once MASON-WP-0003-T02 has created the policy, AppRole, and KV path and the negative capability check passes."
reviewed: "2026-08-26"
verified: unverified
# ops-warden routes this and executes nothing: it issues SSH certificates
# only and owns no secret store. ops-mason builds the structure; the forge
# owner mints the value; paste_once_provision delivers it.
auth_method: "AppRole login (state-hub-forge-derivation) 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]

View file

@ -0,0 +1,107 @@
# State Hub Forge Derivation Read Token
Date: 2026-08-26 (proposed)
Catalog: `state-hub-forge-derivation-read` (status `draft` until built)
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 AppRole, policy, and KV path
are ops-mason's build; the token value is minted by the forge owner and
delivered through `paste_once_provision`.
**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) |
| AppRole | `state-hub-forge-derivation` (`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 AppRole identity can read the data path
bao token capabilities <approle-token> platform/data/workloads/state-hub/forge-derivation
# → expect: read
# Negative: it can read nothing else, including the admin lane
bao token capabilities <approle-token> platform/data/workloads/forgejo/forgejo-admin
# → expect: deny
```
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