railiance-platform/docs/credential-lane-designs/core-hub-forgejo-source-read.md
codex 401765f184
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
CUST-WP-0075: dedicated core-hub Forgejo read identity CCR draft
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
2026-10-03 08:27:56 +02:00

5.3 KiB

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-<UTC timestamp>, 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 (<workload>-source, <workload>-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)

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