diff --git a/registry/routing/catalog.yaml b/registry/routing/catalog.yaml index 339eecf..a45829f 100644 --- a/registry/routing/catalog.yaml +++ b/registry/routing/catalog.yaml @@ -216,21 +216,25 @@ entries: - id: reuse-surface-hub-write-token title: reuse-surface federation hub write bearer token - need_keywords: [reuse-surface, reuse_surface, hub, register, federation, write, token, bearer, REUSE_SURFACE_TOKEN, reuse.coulomb.social] - owner_repo: reuse-surface - subsystem: reuse-surface federation hub + need_keywords: [reuse-surface, reuse_surface, hub, register, federation, write, token, bearer, REUSE_SURFACE_TOKEN, REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET, reuse.coulomb.social] + owner_repo: railiance-platform + subsystem: OpenBao + reuse-surface warden_executes: false wiki_ref: wiki/playbooks/reuse-surface-hub-write-token.md#worker-checklist canon_ref: reuse-surface/specs/FederationHubAPI.md reviewed: "2026-07-07" status: active - # Concrete, owner-confirmed lane — REUSE-WP-0011 / RAILIANCE-WP-0007 (hub live - # 2026-06-15): token is the cluster Secret reuse-surface-env on Railiance01, - # not OpenBao. warden access proxies kubectl as the caller and never holds the value. - auth_method: "kubectl with Railiance01 kubeconfig (~/.kube/config-hosteurope)" - path_template: "reuse/reuse-surface-env" - fetch_command: "kubectl --kubeconfig ~/.kube/config-hosteurope get secret reuse-surface-env -n reuse -o jsonpath='{.data.REUSE_SURFACE_TOKEN}' | base64 -d" + # Concrete, owner-confirmed lane — railiance-platform CCR-2026-0005 / RAILIANCE-WP-0011 + # (promoted 2026-07-07): policy workload-kv-read-reuse-surface-runtime; ExternalSecret + # reuse/reuse-surface-runtime SecretSynced to reuse-surface-env on Railiance01; + # positive + negative access verified. Production consumer is ESO; warden access + # proxies reads as the caller and never holds the value. + auth_method: "caller's own OpenBao token (operator OIDC via key-cape, or a token carrying workload-kv-read-reuse-surface-runtime)" + path_template: "platform/workloads/reuse/reuse-surface/runtime-secrets" + fetch_command: "bao kv get -field=REUSE_SURFACE_TOKEN platform/workloads/reuse/reuse-surface/runtime-secrets" + policy_ref: "flex-auth check secret.read:reuse" exec_capable: true + resolvable: true lane: secret - id: openrouter-llm-connect diff --git a/tests/test_proxy.py b/tests/test_proxy.py index 5909fc3..cfc356e 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -64,16 +64,16 @@ def test_resolve_refuses_non_exec_capable(): resolve_fetch_command(_entry(exec_capable=False, fetch_command=None)) -def test_resolve_piped_fetch_uses_shell_cmd(): +def test_resolve_bao_fetch_uses_argv(): from warden.routing import load_catalog catalog = load_catalog(Path(__file__).resolve().parents[1] / "registry" / "routing" / "catalog.yaml") entry = catalog.get("reuse-surface-hub-write-token") resolved = resolve_fetch_command(entry) - assert resolved.argv is None - assert resolved.shell_cmd is not None - assert "| base64 -d" in resolved.shell_cmd - assert "reuse-surface-env" in resolved.shell_cmd + assert resolved.argv is not None + assert resolved.shell_cmd is None + assert resolved.argv[0] == "bao" + assert "platform/workloads/reuse/reuse-surface/runtime-secrets" in resolved.argv # --- G2: transit-only fetch (inherited stdout) ----------------------------- diff --git a/tests/test_routing.py b/tests/test_routing.py index f75ed48..9b96520 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -288,8 +288,8 @@ def test_reuse_surface_hub_write_token_lane_is_resolvable(): e = catalog.get("reuse-surface-hub-write-token") assert e is not None and e.is_active and e.exec_capable assert e.resolvable is True - assert e.owner_repo == "reuse-surface" - assert "reuse-surface-env" in e.fetch_command + assert e.owner_repo == "railiance-platform" + assert "platform/workloads/reuse/reuse-surface/runtime-secrets" in e.fetch_command def test_find_object_storage_sts(): diff --git a/wiki/CredentialRouting.md b/wiki/CredentialRouting.md index 1f5f271..dc35d6c 100644 --- a/wiki/CredentialRouting.md +++ b/wiki/CredentialRouting.md @@ -96,7 +96,7 @@ run the owner's tool as the caller and preserve owner custody. | `inter-hub-bootstrap-ssh` | "Inter-Hub bootstrap SSH envelope — attended vs unattended branches" | See `wiki/InterHubBootstrapAccessLane.md` | | `issue-core-ingestion-api-key` | "railiance-platform OpenBao KV + ESO deliver `ISSUE_CORE_API_KEY` — here is the path" | ESO consumes in-cluster; `warden access issue-core-ingestion-api-key --fetch ISSUE_CORE_API_KEY` as yourself | | `openrouter-llm-connect` | "railiance-platform OpenBao KV + ESO deliver `OPENROUTER_API_KEY` to activity-core" | ESO consumes in-cluster; `warden access openrouter-llm-connect --fetch OPENROUTER_API_KEY` as yourself | -| `reuse-surface-hub-write-token` | "reuse-surface hub write bearer — K8s secret `reuse-surface-env` on Railiance01" | `kubectl` from `~/.kube/config-hosteurope`, or `warden access reuse-surface-hub-write-token --fetch` as yourself | +| `reuse-surface-hub-write-token` | "railiance-platform OpenBao KV + ESO deliver `REUSE_SURFACE_TOKEN` to reuse-surface" | ESO consumes in-cluster; `warden access reuse-surface-hub-write-token --fetch` as yourself | Promotion criteria: `wiki/playbooks/catalog-lane-promotion.md`. diff --git a/wiki/playbooks/reuse-surface-hub-write-token.md b/wiki/playbooks/reuse-surface-hub-write-token.md index 96843c4..18cf997 100644 --- a/wiki/playbooks/reuse-surface-hub-write-token.md +++ b/wiki/playbooks/reuse-surface-hub-write-token.md @@ -1,13 +1,13 @@ -# reuse-surface Hub Write Token +# reuse-surface Hub Write Token — OpenBao Custody -Date: 2026-07-07 -Catalog: `reuse-surface-hub-write-token` (status `active`, `resolvable: true`) -Owner: `reuse-surface` (service) · deploy custody `railiance-apps` (K8s secret) +Date: 2026-07-07 (promoted active 2026-07-07) +Workplan: RAILIANCE-WP-0011-T03 · CCR-2026-0005 +Catalog: `reuse-surface-hub-write-token` (**active** — path live, ESO delivering) Bearer token for authenticated writes to the production federation hub at `https://reuse.coulomb.social` (`POST /v1/repos`, `reuse-surface hub register`). -ops-warden **does not hold this token** — it is a pointer lane to the cluster -secret that backs the hub Deployment. +ops-warden does not vend this token — custody belongs to `railiance-platform` +(OpenBao) and the `reuse-surface` workload via External Secrets. --- @@ -15,72 +15,76 @@ secret that backs the hub Deployment. | Field | Value | | --- | --- | -| Cluster | Railiance01 (`92.205.62.239`) | -| Namespace | `reuse` | -| Secret | `reuse-surface-env` | -| Field | `REUSE_SURFACE_TOKEN` | -| Kubeconfig | `~/.kube/config-hosteurope` | +| OpenBao server | `https://bao.coulomb.social` (coulombcore) | +| KV path | `platform/workloads/reuse/reuse-surface/runtime-secrets` | +| Hub write field | `REUSE_SURFACE_TOKEN` | +| Webhook HMAC field | `REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET` | +| Read policy | `workload-kv-read-reuse-surface-runtime` | +| ESO delivery | `ExternalSecret reuse/reuse-surface-runtime` → `reuse-surface-env` (Railiance01) | | Deploy runbook | `railiance-apps/docs/reuse-surface-on-railiance01.md` | | Hub API spec | `reuse-surface/specs/FederationHubAPI.md` | -This is **not** an OpenBao KV path. The token is generated at deploy time and -stored only in the Kubernetes Secret consumed by the `reuse-surface` workload. +**Promotion gate (met 2026-07-07):** path seeded, `ExternalSecret reuse/reuse-surface-runtime` +`SecretSynced`, positive hub + webhook verification and negative default-policy denial +recorded in CCR-2026-0005. -### Related key in the same Secret +### Break-glass (cluster read) -| Field | Purpose | -| --- | --- | -| `REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET` | HMAC for `POST /v1/webhooks/forgejo`; must match the org webhook on Forgejo | - -Fetch (same kubectl lane — never paste into chat): +If OpenBao is unreachable, operators with Railiance01 kubeconfig may read the +materialized Secret (ESO cache): ```bash kubectl --kubeconfig ~/.kube/config-hosteurope get secret reuse-surface-env -n reuse \ - -o jsonpath='{.data.REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET}' | base64 -d + -o jsonpath='{.data.REUSE_SURFACE_TOKEN}' | base64 -d ``` -Forgejo org webhook rollout: `railiance-apps` `make reuse-forgejo-webhook` -(runbook `docs/reuse-surface-on-railiance01.md#forgejo-org-webhook`). - -Planned OpenBao migration: **RAILIANCE-WP-0011** (`railiance-platform`). +Never paste values into chat, State Hub, workplans, or Git. --- ## Worker checklist -1. **Confirm kubeconfig reachability** (you act as yourself; ops-warden adds no credential): +1. **Confirm OpenBao reachability** (you act as yourself; ops-warden adds no credential): ```bash - kubectl --kubeconfig ~/.kube/config-hosteurope get secret reuse-surface-env -n reuse + bao kv metadata get platform/workloads/reuse/reuse-surface/runtime-secrets ``` -2. **Export for a shell session** (value streams to your terminal — never paste into chat): +2. **Export hub write token for a shell session** (streams to your terminal): ```bash export REUSE_SURFACE_URL=https://reuse.coulomb.social export REUSE_SURFACE_TOKEN=$( - kubectl --kubeconfig ~/.kube/config-hosteurope get secret reuse-surface-env -n reuse \ - -o jsonpath='{.data.REUSE_SURFACE_TOKEN}' | base64 -d + bao kv get -field=REUSE_SURFACE_TOKEN \ + platform/workloads/reuse/reuse-surface/runtime-secrets ) ``` -3. **Or proxy via warden access** (same kubectl command, audited metadata only): +3. **Or proxy via warden access** (same `bao kv get`, audited metadata only): ```bash warden route show reuse-surface-hub-write-token --json warden access reuse-surface-hub-write-token --no-policy --fetch ``` -4. **Register a repo** after publish-check passes: +4. **Webhook HMAC** (same path, second field — must match Forgejo org webhook): + ```bash + bao kv get -field=REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET \ + platform/workloads/reuse/reuse-surface/runtime-secrets + ``` + After rotation: `railiance-apps` `make reuse-forgejo-webhook`. + +5. **Register a repo** after publish-check passes: ```bash reuse-surface hub status reuse-surface hub register --repo \ - --url \ + --url \ --domain ``` -5. **Verify federated index** picked up the new source: +6. **Verify federated index** picked up the new source: ```bash curl -fsS "$REUSE_SURFACE_URL/v1/federated" | jq '.sources | map(.repo) | index("")' ``` -Never commit the token, paste it into State Hub or agent chat, or store it in a -workplan. Rotation: regenerate the secret on-cluster and roll the Deployment -(`reuse-surface/docs/deploy/reuse-kubernetes.md`). \ No newline at end of file +Rotation: update fields in OpenBao, wait for ESO refresh (`make reuse-runtime-es-status`), +roll `deployment/reuse-surface`, and re-run `make reuse-forgejo-webhook` when the +webhook HMAC changes. Lifecycle: +`railiance-platform/docs/credential-lane-lifecycle-runbook.md` (lane entry pending T04). \ No newline at end of file