Files
railiance-platform/docs/whynot-design-npm-publish-handoff.md

6.5 KiB

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: applied; non-secret OpenBao apply checks passed 2026-06-28
  • Front door: applied-pending-verify, resolvable=false
  • 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; no user membership was changed. Add only the intended publisher/verifier identity to that group before retrying positive verification.

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.
  • Do not mark the ops-warden catalog entry ready until positive and negative verification are complete.

OpenBao Secret Check

In the OpenBao UI, confirm the secret exists under the platform KV engine:

workloads/coulomb/whynot-design/npm-publish

Expected field:

NPM_AUTH_TOKEN

Expected custom metadata:

catalog-id = whynot-design-npm-publish

Do not reveal the value during review.

Policy

Create or update ACL policy:

workload-kv-read-whynot-design-npm-publish

Policy body:

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:

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:

auth/netkingdom/role/whynot-design-workload-kv-read

Role payload:

{
  "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:

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:

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:

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:

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.

Use an attended shell, keep tracing disabled, and suppress command output:

set +x
bao login -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.

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;

then CCR-2026-0001 can move toward active, and ops-warden can mark whynot-design-npm-publish ready/resolvable=true.

Until then, keep the front door as:

readiness = applied-pending-verify
resolvable = false