ops-warden/wiki/playbooks/whynot-design-npm-publish.md
tegwick baf53602ca Revert the npm field, re-measure coverage, and hold the layer divergence
Five inbox items worked, none of which changed a credential value or moved a
secret.

whynot-design-npm-publish: field reverted npm_token -> NPM_AUTH_TOKEN and the
path confirmed, on railiance-platform's attended, read-only, no-value field
enumeration (their docs/evidence/2026-09-10-npm-lane-field-resolution.json).
Exactly one field is present at the governed path. The 2026-09-09 change was
adopted from a coordination message and would have failed at the WP-0037-T03
rotation. The ungoverned second location is recorded as an explicit non-lane,
not deleted and not tidied away.

pep-stance coverage: published figures were stale by eight lanes (unknown
18->20, not_applicable 12->15) while resolved stayed at 3 — the denominator
moved, the classification did not. Caught by the test that asserts the published
block equals what report_coverage.py measures. tests/test_workload_join.py held
the same stale counts; both now measure the same populations.

rapp-qonto-keycape-client: blocker character updated — authority exists and is
unexercised by owner decision ("not yet", offer open), which is not the same as
no authority existing. Reopen triggers are events, never elapsed time.

flex-auth -> access-engine rename (WARDEN-IN-0003): access-engine added to the
policy-check lane's keywords so routing resolves under both names from today.
owner_repo deliberately not flipped — policy.py sends it as resource.system on
every /v1/check, and FLEX-DEC-2026-013 keeps runtime names as flex-auth.

layer declaration: INTENT.md says Staff, layer.yaml says staff, section 11 does
not say which governs. Neither changed; gate-house holds the ruling. Position in
docs/layer-declaration-precedence.md, wait in WARDEN-WP-0034-T06, and a comment
in layer.yaml telling the next session not to "fix" it — the divergence is the
evidence the ruling is made against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 63291@bnt-lap001
Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
2026-09-21 02:16:33 +02:00

6.2 KiB

whynot-design npm publish token

Date: 2026-09-04 Catalog: whynot-design-npm-publish (status active, resolvable: true) Owner: railiance-platform (OpenBao) · provisioning CCR-2026-0001 (commit 8f617fc)

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 publish token for @whynot/design on the coulomb Forgejo npm registry (KV field NPM_AUTH_TOKEN, which is also the name the publish command reads it under) (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.


Owner-confirmed lane (no placeholders)

Field Value
OpenBao path platform/workloads/coulomb/whynot-design/npm-publish
KV field NPM_AUTH_TOKEN — the only field present at this path (attended enumeration 2026-09-10, railiance-platform docs/evidence/2026-09-10-npm-lane-field-resolution.json)
Injected env var NPM_AUTH_TOKEN — same name as the KV field, which is what made the 2026-09-09 npm_token change look plausible
KV mount platform
Read policy workload-kv-read-whynot-design-npm-publish
OIDC login bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
Bound group whynot-design
flex-auth ref secret.read:whynot-design (if tenant policy requires pre-approval)
Runbook (owner) railiance-platform/docs/workload-kv-access-lanes.md

The platform/workloads/whynot-design/whynot-design/npm-publish path from early in the provisioning thread is superseded — the live path is under the coulomb tenant.

A second, ungoverned location exists and is not this lane. secret/coulomb/whynot-design/npm/publish (v1, created 2026-07-03, never updated) sits outside this lane's exact-path policy and outside any CCR. It was found by metadata read only; its field names were not enumerated, its value was not read, and it was not deleted — a location holding real credential material is disposed of deliberately by its owner, not tidied away by whoever finds it. railiance-platform tracks it as RPF-WP-0035-T07, with an open hypothesis that the native secrets-engine exec front door below may be reading it rather than the governed path. If that proves true, this lane's acceptance evidence describes a path its consumer does not use. Do not route around the governed path on that suspicion; the question is with its owners.


Worker checklist

  1. Authenticate as yourself (you need your own identity; ops-warden adds none):

    bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
    

    Your token must carry the whynot-design group bound claim; a non-whynot identity is denied by policy (verified negative case).

  2. Run via the owner-native front door (primary). secrets-engine owns the secret-exec for this lane (SECRETS-WP-0003, decision e6381a56); ops-warden routes to it:

    secrets-engine route whynot-design-npm-publish --json          # pointer / readiness
    secrets-engine exec --catalog whynot-design-npm-publish -- \
      npm view @whynot/design@<version> 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). The project .npmrc must point both the @whynot scope and token fragment at forgejo.coulomb.social:

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

    On either path the value transits to you (or the child env) and never enters ops-warden's memory, disk, or audit log.

  3. Readiness gate (for automated callers). Before attempting --fetch, check the flag:

    warden route show whynot-design-npm-publish --json | jq .resolvable   # true
    

    resolvable: true means the lane is concrete and --fetch will run; a template lane reports false.

  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.


Scopes

This lane is the publish token only. A separate read/install token (for consumers of @whynot/design) is a distinct need and would be its own catalog id (whynot-design-npm-read) once railiance-platform provisions it — do not conflate them.


See also

  • wiki/OperatorAccessAssist.md — the warden access front door + guardrails
  • wiki/CredentialRouting.md — routing model
  • railiance-platform/docs/workload-kv-access-lanes.md, workplans/RAILIANCE-WP-0006-workload-kv-access-lanes.md