--- id: SECRETS-WP-0003 type: workplan title: "Close out the whynot-design npm publish pilot (real)" domain: infotech repo: secrets-engine status: active owner: codex topic_slug: custodian created: "2026-06-29" updated: "2026-06-29" state_hub_workstream_id: "07ee9cee-3efb-4abc-89a8-a30436d6a601" --- # SECRETS-WP-0003 - Close out the whynot-design npm publish pilot (real) ## Goal Turn the proven MVP chain into a real, no-longer-faked production pilot: replace the local decision fixture with a canonical State Hub decision, provision a real Gitea npm token behind a dedicated bot account so the repo-scope is *enforced* (not just labelled), and perform a real `npm publish` of `@whynot/design` through `secrets-engine exec`. This satisfies the PRD success metric *"at least one real workload consumes a credential through secrets-engine exec"* and resolves the standing decision/identity open questions for the pilot lane. ## Context `SECRETS-WP-0002` delivered the working engine and proved the whole chain against a throwaway OpenBao dev server with a fake token and a `--dry-run` publish. Three things are still stand-ins: - the lane's approval runs on `.decisions/whynot-design-npm-publish.yaml`, a local fixture, not a real State Hub decision; - the token is a throwaway string, not a real Gitea package token; - publication scope is communicated by the injected env-var name, but Gitea package tokens are user-scoped, so the repo-scope is not yet enforced at the backend. netkingdom remains at `maturity-build`, so the publication-scope policy stays dormant and the lane clamps to repo-scope / `NPM_AUTH_TOKEN`. This workplan does not change that gate. ## Design Constraints - No raw token value in Git, State Hub, chat, prompts, workplans, or normal logs. - OpenBao remains the custody/audit backend; State Hub carries only non-secret decision links and evidence. - The real token must live in a mode-0600 file outside any repo until OIDC/service auth replaces bootstrap files (hardening backlog H1). - Every minted token gets a revocation task in `docs/hardening-backlog.md` (H0). ## 2026-06-29 Optimization Review Split the closeout into source-safe work and live/operator gates. Source-safe work can complete in this repo: point the lane at the canonical State Hub decision, keep only a UUID-named offline fallback fixture for demos, document the real publish runbook, provide a non-secret preflight, and hand ops-warden a route pointer. Live work remains gated because it requires Gitea admin/package rights, an operator-minted bot token, OpenBao bootstrap authority, a coordinated `whynot-design` version bump, and a real publish. Existing State Hub evidence for CCR-2026-0001 confirms the corrected approval `e6381a56-6b04-4fd5-b2de-f3ef59cde888` and related OpenBao/OIDC verification, but that CCR path is not the same as this repo's original MVP catalog path, so it is approval context rather than proof that `secrets-engine exec` has already published `@whynot/design`. ## Tasks ## T01 - Record the canonical State Hub decision for the lane ```task id: SECRETS-WP-0003-T01 status: done priority: high state_hub_task_id: "11586d9d-c6bb-4455-8560-32da75cb06d4" ``` 2026-06-29: Reused the canonical approved State Hub decision `e6381a56-6b04-4fd5-b2de-f3ef59cde888`, updated `catalog/whynot-design-npm-publish.yaml` to reference that UUID, and replaced the slug-named local decision fixture with a UUID-named offline fallback only. `decision inspect` resolves from `source: hub` when State Hub is reachable. Record a real State Hub decision approving establishment of the whynot-design npm publish lane, then point `catalog/whynot-design-npm-publish.yaml` `approval.decision_ref` at that decision's UUID. Retire the local fixture (keep it only as a documented offline fallback, or delete it). Acceptance: - `secrets-engine decision inspect ` resolves with `source: hub` and shows the decision approved. - The lane still passes `require_approved` via the hub, not the fixture. - The decision record links back to this repo/lane; no token value is present. ## T02 - Stand up a dedicated Gitea bot account for the repo-scoped grant ```task id: SECRETS-WP-0003-T02 status: wait priority: high state_hub_task_id: "13a34d32-ab4b-4cf5-a1fb-e3e920649a23" ``` 2026-06-29: Added bot-account evidence requirements to `docs/whynot-design-real-publish-closeout.md`. This remains an operator/Gitea admin gate; no repo-side command can create or prove the scoped bot without Gitea admin credentials and package-permission evidence. Create a dedicated Gitea bot account (e.g. `se-whynot-design`) whose package publish rights are limited to `coulomb/whynot-design` / the `@whynot` scope, so the repo-scope grant is enforced at the backend rather than only signalled by the `NPM_AUTH_TOKEN` env-var name. Acceptance: - The bot account can publish `@whynot/design` but cannot publish other orgs' packages; the negative result is documented as Gitea-level evidence. - The catalog `delivery_config.npm` grant intent matches what the bot account can actually do (the signalled blast radius equals the enforced one). - Account creation and its scope are recorded as non-secret evidence. ## T03 - Provision the real npm token without disclosure ```task id: SECRETS-WP-0003-T03 status: wait priority: high state_hub_task_id: "746b5e7f-cc10-43e4-b6d3-7d792d95dfeb" ``` 2026-06-29: Documented the safe apply/provision/verify sequence and added revocation tracking rows for the production OpenBao bootstrap token and whynot-design Gitea bot package token. Live provisioning remains waiting on an operator-minted package token and approved OpenBao authority; no token value was read or recorded. Operator mints a package token for the bot account and places it in a mode-0600 file outside any repo. Provision it with `secrets-engine provision whynot-design-npm-publish --stage prod --field npm_token --from-file `. Acceptance: - Positive verification proves the approved consumer can read the lane; negative verification proves an unrelated token is denied. - No token value appears in Git, State Hub, logs, or chat. - The bootstrap token file is added to `docs/hardening-backlog.md` H0 with an explicit revocation task and TTL. ## T04 - Real `npm publish` of @whynot/design through secrets-engine exec ```task id: SECRETS-WP-0003-T04 status: wait priority: high state_hub_task_id: "36b925c2-0670-4481-95d9-1f23dcc96575" ``` 2026-06-29: Added the real publish runbook and non-secret source-side preflight. A real publish is still waiting on T02/T03 plus a coordinated version bump in the external `whynot-design` repo and operator confirmation of the published package version. Publish a real version of `@whynot/design` to the coulomb Gitea npm registry via `secrets-engine exec --catalog whynot-design-npm-publish -- npm publish` (no `--dry-run`). Coordinate the version bump with the whynot-design repo. Acceptance: - The published version appears in `https://gitea.coulomb.social/api/packages/coulomb/npm/`. - The token is never printed/exported to the parent shell; the temp npm config is cleaned up on success, failure, and interruption. - Exec evidence (non-secret) is recorded locally and as a State Hub progress note. ## T05 - Hand the routing contract to ops-warden (cross-repo) ```task id: SECRETS-WP-0003-T05 status: progress priority: medium state_hub_task_id: "461a7854-6229-4bc1-8d94-f6e2c4e5fa79" ``` 2026-06-29: Updated `docs/ops-warden-routing-contract.md` with the canonical whynot-design pointer payload and sent State Hub message `765a03f0-0b1a-4da4-a244-04de468cadba` to `ops-warden`. Completion remains waiting on ops-warden updating/confirming its own routing catalog so `warden route find "npm publish whynot-design"` resolves here. Coordinate with the ops-warden repo so `warden route find` points npm publish credential needs at secrets-engine, returning the `secrets-engine route` pointer rather than a value. This is a handoff/coordination task; the route catalog entry lives in ops-warden. Acceptance: - `warden route find "npm publish whynot-design"` returns the secrets-engine catalog id and the safe next command. - ops-warden does not request or store the raw token. - The handoff is recorded (State Hub message or progress note) so ownership is clear. ## Exit Criteria - The whynot-design lane is approved by a real State Hub decision, not a fixture. - The real token is provisioned and verified without disclosure, behind a bot account whose enforced scope matches the catalog grant. - A real `@whynot/design` version is published through `secrets-engine exec`. - ops-warden routes npm credential needs to secrets-engine. - Every minted bootstrap token has a revocation task in the hardening backlog.