CUST-WP-0075: catalog entry core-hub-forgejo-source-read (CCR-2026-0031)

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
This commit is contained in:
tegwick 2026-10-03 12:55:08 +02:00
parent 88c22d43c9
commit 2f8387cc2f
5 changed files with 121 additions and 3 deletions

View file

@ -94,14 +94,14 @@ on_apply:
# a register that cannot detect its own staleness is only as good as the last
# re-measure, and this one was stale by eight lanes before the test caught it.
classification_coverage:
measured: "2026-09-28"
measured: "2026-10-03"
attribution: self-measured
signing_targets:
resolved: 0
unknown: 3
not_applicable: 1
routing_lanes:
resolved: 3
resolved: 4
unknown: 20
not_applicable: 15

View file

@ -390,6 +390,45 @@ entries:
- "Use the attended railiance-platform bootstrap to update OpenBao and the coulomb/policy-nexus FORGEJO_SOURCE_TOKEN Actions secret without exposing the value."
- "Pass one exact-commit candidate workflow, then revoke the predecessor PAT and record bounded non-secret evidence in CCR-2026-0014."
- id: core-hub-forgejo-source-read
title: Core Hub repo-manager publisher Forgejo private-source repository read token
# Read-only at Forgejo, but disclosure grants estate-wide private source read for
# org coulomb. ESO is the only consumer (CCR-2026-0031): no operator fetch lane,
# so exec_capable stays false and Warden never proxies a read of this value.
risk: high
workload_ref:
applicability: applicable
rapp_id: rapp-core-hub
name: core-hub
deployable: repository-classification-publisher
fields: [FORGEJO_SOURCE_TOKEN, API_USER, API_BASE_URL, TOKEN_SCOPES, GENERATED_AT] # CCR-2026-0031
need_keywords: [core-hub, core, hub, repo-manager, publisher, forgejo, private, source, repository, read, token, eso, external-secrets, FORGEJO_SOURCE_TOKEN]
owner_repo: railiance-platform
subsystem: OpenBao + External Secrets + Forgejo
warden_executes: false
wiki_ref: wiki/playbooks/core-hub-forgejo-source-read.md#worker-checklist
canon_ref: railiance-platform/credential-change-requests/CCR-2026-0031-core-hub-forgejo-source-read.yaml
reviewed: "2026-10-03"
status: active
delegation:
mode: native
intended_owner: railiance-platform
reviewed: "2026-10-03"
verified: source-read
auth_method: "Kubernetes auth (mount kubernetes) role=external-secrets-core-hub-forgejo-source, bound to external-secrets/external-secrets; ESO delivery only (ClusterSecretStore openbao-core-hub-forgejo-source → ExternalSecret core-hub/repo-manager-forgejo-source)"
path_template: "platform/workloads/core-hub/forgejo-source-read"
policy_ref: "workload-kv-read-core-hub-forgejo-source"
exec_capable: false
lane: secret
rotation:
method: rotate
owner: railiance-platform
automatable: false
steps:
- "Every 180 days or on owner change: mint a replacement PAT for the restricted core-hub-source identity with scope exactly read:repository; retain the predecessor until verification passes."
- "Write the replacement to platform/workloads/core-hub/forgejo-source-read from stdin through the attended railiance-platform bootstrap, then let ESO refresh core-hub/repo-manager-forgejo-source (5m)."
- "Pass make verify-publisher in rapp-core-hub, then revoke the predecessor PAT and record bounded non-secret evidence in CCR-2026-0031."
- id: flex-auth-policy-check
title: Authorization decision — may this actor perform this action
# Returns an authorization decision; no credential flows (WARDEN-WP-0032-T05).

View file

@ -197,6 +197,32 @@ def test_route_find_policy_nexus_source_read_prefers_concrete_lane():
assert matches[0].id == "policy-nexus-forgejo-source-read"
def test_core_hub_source_read_lane_is_eso_only_and_not_resolvable():
"""CCR-2026-0031: ESO is the only consumer, so no operator fetch lane."""
catalog = load_catalog(_repo_catalog())
entry = catalog.get("core-hub-forgejo-source-read")
assert entry is not None and entry.is_active
assert entry.exec_capable is False
assert entry.resolvable is False
assert entry.fetch_command is None
assert entry.lane == "secret"
assert entry.risk == "high"
assert entry.owner_repo == "railiance-platform"
assert entry.path_template == "platform/workloads/core-hub/forgejo-source-read"
assert "role=external-secrets-core-hub-forgejo-source" in entry.auth_method
assert entry.delegation is not None and entry.delegation.mode == "native"
assert entry.canon_ref.endswith("CCR-2026-0031-core-hub-forgejo-source-read.yaml")
def test_route_find_core_hub_source_read_prefers_core_hub_lane():
catalog = load_catalog(_repo_catalog())
matches = catalog.find(
"core hub repo-manager publisher Forgejo private source repository read token",
limit=1,
)
assert matches[0].id == "core-hub-forgejo-source-read"
def test_generic_and_template_lanes_not_resolvable():
catalog = load_catalog(_repo_catalog())
# generic openbao lane has <FIELD>/<path_template>; login lane has <domain>.

