# whynot-design npm Publish Token Handoff This is the next-session handoff for `CCR-2026-0001` and the `whynot-design-npm-publish` access lane. ## Current State - CCR: `CCR-2026-0001` - Decision: `e6381a56-6b04-4fd5-b2de-f3ef59cde888` - Status: active; non-secret OpenBao apply and verification checks passed - Front door: `ready`, `resolvable=true` - Positive verification: passed 2026-06-28 - Negative verification: passed 2026-06-28 - Catalog id: `whynot-design-npm-publish` - Tenant/org: `coulomb` - Workload/project: `whynot-design` - Bound IAM group: `whynot-design` - Secret path: `platform/workloads/coulomb/whynot-design/npm-publish` - Field: `NPM_AUTH_TOKEN` - Token source: Gitea package token for `https://gitea.coulomb.social/api/packages/coulomb/npm/` The operator reported that the Gitea token was generated and stored in OpenBao. Using the temporary operator token only for non-secret infrastructure work, Codex confirmed that the policy exists, the OIDC role exists with the whynot-design binding and redirect URIs, the secret metadata has the expected catalog id, and the `NPM_AUTH_TOKEN` field is present. No secret value was printed, recorded, or copied into Git, State Hub, chat, or workplans. On 2026-06-28, the attended positive OIDC login advanced from a missing `groups` claim to a bound-claim mismatch. That means the role now requests the `groups` scope correctly, but the authenticating identity is not a member of `whynot-design`. The `whynot-design` LLDAP group was created and verified. The intended publisher/verifier identity was later added, positive verification passed, then `platform-root` was temporarily removed for negative verification. The negative check passed with a groups bound-claim mismatch, and `platform-root` was restored to `whynot-design`. ## Safety Rules - Do not paste `NPM_AUTH_TOKEN` into Git, State Hub, chat, shell history, logs, workplans, or screenshots. - Do not run verification with shell tracing enabled. - Record only non-secret evidence: path, field name, metadata keys, policy name, role name, actor, timestamp, and pass/fail result. - Mark ops-warden catalog entries ready only after positive and negative verification are complete. For this lane, both checks have passed. ## OpenBao Secret Check In the OpenBao UI, confirm the secret exists under the `platform` KV engine: ```text workloads/coulomb/whynot-design/npm-publish ``` Expected field: ```text NPM_AUTH_TOKEN ``` Expected custom metadata: ```text catalog-id = whynot-design-npm-publish ``` Do not reveal the value during review. ## Policy Create or update ACL policy: ```text workload-kv-read-whynot-design-npm-publish ``` Policy body: ```hcl path "platform/data/workloads/coulomb/whynot-design/npm-publish" { capabilities = ["read"] } path "platform/metadata/workloads/coulomb/whynot-design/npm-publish" { capabilities = ["read"] } ``` Equivalent CLI command from an approved OpenBao operator context: ```bash bao policy write workload-kv-read-whynot-design-npm-publish \ openbao/policies/workload-kv-read-whynot-design-npm-publish.hcl ``` ## OIDC Role Create or update: ```text auth/netkingdom/role/whynot-design-workload-kv-read ``` Role payload: ```json { "role_type": "oidc", "allowed_redirect_uris": [ "https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback", "http://localhost:8250/oidc/callback", "http://127.0.0.1:8250/oidc/callback" ], "oidc_scopes": [ "openid", "profile", "email", "groups" ], "user_claim": "sub", "groups_claim": "groups", "bound_claims": { "groups": ["whynot-design"] }, "policies": "workload-kv-read-whynot-design-npm-publish", "ttl": "15m" } ``` Equivalent CLI command from an approved OpenBao operator shell: ```bash role_payload_file="$(mktemp)" trap 'rm -f "$role_payload_file"' EXIT cat >"$role_payload_file" <<'JSON' { "allowed_redirect_uris": [ "https://bao.coulomb.social/ui/vault/auth/netkingdom/oidc/callback", "http://localhost:8250/oidc/callback", "http://127.0.0.1:8250/oidc/callback" ], "oidc_scopes": [ "openid", "profile", "email", "groups" ], "bound_claims": { "groups": [ "whynot-design" ] }, "groups_claim": "groups", "policies": "workload-kv-read-whynot-design-npm-publish", "role_type": "oidc", "ttl": "15m", "user_claim": "sub" } JSON bao write auth/netkingdom/role/whynot-design-workload-kv-read @"$role_payload_file" ``` The OpenBao Browser CLI cannot run this shell block and may treat `bound_claims={...}` as a string. When staying in the Web UI, open the API Explorer and submit the role payload JSON above with: ```text method: PUT path: /v1/auth/netkingdom/role/whynot-design-workload-kv-read ``` If the API Explorer asks for a path without the API prefix, use `auth/netkingdom/role/whynot-design-workload-kv-read`. ## Non-Secret Reads These commands should succeed from an operator-capable identity and do not print the token value: ```bash bao kv metadata get platform/workloads/coulomb/whynot-design/npm-publish bao policy read workload-kv-read-whynot-design-npm-publish bao read auth/netkingdom/role/whynot-design-workload-kv-read ``` ## Positive Verification Positive verification proves the approved whynot-design identity can fetch the field without exposing it in logs. Before retrying, confirm the account used for OIDC login is a member of the `whynot-design` LLDAP group. If OpenBao reports: ```text claim "groups" does not match any associated bound claim values ``` then the groups claim is present, but the account is not in `whynot-design` or KeyCape did not emit that membership in the fresh login. The positive verification passed on 2026-06-28. During that run, the CLI printed the short-lived OpenBao login token; it was revoked immediately by accessor. Prefer `bao login -no-print` for future attended verification if the installed CLI accepts that flag. Use an attended shell, keep tracing disabled, and suppress command output: ```bash set +x bao login -no-print -method=oidc -path=netkingdom role=whynot-design-workload-kv-read bao kv get -format=json platform/workloads/coulomb/whynot-design/npm-publish \ | jq -e '.data.data.NPM_AUTH_TOKEN | type == "string" and length > 0' \ >/dev/null ``` Record only that the check passed. ## Negative Verification Negative verification proves a non-whynot identity cannot read the same field. Use a non-whynot identity or role and confirm the read is denied. Do not print or store any token value. Record only the denial result and non-secret audit timestamp/request metadata. The negative verification passed on 2026-06-28. `platform-root` was temporarily removed from `whynot-design`; OpenBao rejected the OIDC login with a groups bound-claim mismatch, so no OpenBao client token was issued and the secret was not read. `platform-root` was then restored to `whynot-design`. ## Activation Only after these are true: - secret metadata confirmed; - policy exists and is scoped to the corrected `coulomb/whynot-design` path; - OIDC role exists and binds only `groups=["whynot-design"]` with approved browser/local CLI callback URIs and `groups` OIDC scope; - positive verification passed; - negative verification passed; `CCR-2026-0001` is now `active`, and ops-warden can mark `whynot-design-npm-publish` `ready`/`resolvable=true`. Current front door: ```text readiness = ready resolvable = true ```