Policy workload-kv-read-state-hub-forge-derivation and Kubernetes auth role state-hub-forge-derivation, verified both directions through a 2-minute test token that was 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. Kubernetes auth replaces the approved AppRole. The plan's §2 survey was written from disk with no OpenBao session and could not see that kubernetes/ auth is enabled on this cluster; the plan's own phase-4 instruction to re-verify against live state is what surfaced it. Ruled by the founder at phase 4. No static credential is created, so nothing has to be delivered into the cluster or rotated. The live survey also re-checked reuse: workload-kv-read-agent-harness- forgejo grants one repository deploy key, not organisation-wide read, so §2's rejection of reuse stands. ops-mason handled no secret value. The KV path does not exist until paste_once_provision writes the token. 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
198 lines
8 KiB
Markdown
198 lines
8 KiB
Markdown
---
|
||
id: MASON-WP-0003
|
||
type: workplan
|
||
title: "Forge read lane so central can derive private repositories"
|
||
domain: infotech
|
||
repo: ops-mason
|
||
status: active
|
||
owner: codex
|
||
topic_slug: custodian
|
||
created: "2026-08-26"
|
||
updated: "2026-08-26"
|
||
related:
|
||
- CUST-ADR-012
|
||
- STATE-WP-0083
|
||
- STATE-WP-0084
|
||
state_hub_workstream_id: "4015b46d-02f1-56ac-853e-87e8542cf0dd"
|
||
---
|
||
|
||
# Forge read lane so central can derive private repositories
|
||
|
||
## Goal
|
||
|
||
Build the credential lane that lets the State Hub read private repositories
|
||
from Forgejo, and register it so `warden route find` answers this question the
|
||
next time someone asks it.
|
||
|
||
This workplan builds the lane. It does not consume it — see the handoff below.
|
||
|
||
## 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.
|
||
|
||
## 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.
|
||
|
||
## What ops-mason does not own
|
||
|
||
Three parts of the end-to-end fix belong to other repositories and are tracked
|
||
in `state-hub/STATE-WP-0084`:
|
||
|
||
- mounting the credential into the `state-hub` deployment;
|
||
- teaching `derive_from_forge()` to use it, and to distinguish "cannot read"
|
||
from "does not exist";
|
||
- re-running the fleet reset and reviewing the nine first diffs.
|
||
|
||
`STATE-WP-0084-T01` (the unreadable-vs-missing distinction) is not merely
|
||
downstream: the recommendation in this lane's construction plan depends on it,
|
||
because it is what makes a narrow grant fail visibly. It is worth landing with
|
||
or without this credential.
|
||
|
||
## Run the construction plan through the decision gate
|
||
|
||
```task
|
||
id: MASON-WP-0003-T01
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "36d26000-ae71-5a58-a563-a07ff5be664f"
|
||
```
|
||
|
||
`plans/state-hub-forge-derivation-read.md` holds phases 1–3: the demand, the
|
||
existing-structure survey (including why `forgejo-admin-api-token` is rejected
|
||
rather than reused), the proposed AppRole/policy/KV path, the review pass, and
|
||
the executive summary.
|
||
|
||
Three things need deciding, and they determine what the credential can do if it
|
||
leaks:
|
||
|
||
1. **Approve, reject, or send back to phase 1.**
|
||
2. **Breadth** — organisation-wide repository read, or per-repository. The plan
|
||
recommends organisation-wide *contingent on `STATE-WP-0084-T01`*, and argues
|
||
the counter-case: an organisation-wide token that leaks reads every private
|
||
repository in the organisation.
|
||
3. **Rotation** — accept build-phase posture (no scheduled `secret_id` expiry),
|
||
or require rotation now.
|
||
|
||
Permission is not in question: derivation performs `git clone --depth 1` and
|
||
nothing else, so the token gets repository *read* and no other scope.
|
||
|
||
Acceptance: the plan reaches `status: reviewed`, the founder decision is
|
||
recorded with its reasoning rather than as a bare value, and the plan carries
|
||
`approved_by`/`approved_at`.
|
||
|
||
**Done (2026-08-26).** Approved by Bernd Worsch, breadth **organisation-wide
|
||
repository read**. The §4 contingency was satisfied first: `STATE-WP-0084-T01`
|
||
landed 2026-08-26, so a repository central may not read now reports as
|
||
unreadable and a source that produced no records cannot retire anything even
|
||
when retirement is acknowledged — which is what makes a missing grant visible
|
||
and, in turn, what the breadth argument rested on. Rotation was not separately
|
||
ruled on; build-phase posture stands as proposed. Reasoning in
|
||
`plans/state-hub-forge-derivation-read.md` §6.
|
||
|
||
## Build the AppRole, policy, and KV path structure
|
||
|
||
```task
|
||
id: MASON-WP-0003-T02
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "68a1c8e4-c12b-550e-962c-06a90ab8c1c2"
|
||
```
|
||
|
||
Phase 4, after T01 approval only. Create the OpenBao policy granting read on
|
||
exactly one KV path, the KV path *structure*, and the AppRole the `state-hub`
|
||
workload authenticates with.
|
||
|
||
**ops-mason does not touch the token value, even transiently.** The forge owner
|
||
mints the read-only Forgejo token; it reaches the KV path through ops-warden's
|
||
existing `paste_once_provision` desk. This task records *where* the credential
|
||
lives and *who* may read it — never what it is. The value never appears in Git,
|
||
State Hub, a workplan, a log, or a chat message.
|
||
|
||
Acceptance: the policy grants read on that path alone; the AppRole
|
||
authenticates and can read nothing else; the KV path exists and the desk has
|
||
delivered a working token into it, confirmed by the consumer rather than by
|
||
reading the value here. Recorded in `audit/build-log.jsonl` against the
|
||
approved plan.
|
||
|
||
**Done (2026-08-27).** Policy `workload-kv-read-state-hub-forge-derivation` and
|
||
Kubernetes auth role `state-hub-forge-derivation` created and verified; see
|
||
`plans/state-hub-forge-derivation-read.md` §7 and `audit/build-log.jsonl`.
|
||
|
||
**Kubernetes auth replaces the approved AppRole**, ruled at phase 4 after the
|
||
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.
|
||
|
||
## Register the lane in the routing catalog
|
||
|
||
```task
|
||
id: MASON-WP-0003-T03
|
||
status: progress
|
||
priority: high
|
||
state_hub_task_id: "e14f0eb3-a920-5623-b4c1-c20858dbb45d"
|
||
```
|
||
|
||
Propose a pointer-only entry (`warden_executes: false`, no authored `steps`,
|
||
`status: draft`) 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 names the owner, the subsystem, the KV path, the rotation method, and
|
||
states plainly that ops-warden routes but does not execute it. Normal git
|
||
contribution to `ops-warden`, not a live API call.
|
||
|
||
Acceptance: `warden route find` returns the lane; `warden route show` gives an
|
||
operator enough to act without reading this workplan.
|
||
|
||
**Drafted 2026-08-26**, awaiting contribution to `ops-warden` (branch
|
||
`mason/state-hub-forge-derivation-read`, commit `3a4333d`). Entry
|
||
`state-hub-forge-derivation-read`: pointer-only, `warden_executes: false`,
|
||
`status: draft`, `risk: high` — graded on breadth rather than write authority,
|
||
since the token is read-only but organisation-wide. Playbook at
|
||
`wiki/playbooks/state-hub-forge-derivation-read.md`, whose verification section
|
||
leads with the *negative* check: the AppRole must be denied on
|
||
`platform/workloads/forgejo/forgejo-admin`, because not being able to do what
|
||
the admin lane can is the entire argument for building this one.
|
||
|
||
`registry/generated/high-risk-data-paths.yaml` regenerated (21 → 24 lanes); it
|
||
had been stale since 2026-08-23, so the regeneration also picks up two
|
||
unrelated lanes. Promote the entry to `active` once T02 has built the structure
|
||
and the negative check passes.
|
||
|
||
## Handoff
|
||
|
||
Once T02 and T03 are done, notify `state-hub` so `STATE-WP-0084-T02` can
|
||
unblock. `STATE-WP-0084-T01` does not wait on this workplan.
|