Gitea has been replaced by Forgejo. Updates prose mentions in docs/ while deliberately preserving live names that a blind sweep would have broken: GITEA_BACKEND_TOKEN is a provisioned OpenBao field in CCR-2026-0002, GITEA_URL is a Makefile variable, and gitea-db is a running cnpg cluster. Capitalisation discriminates prose from identifiers. Archived workplans are left as historical record. Blueprint 5.2: forge placement decided - workload to rapp-forgejo, layer responsibility to S4 railiance-enablement, which already declares the handoff contract and gains its first concrete owned responsibility. Blueprint 5.6: whether Railiance should use ArgoCD at all is recorded as an open decision rather than acted on by removing mentions. S3 runs four live ArgoCD Applications plus AppProjects, and the two most recent commits here add more, so deleting the documentation would describe a system that does not exist. The question is real; it needs a decision and a migration, not a docs edit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
253 lines
7.3 KiB
Markdown
253 lines
7.3 KiB
Markdown
# 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: Forgejo package token for
|
|
`https://forgejo.coulomb.social/api/packages/coulomb/npm/`
|
|
|
|
The operator reported that the Forgejo 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
|
|
```
|