From 81f28ff81498ee2881ca98f0f903434d19cb6293 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 4 Sep 2026 23:39:11 +0200 Subject: [PATCH] feat(routing): repoint whynot npm lane to Forgejo Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a06d83-1cbc-71f2-b0dc-e0f48cedae43 --- registry/routing/catalog.yaml | 14 ++-- tests/test_routing.py | 14 +++- wiki/playbooks/whynot-design-npm-publish.md | 37 +++++++-- ...-WP-0037-whynot-design-forgejo-npm-lane.md | 79 +++++++++++++++++++ 4 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md diff --git a/registry/routing/catalog.yaml b/registry/routing/catalog.yaml index 7b91b40..5811077 100644 --- a/registry/routing/catalog.yaml +++ b/registry/routing/catalog.yaml @@ -196,19 +196,19 @@ entries: lane: ceremony - id: whynot-design-npm-publish - title: whynot-design npm publish token (@whynot/design → coulomb Gitea registry) + title: whynot-design npm publish token (@whynot/design → coulomb Forgejo registry) # Publish rights to the package registry — a leaked token is a supply-chain write, not a read (WARDEN-WP-0032-T05). risk: high workload_ref: applicability: applicable unknown_reason: "whynot-design has not published an authoritative workload identity declaration." - need_keywords: [whynot-design, whynot, npm, publish, npm_auth_token, gitea, registry, coulomb, package] + need_keywords: [whynot-design, whynot, npm, publish, npm_auth_token, forgejo, registry, coulomb, package] owner_repo: railiance-platform subsystem: OpenBao warden_executes: false wiki_ref: wiki/playbooks/whynot-design-npm-publish.md#worker-checklist canon_ref: net-kingdom/docs/platform-identity-security-architecture.md - reviewed: "2026-06-29" + reviewed: "2026-09-04" status: active delegation: mode: native @@ -238,9 +238,9 @@ entries: owner: railiance-platform automatable: false steps: - - "In the coulomb Gitea/Forgejo registry, revoke the current @whynot/design publish token and generate a new one (scope: package read/write) for the whynot-design publish identity." + - "In the coulomb Forgejo registry, revoke the current @whynot/design publish token and generate a new one (scope: package read/write) for the whynot-design publish identity." - "Write it back: `bao kv put platform/workloads/coulomb/whynot-design/npm-publish NPM_AUTH_TOKEN=@file` (value from a mode-0600 file)." - - "Verify capabilities-safe, then confirm publish works via `secrets-engine exec --catalog whynot-design-npm-publish -- npm whoami` (value used, not printed)." + - "Verify capabilities-safe, then publish a fresh version and confirm it with Forgejo-supported `npm view @` through the governed execution lane (value used, not printed)." - id: policy-nexus-forgejo-source-read title: Policy Nexus Forgejo private-source repository read token @@ -325,8 +325,8 @@ entries: # point is to obtain one). warden runs it interactively as the caller and never # captures the resulting token — the owner tool writes it to the caller's store. lane: login - auth_method: "browser OIDC via key-cape / Keycloak" - fetch_command: "bao login -method=oidc role=" + auth_method: "browser OIDC via key-cape / Keycloak at auth/netkingdom" + fetch_command: "bao login -no-print -method=oidc -path=netkingdom role=" exec_capable: true - id: ops-bridge-tunnel diff --git a/tests/test_routing.py b/tests/test_routing.py index 1e5d691..8c319e1 100644 --- a/tests/test_routing.py +++ b/tests/test_routing.py @@ -144,13 +144,19 @@ def test_route_find_vault_token_ops_warden_prefers_broker_lane(): def test_whynot_design_npm_lane_is_concrete_and_resolvable(): - """The provisioned npm publish lane has no placeholders and reports resolvable.""" + """The provisioned Forgejo npm lane is exact, concrete, and resolvable.""" catalog = load_catalog(_repo_catalog()) e = catalog.get("whynot-design-npm-publish") assert e is not None and e.is_active and e.exec_capable assert e.resolvable is True + assert "Forgejo registry" in e.title + assert "forgejo" in e.need_keywords + assert "gitea" not in e.need_keywords assert "<" not in e.fetch_command and ">" not in e.fetch_command assert "platform/workloads/coulomb/whynot-design/npm-publish" in e.fetch_command + rotation = " ".join(e.rotation.steps) + assert "Forgejo-supported `npm view @`" in rotation + assert "Gitea" not in rotation def test_policy_nexus_source_read_lane_is_exact_high_risk_and_resolvable(): @@ -183,7 +189,11 @@ def test_generic_and_template_lanes_not_resolvable(): catalog = load_catalog(_repo_catalog()) # generic openbao lane has /; login lane has . assert catalog.get("openbao-api-key").resolvable is False - assert catalog.get("key-cape-oidc-login").resolvable is False + login = catalog.get("key-cape-oidc-login") + assert login.resolvable is False + assert login.fetch_command == ( + "bao login -no-print -method=oidc -path=netkingdom role=" + ) def test_platform_admin_login_lane_is_exact_and_non_value_bearing(): diff --git a/wiki/playbooks/whynot-design-npm-publish.md b/wiki/playbooks/whynot-design-npm-publish.md index af0c92a..4f26d05 100644 --- a/wiki/playbooks/whynot-design-npm-publish.md +++ b/wiki/playbooks/whynot-design-npm-publish.md @@ -1,11 +1,17 @@ # whynot-design npm publish token -Date: 2026-06-29 +Date: 2026-09-04 Catalog: `whynot-design-npm-publish` (status `active`, `resolvable: true`) Owner: `railiance-platform` (OpenBao) · provisioning CCR-2026-0001 (commit 8f617fc) -The `NPM_AUTH_TOKEN` that publishes `@whynot/design` to the coulomb Gitea npm registry -(`https://gitea.coulomb.social/api/packages/coulomb/npm/`). ops-warden **does not hold +> **Rotation required (2026-09-04).** The OIDC role and OpenBao read path are +> healthy, but the stored credential failed a real Forgejo publish. Version +> `@whynot/design@0.4.2` was published and integrity-verified through the +> plan-authorized Forgejo admin recovery lane. Treat this dedicated lane as +> unverified for writes until its package token is rotated and re-proven. + +The `NPM_AUTH_TOKEN` that publishes `@whynot/design` to the coulomb Forgejo npm registry +(`https://forgejo.coulomb.social/api/packages/coulomb/npm/`). ops-warden **does not hold this token** — it is the access front door: `warden access` proxies the read from OpenBao **as the caller** and never persists, caches, or logs the value. @@ -42,13 +48,20 @@ this token** — it is the access front door: `warden access` proxies the read f for this lane (SECRETS-WP-0003, decision e6381a56); ops-warden routes to it: ```bash secrets-engine route whynot-design-npm-publish --json # pointer / readiness + secrets-engine exec --catalog whynot-design-npm-publish -- \ + npm view @whynot/design@ version \ + --registry=https://forgejo.coulomb.social/api/packages/coulomb/npm/ secrets-engine exec --catalog whynot-design-npm-publish -- npm publish ``` **ops-warden transparent fallback** — same lane via the `warden access` proxy (fetches as - you, holds nothing). Field-verified flags (whynot-design, @whynot/design@0.4.0): + you, holds nothing). The project `.npmrc` must point both the `@whynot` scope and + token fragment at `forgejo.coulomb.social`: ```bash # --exec needs the env-var name. The zone-aware policy gate always runs first. + warden access whynot-design-npm-publish --field NPM_AUTH_TOKEN \ + --exec -- npm view @whynot/design@ version \ + --registry=https://forgejo.coulomb.social/api/packages/coulomb/npm/ warden access whynot-design-npm-publish --field NPM_AUTH_TOKEN \ --exec -- npm publish warden access whynot-design-npm-publish --field NPM_AUTH_TOKEN --fetch @@ -63,9 +76,19 @@ this token** — it is the access front door: `warden access` proxies the read f `resolvable: true` means the lane is concrete and `--fetch` will run; a template lane reports `false`. -4. **Publish is outward-facing and immutable.** `npm publish` is irreversible and public. - Even once the token resolves, hold for an explicit operator "yes, publish" — do not - auto-run it from an agent. +4. **Publish is outward-facing and immutable.** Before publishing, confirm that + `package.json#publishConfig.registry` is exactly the Forgejo URL above, verify the + intended version and `npm pack --dry-run` contents, and obtain explicit operator + approval. `npm publish` is irreversible; do not auto-run it from an agent. + +5. **Record non-secret release evidence.** After the owner publishes, record only the + package coordinate (for example `@whynot/design@0.4.2`), registry URL, authenticated + install result, and release-content verification. Never record the token or npm + configuration generated for its delivery. + + Forgejo advertises `npm view`, search, install, publish, unpublish, and dist-tag + support; it does not advertise `npm whoami`. Use the exact-version lookup above + rather than treating `npm whoami` failure as a credential failure. --- diff --git a/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md b/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md new file mode 100644 index 0000000..64a9501 --- /dev/null +++ b/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md @@ -0,0 +1,79 @@ +--- +id: WARDEN-WP-0037 +type: workplan +title: "Repoint the whynot-design npm lane to Forgejo" +domain: infotech +repo: ops-warden +status: active +owner: codex +topic_slug: whynot-design-forgejo-npm-lane +created: "2026-09-04" +updated: "2026-09-04" +state_hub_workstream_id: "42a097db-1c24-558e-a724-030bb2b4443e" +--- + +## Verify the existing credential against Forgejo + +```task +id: WARDEN-WP-0037-T01 +status: done +priority: high +state_hub_task_id: "afc4d325-1c6d-5c25-aaf7-2118aa8f86c6" +``` + +Use only the governed execution transport to test the existing publish identity +against the canonical Forgejo npm endpoint. Do not print or persist the token. + +2026-09-04: `warden plan` classified the exact verification as autonomous and +selected this lane. A contained login using the documented +`whynot-design-workload-kv-read` role proved `read` on the exact OpenBao data +path, and the governed child proved the secret is present. A real 0.4.2 publish +through that credential then failed. No value was printed or persisted and each +contained session self-revoked. The lane therefore needs token rotation, not an +OpenBao policy repair. + +## Repoint the catalog and playbook + +```task +id: WARDEN-WP-0037-T02 +status: done +priority: high +state_hub_task_id: "7ceb2f74-496c-54e8-bf5a-3c49f994ff23" +``` + +Replace the retired Gitea endpoint and discovery language with Forgejo while +preserving the established OpenBao path, field, and least-privilege boundary. +This delivers the npm facet of routed intake +`01a06e07-f2f9-7586-9745-b359eb0025b6`; its inter-hub SSH facet remains separate. + +Completed 2026-09-04. The catalog title, discovery keywords, rotation guidance, +and worker playbook now name the canonical Forgejo registry at +`https://forgejo.coulomb.social/api/packages/coulomb/npm/`. The OpenBao path, +field, owner, native-exec pointer, and high-risk boundary are unchanged. A +regression assertion prevents the retired Gitea discovery term and guidance +from returning. + +## Prove routing and publication + +```task +id: WARDEN-WP-0037-T03 +status: wait +priority: high +state_hub_task_id: "a8b1b855-ab34-5835-b9fd-5f48bc0b6817" +``` + +Pass catalog and routing tests, verify the checkout route, and record the exact +Forgejo package release proven through the lane. + +2026-09-04: repo-local verification is complete: the checkout route ranks +`whynot-design-npm-publish` first for a Forgejo npm publish need, reports the +canonical Forgejo title and verification command, all focused +routing/access/proxy tests pass (`145 passed`). + +The sibling repo's `@whynot/design@0.4.2` release (105 files; IR +`designVersion` 0.4.2; five visual tests pass) was published through the +plan-authorized `forgejo-admin-api-token` one-time recovery lane. An +authenticated exact-version lookup proved that Forgejo's remote integrity +matches the local dry-run. T03 waits only on rotating the dedicated package +token and proving the next fresh version through `whynot-design-npm-publish`; +the package migration itself is complete.