View file

@ -12,7 +12,7 @@ ROOT = Path(__file__).resolve().parents[1]
def test_repo_catalog_uses_only_explicit_workload_references():
report = build(ROOT / "registry/routing/catalog.yaml", Path.home())
assert report["ok"] is True
assert len(report["resolved"]) == 3
assert len(report["resolved"]) == 4
assert len(report["unknown"]) == 20
# 15 since 2026-09-21: the layer-declaration route is repository conformance
# guidance, not a workload delivery lane, and the two NetKingdom SSO lanes
@ -25,6 +25,7 @@ def test_repo_catalog_uses_only_explicit_workload_references():
"ops-warden-warden-sign-token",
"issue-core-ingestion-api-key",
"rapp-qonto-keycape-client",
"core-hub-forgejo-source-read", # CCR-2026-0031, 2026-10-03
}

View file

@ -0,0 +1,52 @@
# Core Hub Forgejo source-read token
Date: 2026-10-03
Catalog: `core-hub-forgejo-source-read` (status `active`, `exec_capable: false`, `resolvable: false`)
Owner: `railiance-platform` (OpenBao and credential lifecycle)
This lane carries the dedicated Forgejo PAT that the Core Hub repo-manager
publisher (`rapp-core-hub`, deployable `repository-classification-publisher`)
uses to read private sources of the repository registry. The Forgejo identity
`core-hub-source` is restricted to organization-wide repository-code read in org
`coulomb`, and the PAT scope is exactly `read:repository`. It has no repository
write, package, organization administration, instance administration, Actions,
cluster, or deployment authority.
The authoritative lifecycle and evidence record is
`railiance-platform/credential-change-requests/CCR-2026-0031-core-hub-forgejo-source-read.yaml`
(design: `railiance-platform/docs/credential-lane-designs/core-hub-forgejo-source-read.md`).
It is distinct from `policy-nexus-forgejo-source-read` (CCR-2026-0014); neither
identity nor token is reused across the two lanes.
## Owner-confirmed lane
| Field | Value |
| --- | --- |
| OpenBao path | `platform/workloads/core-hub/forgejo-source-read` |
| Fields | `FORGEJO_SOURCE_TOKEN`, `API_USER`, `API_BASE_URL`, `TOKEN_SCOPES`, `GENERATED_AT` |
| Read policy | `workload-kv-read-core-hub-forgejo-source` |
| Auth | Kubernetes auth role `external-secrets-core-hub-forgejo-source` (bound to `external-secrets/external-secrets`) |
| Delivery | ClusterSecretStore `openbao-core-hub-forgejo-source` → ExternalSecret `core-hub/repo-manager-forgejo-source` → Secret key `token` |
| Forgejo identity | `core-hub-source` |
| Forgejo team | `core-hub-source-readers` |
## Worker checklist
1. There is no operator or agent fetch lane. External Secrets is the only reader,
so `warden access core-hub-forgejo-source-read --fetch/--exec` is not offered
and the fetch-policy pin does not list this lane. Do not request one; if a
legitimate operator read need appears, it goes through a new CCR first.
2. Check delivery health without reading values: ExternalSecret
`core-hub/repo-manager-forgejo-source` Ready, and `make verify-publisher` in
`rapp-core-hub`. Verify OpenBao allow/deny with `bao token capabilities`, never
`bao kv get` (see `catalog-lane-promotion.md`).
3. For rotation (every 180 days or on owner change), deactivation, or compromise,
follow the CCR-2026-0031 lifecycle; `warden rotate-guide core-hub-forgejo-source-read`
prints the rotation steps. A replacement is not active until `make
verify-publisher` passes; revoke the predecessor afterward.
4. Never place the value in argv, chat, Git, State Hub, logs, or a persistent
temporary file. Never substitute the Forgejo admin PAT, a personal token, or
the policy-nexus-source token.