From 9ffa279d1f27b1b08bf4253f0e192395c314684e Mon Sep 17 00:00:00 2001 From: codex Date: Wed, 26 Aug 2026 21:09:34 +0200 Subject: [PATCH] feat(workplan): open MASON-WP-0003 for the state-hub forge read lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nine private repositories are invisible to the hub's derivation: the pod clones Forgejo anonymously, so ADR-012's premise that the forge is the projection source holds only for repositories central can read. warden route find returns no lane for this need, and the nearest entry is an operator admin PAT owned by railiance-platform — more authority than derivation requires. ops-mason owns AppRoles, policies and KV paths, which is what is missing. Six tasks: settle scope and breadth, create the AppRole and KV path, register the routing entry, deliver the credential to the pod, teach the derivation to use it, and confirm the nine. Token creation stays operator-executed; this workplan describes the lane rather than performing it. Co-Authored-By: Claude Opus 5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006 --- ...MASON-WP-0003-state-hub-forge-read-lane.md | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 workplans/MASON-WP-0003-state-hub-forge-read-lane.md diff --git a/workplans/MASON-WP-0003-state-hub-forge-read-lane.md b/workplans/MASON-WP-0003-state-hub-forge-read-lane.md new file mode 100644 index 0000000..a38e755 --- /dev/null +++ b/workplans/MASON-WP-0003-state-hub-forge-read-lane.md @@ -0,0 +1,187 @@ +--- +id: MASON-WP-0003 +type: workplan +title: "Forge read lane so central can derive private repositories" +domain: infotech +repo: ops-mason +status: proposed +owner: codex +topic_slug: custodian +created: "2026-08-26" +updated: "2026-08-26" +related: + - CUST-ADR-012 + - STATE-WP-0083 +--- + +# Forge read lane so central can derive private repositories + +## Goal + +Give the State Hub read-only access to Forgejo so it can derive projections for +private repositories, and register the lane so `warden route find` answers this +question the next time someone asks it. + +## Why this exists + +`ADR-012` makes the forge the projection source: central clones a repository's +default branch and derives its work records from what Forgejo holds. That works +today because the pod clones anonymously. + +It does not work for private repositories. The first fleet-wide reset +(`STATE-WP-0083-T04`, 2026-08-26) covered 121 repositories and nine failed +identically: + +```text +fatal: could not read Username for 'https://forgejo.coulomb.social' +``` + +`rapp-core-hub`, `rapp-issue-core`, `rapp-openbao`, `rapp-policy-nexus` and five +others are invisible to the hub's derivation entirely. + +This is a limit on the ADR's own premise. *The forge is the projection source* +holds only for repositories central can read, and nothing in the current design +says so. Worse, the failure is indistinguishable from a broken repository: the +pass records an error, not a policy, so "cannot read" and "does not exist" look +the same from the outside. + +## Why ops-mason owns it + +`warden route find` returns no lane for this need. The nearest entry is +`forgejo-admin-api-token` — an operator PAT owned by `railiance-platform` — which +is far more authority than derivation requires and the wrong thing to reuse. + +This repository builds "OpenBao AppRoles, policies, and KV secret paths so +ops-warden always has something real to route to", which is exactly what is +missing. ops-warden issues SSH certificates only and routes everything else; a +Forgejo token is not its to vend. + +## Decide the token's scope and breadth + +```task +id: MASON-WP-0003-T01 +status: todo +priority: high +``` + +Two choices to settle before anything is created, because they determine what +the credential can do if it leaks. + +**Permission.** Derivation performs `git clone --depth 1` and nothing else, so +the token needs repository *read* and no other scope. It must not be able to +push, administer, or read other Forgejo resources. Reusing the existing admin PAT +is explicitly rejected: a projection that only reads should not hold an +identity that can write. + +**Breadth.** Organisation-wide read means new private repositories derive without +further work and no one has to remember this lane exists. A per-repository grant +is tighter but needs maintenance every time a repository is added, and a +forgotten grant reappears as the same silent "cannot read" this workplan exists +to remove. Recommend organisation-wide read, on the grounds that the failure mode +of the narrow option is invisible. + +Acceptance: scope and breadth recorded as a decision with the reasoning, not +just a value. + +## Create the AppRole, policy, and KV path + +```task +id: MASON-WP-0003-T02 +status: todo +priority: high +``` + +Create the read-only Forgejo token, an OpenBao policy granting read on exactly +one KV path, and an AppRole for the State Hub workload to authenticate with. + +The token value never appears in Git, State Hub, a workplan, a log, or a chat +message. This task records *where* the credential lives and *who* may read it — +never what it is. + +Operator-executed. This workplan describes the lane; it does not perform the +creation. + +Acceptance: the KV path exists and holds a working read-only token; the policy +grants read on that path alone; the AppRole authenticates and cannot read +anything else. + +## Register the lane in the routing catalog + +```task +id: MASON-WP-0003-T03 +status: todo +priority: high +``` + +Add an entry so `warden route find "state hub read private repository"` resolves. +Its absence is why this had to be reasoned out from first principles rather than +looked up. + +The entry should name the owner, the subsystem, the KV path, the rotation +method, and state plainly that ops-warden routes but does not execute it. + +Acceptance: `warden route find` returns the lane; `warden route show` gives an +operator enough to act without reading this workplan. + +## Deliver the credential to the pod + +```task +id: MASON-WP-0003-T04 +status: todo +priority: medium +``` + +Make the token available to the `state-hub` deployment as a Kubernetes Secret, +mounted or injected, and referenced by the chart the same way `state-hub-env` +already is. + +It must not be baked into the image, and it must not be committed to the chart. +Rotation must not require a chart change. + +Acceptance: the pod can read the credential; nothing in the repository contains +it; rotating the token does not require a redeploy. + +## Teach the derivation to use it + +```task +id: MASON-WP-0003-T05 +status: todo +priority: medium +``` + +`derive_from_forge()` in `state-hub` clones anonymously. It should use the +credential when present and continue working without it — a hub with no token +must still derive public repositories rather than failing wholesale. + +Credentials must never reach the clone URL in a way that lands in logs or process +listings; use a credential helper or header, not an embedded userinfo URL. + +**Distinguish "cannot read" from "does not exist".** A repository the hub is not +permitted to read must be reported as unreadable, not as a repository whose +records no longer derive. Today the reset treats a failed clone as an error, +which is correct only by accident: if a clone ever returned empty instead of +failing, every record in that repository would be proposed for retirement. That +is the failure that nearly retired `vergabe-teilnahme`, and it must be impossible +here by construction rather than by luck. + +Acceptance: private repositories derive; a hub without the credential still +derives public ones; an unreadable repository is reported as unreadable and never +as retirement work. + +## Confirm the nine + +```task +id: MASON-WP-0003-T06 +status: wait +priority: medium +``` + +Re-run the fleet reset and confirm the nine repositories derive rather than +error. Expect them to arrive with a real diff — quite possibly a large one, since +none has ever been reconciled against its files. + +Treat the first diff for each as review material, not as work to apply. Every +repository examined this way for the first time has produced findings. + +Acceptance: fleet errors fall from nine to zero; each newly readable repository +has its first diff reviewed before anything is applied.