# Core Hub Forgejo source-read lane (CCR-2026-0031) Status: **proposed**, drafted 2026-10-03 under CUST-WP-0075 for `RAPPCOREHUB-WP-0003-T04`. Nothing here is approved, applied or provisioned. No Forgejo, OpenBao or cluster object was created and no owner message other than the CUST-WP-0075 reply was sent. ## Why The repo-manager publisher in namespace `core-hub` reads the 123-entry repository registry (all `coulomb/*`) anonymously. Nine private sources return HTTP 404. T04 forbids the Forgejo admin PAT, personal keys or PATs, and the `policy-nexus-source` token from CCR-2026-0014. This lane gives the publisher its own read-only identity. ## Shape | Item | Value | | --- | --- | | Forgejo user | `core-hub-source` (restricted, non-admin, private; random unrecorded password) | | Forgejo team | `coulomb/core-hub-source-readers`: permission read, all repositories, `repo.code` read, every other unit none, cannot create repos | | PAT | `core-hub-source-read-`, scope exactly `read:repository` | | OpenBao | `platform/workloads/core-hub/forgejo-source-read` fields `FORGEJO_SOURCE_TOKEN`, `API_USER`, `API_BASE_URL`, `TOKEN_SCOPES`, `GENERATED_AT` | | Policy | `workload-kv-read-core-hub-forgejo-source` (`openbao/policies/…hcl`, read on data + metadata of that one path) | | Auth | Kubernetes role `external-secrets-core-hub-forgejo-source`, bound to SA `external-secrets/external-secrets`, TTL 15m | | Delivery | ESO store + ExternalSecret below → Secret `core-hub/repo-manager-forgejo-source` key `token` | | Consumer | rapp-core-hub `publisher.existingSecret: repo-manager-forgejo-source` (already supported by the chart; mounts read-only at `/var/run/secrets/repo-manager/forgejo/token`) | | Rotation | every 180 days or owner change; Forgejo PATs have no server-side expiry | | Front door | ops-warden `core-hub-forgejo-source-read`, follow-up after approval (see below) | Naming follows the CCR-2026-0014 precedent (`-source`, `-source-readers`). repo-manager has no service-user naming canon. Its outstanding `identity-canon` correction is a registry/Forgejo identity mismatch for one repository. It blocks the 123/0 acceptance, not this credential or its name. ## Draft manifests (land in `argocd/platform-addons/openbao-secretstore/` only after metadata apply) ```yaml # CCR-2026-0031. Do not apply until approval and confirm-binding. apiVersion: external-secrets.io/v1 kind: ClusterSecretStore metadata: name: openbao-core-hub-forgejo-source labels: app.kubernetes.io/part-of: railiance-gitops railiance-platform/component: external-secrets app.kubernetes.io/name: core-hub spec: provider: vault: server: http://openbao.openbao.svc:8200 path: platform version: v2 auth: kubernetes: mountPath: kubernetes role: external-secrets-core-hub-forgejo-source serviceAccountRef: name: external-secrets namespace: external-secrets conditions: - namespaces: - core-hub --- apiVersion: external-secrets.io/v1 kind: ExternalSecret metadata: name: repo-manager-forgejo-source namespace: core-hub spec: refreshInterval: 5m secretStoreRef: kind: ClusterSecretStore name: openbao-core-hub-forgejo-source target: # Explicit target metadata prevents ESO copying source last-applied annotations. template: metadata: {} name: repo-manager-forgejo-source creationPolicy: Owner deletionPolicy: Retain data: - secretKey: token remoteRef: key: workloads/core-hub/forgejo-source-read property: FORGEJO_SOURCE_TOKEN ``` ## Attended sequence (after approval) 1. Reviewers approve and confirm the binding (human acts, recorded by the CCR tooling): `credential-change.py approve CCR-2026-0031 …` and `credential-change.py confirm-binding CCR-2026-0031 …`. 2. Founder, in their own terminal (child is silent; read the diagnostic file on failure, never the output): `warden access openbao-platform-admin-login --exec -- scripts/openbao-bootstrap-core-hub-source.sh`. This runs the delegated metadata apply (policy + auth role), then `scripts/provision-core-hub-forgejo-source.py`, which gets the Forgejo admin token only through `warden access forgejo-admin-api-token --exec`, mints the PAT, verifies scope, private-repo read and denials, writes the value to OpenBao from stdin, reads it back for equality, and records non-secret evidence. Re-running when the PAT and the OpenBao value both exist is a no-op; a half state fails closed and points to rotation. Failure diagnostics: `/tmp/core-hub-source-bootstrap-diagnostic.json` (stage + bounded reason only). 3. Commit the two manifests above and let Argo sync; check presence only with `scripts/secret_annotation_maintenance.py` through the authorized admin path. 4. rapp-core-hub sets `publisher.existingSecret`, deploys, runs `make verify-publisher` (expects 123/0 once repo-manager ships the identity-canon correction), then enables `connectCandidate`. 5. Add the ops-warden catalog entry `core-hub-forgejo-source-read` (risk high, owner railiance-platform, path above, rotation steps from the CCR) and move the CCR to `verified`/`active` with evidence. Offline tests: `python3 -m unittest tests/test_core_hub_forgejo_source_provision.py`.