Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
194 lines
6.9 KiB
Markdown
194 lines
6.9 KiB
Markdown
---
|
|
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
|
|
state_hub_workstream_id: "4015b46d-02f1-56ac-853e-87e8542cf0dd"
|
|
---
|
|
|
|
# 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
|
|
state_hub_task_id: "36d26000-ae71-5a58-a563-a07ff5be664f"
|
|
```
|
|
|
|
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
|
|
state_hub_task_id: "68a1c8e4-c12b-550e-962c-06a90ab8c1c2"
|
|
```
|
|
|
|
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
|
|
state_hub_task_id: "e14f0eb3-a920-5623-b4c1-c20858dbb45d"
|
|
```
|
|
|
|
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
|
|
state_hub_task_id: "1b802564-84aa-5934-8923-51b2ad9dd607"
|
|
```
|
|
|
|
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
|
|
state_hub_task_id: "4eeb9744-0d2f-57d8-a063-0e4ed371ac63"
|
|
```
|
|
|
|
`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
|
|
state_hub_task_id: "cbc9c02c-e49a-54c3-91e5-51df238139a6"
|
|
```
|
|
|
|
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.
|