# 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 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 ``` 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