secrets-engine/catalog/whynot-design-npm-publish.yaml
tegwick b61b575b5b
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
docs: record whynot-design lane pointer discrepancy from ops-warden
ops-warden (WARDEN-WP-0037-T01) reported the whynot-design npm lane as
platform/workloads/coulomb/whynot-design/npm-publish, field NPM_AUTH_TOKEN.

Reviewed without any OpenBao read or mutation:
- The field claim conflates the injected env var (resolved by
  publication_policy) with the declared KV field (npm_token). Annotated the
  catalog so the distinction is explicit at the point of confusion.
- The path claim is credible but unresolved: hardening-backlog already names
  both locations, and custody is owned by railiance-platform. Catalog
  mount/path left unchanged pending custody-side confirmation rather than
  rewriting a proven production lane from an inbox claim.

Recorded under SECRETS-WP-0006-T06.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M65ovP3eiiPHubibvWs9mD

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 393550@bnt-lap001
Assistant-Session: 4bb359f9-1f12-4410-9e76-079cf23c82e4
2026-09-06 00:46:02 +02:00

78 lines
3.3 KiB
YAML

# whynot-design npm publish token — the MVP pilot lane.
# This file is NON-SECRET. It describes where the token lives in OpenBao and how
# it may be consumed. The token VALUE never appears here.
#
# Terminology (Gitea is overloaded — we use the most explicit words):
# org = coulomb the Gitea organisation
# repo = whynot-design the Gitea repository / product (NOT an org, NOT a scope)
# npm package = @whynot/design published to the coulomb Gitea npm registry
# "@whynot" is the npm *scope*; it is neither the org nor the repo name.
id: whynot-design-npm-publish
org: coulomb
repo: whynot-design
stage: prod
description: >-
npm automation token used to publish the @whynot/design package from the
coulomb/whynot-design repo to the coulomb Gitea npm registry. Delivered to
`npm publish` via an exec-time temporary npm config; never printed or exported
into the parent shell.
# OpenBao KV v2 location of the secret material (org/repo-scoped path).
mount: secret
path: coulomb/whynot-design/npm/publish
# Field(s) inside the KV entry. The publish token is stored under this key.
# NOTE: this is the KV field name, NOT the env var the value is injected as.
# The injected name is resolved separately by the publication-scope policy and
# is currently `NPM_AUTH_TOKEN` (see delivery_config.npm.maturity below and
# docs/publication-scope-policy.md). Do not conflate the two.
fields:
- npm_token
# Who may consume this lane and the identity claim that binds them.
consumers:
- name: whynot-design-ci
auth: approle # bound OpenBao auth method
claim: "repo:coulomb/whynot-design"
purpose: "publish @whynot/design to the coulomb Gitea npm registry from CI"
# How the value may leave OpenBao. npm-config = temp .npmrc for the child only.
delivery_modes:
- npm-config
- read-check
# npm-specific delivery target. The registry/scope live here as catalog DATA so
# the engine never hardcodes a registry. Matches coulomb/whynot-design/.npmrc.
delivery_config:
npm:
registry: "https://forgejo.coulomb.social/api/packages/coulomb/npm/"
scope: "@whynot"
package: "@whynot/design"
# Package maturity tag. Under the netkingdom publication-scope policy this
# would map to a publication scope (build->gitea, test->org, prod->repo) once
# netkingdom is production grade. netkingdom is at maturity-build today, so the
# policy is dormant and this lane clamps to repo-scope, injected as
# NPM_AUTH_TOKEN. Set `token_env` to override the resolved name.
maturity: maturity-build
# token_env: NPM_AUTH_WHYNOTDESIGN # explicit per-repo form (optional)
# Privileged actions on this lane require an approved decision/CCR.
approval:
model: decision
decision_ref: "e6381a56-6b04-4fd5-b2de-f3ef59cde888" # Canonical State Hub decision UUID; local fixture is offline fallback
notes: "Production lane: apply requires an approved decision."
# Verification expectations (no value is ever printed).
verification:
positive: "approved consumer token can read the lane field"
negative: "an unrelated token is denied read on the lane path"
rotation:
expectation: "rotate on compromise or every 90 days"
ttl: "90d"
deactivation:
expectation: "revoke approle + delete KV metadata; record evidence"
audit:
evidence: "decision id, actor, path, timestamp, result — no secret value"