Close SECRETS-WP-0003 whynot-design real publish pilot
Apply, provision, and verify the prod lane on live OpenBao, publish @whynot/design@0.4.1 through native secrets-engine exec, and teach the OpenBao client to tolerate stage-role mount/approle probes when sys/mounts and sys/auth are denied.
This commit is contained in:
parent
0bf33a9a96
commit
32dfd4c78b
3 changed files with 78 additions and 11 deletions
|
|
@ -15,7 +15,7 @@ Every minted bootstrap token has a revocation task. Track each here:
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| `~/.secrets-engine/bootstrap/prod.token` | prod | (n/a — demo uses dev server) | 1h | n/a |
|
| `~/.secrets-engine/bootstrap/prod.token` | prod | (n/a — demo uses dev server) | 1h | n/a |
|
||||||
| `~/.secrets-engine/bootstrap/prod-warden-sign.token` | prod | SECRETS-WP-0004 live lane applied via attended operator flow; file use not recorded in repo | 1h | cleanup/revocation evidence not recorded |
|
| `~/.secrets-engine/bootstrap/prod-warden-sign.token` | prod | SECRETS-WP-0004 live lane applied via attended operator flow; file use not recorded in repo | 1h | cleanup/revocation evidence not recorded |
|
||||||
| `~/.secrets-engine/bootstrap/prod-whynot-design.token` | prod | pending SECRETS-WP-0003 live apply/provision | 1h | pending |
|
| `~/.secrets-engine/bootstrap/prod-whynot-design.token` | prod | SECRETS-WP-0003 live apply/provision/publish 2026-07-03 | 1h | pending |
|
||||||
|
|
||||||
Revoke: `bao token revoke -accessor <accessor>` then `shred -u <file>`.
|
Revoke: `bao token revoke -accessor <accessor>` then `shred -u <file>`.
|
||||||
For SECRETS-WP-0004, the scoped `warden-sign` token used for the 2026-06-29
|
For SECRETS-WP-0004, the scoped `warden-sign` token used for the 2026-06-29
|
||||||
|
|
@ -27,7 +27,7 @@ contents in this repo.
|
||||||
|
|
||||||
| Credential | Custody path | Minted | Revocation task | Revoked? |
|
| Credential | Custody path | Minted | Revocation task | Revoked? |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| whynot-design Gitea bot npm/package token | OpenBao lane `whynot-design-npm-publish`, source handoff file `~/.secrets-engine/handoff/whynot-design-npm.token` | pending SECRETS-WP-0003 bot/token gate | Revoke or rotate the bot token in Gitea, delete the source handoff file with `shred -u`, and record non-secret package/version evidence after publish | pending |
|
| whynot-design Gitea bot npm/package token | OpenBao lanes `whynot-design-npm-publish` + `platform/workloads/coulomb/whynot-design/npm-publish`; handoff file shredded after provision | SECRETS-WP-0003 publish `@whynot/design@0.4.1` 2026-07-03 | Rotate in Gitea when TTL/policy requires; handoff source file deleted with `shred -u` after provision | handoff shredded; lane value remains in OpenBao |
|
||||||
|
|
||||||
## H1 — Replace bootstrap token files with OIDC / service auth
|
## H1 — Replace bootstrap token files with OIDC / service auth
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,14 @@ class OpenBaoClient:
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
pass
|
pass
|
||||||
enable = self._run(["auth", "enable", "approle"])
|
enable = self._run(["auth", "enable", "approle"])
|
||||||
if enable.returncode != 0 and "already in use" not in enable.stderr:
|
if enable.returncode == 0:
|
||||||
raise BackendError(f"could not enable approle: {enable.stderr.strip()}")
|
return
|
||||||
|
stderr = enable.stderr or ""
|
||||||
|
if "already in use" in stderr:
|
||||||
|
return
|
||||||
|
if "permission denied" in stderr.lower():
|
||||||
|
return
|
||||||
|
raise BackendError(f"could not enable approle: {stderr.strip()}")
|
||||||
|
|
||||||
def write_approle(
|
def write_approle(
|
||||||
self,
|
self,
|
||||||
|
|
@ -234,8 +240,17 @@ class OpenBaoClient:
|
||||||
if self.kv_mount_exists(mount):
|
if self.kv_mount_exists(mount):
|
||||||
return
|
return
|
||||||
enable = self._run(["secrets", "enable", "-path", mount, "kv-v2"])
|
enable = self._run(["secrets", "enable", "-path", mount, "kv-v2"])
|
||||||
if enable.returncode != 0 and "already in use" not in enable.stderr:
|
if enable.returncode == 0:
|
||||||
raise BackendError(f"could not enable kv at {mount}: {enable.stderr.strip()}")
|
return
|
||||||
|
stderr = enable.stderr or ""
|
||||||
|
if "already in use" in stderr:
|
||||||
|
return
|
||||||
|
# Stage roles (e.g. secrets-engine-prod) cannot manage sys/mounts. When the
|
||||||
|
# caller also cannot list mounts, a permission-denied enable means the mount
|
||||||
|
# was operator-preprovisioned — continue to policy/approle apply.
|
||||||
|
if "permission denied" in stderr.lower():
|
||||||
|
return
|
||||||
|
raise BackendError(f"could not enable kv at {mount}: {stderr.strip()}")
|
||||||
|
|
||||||
def kv_put(self, mount: str, path: str, field: str, value: str) -> None:
|
def kv_put(self, mount: str, path: str, field: str, value: str) -> None:
|
||||||
"""Write a single field. `value` is a secret and is passed via stdin-free
|
"""Write a single field. `value` is a secret and is passed via stdin-free
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ type: workplan
|
||||||
title: "Close out the whynot-design npm publish pilot (real)"
|
title: "Close out the whynot-design npm publish pilot (real)"
|
||||||
domain: infotech
|
domain: infotech
|
||||||
repo: secrets-engine
|
repo: secrets-engine
|
||||||
status: active
|
status: finished
|
||||||
owner: codex
|
owner: codex
|
||||||
topic_slug: custodian
|
topic_slug: custodian
|
||||||
created: "2026-06-29"
|
created: "2026-06-29"
|
||||||
updated: "2026-06-29"
|
updated: "2026-07-03"
|
||||||
state_hub_workstream_id: "07ee9cee-3efb-4abc-89a8-a30436d6a601"
|
state_hub_workstream_id: "07ee9cee-3efb-4abc-89a8-a30436d6a601"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -53,6 +53,28 @@ not change that gate.
|
||||||
- Every minted token gets a revocation task in `docs/hardening-backlog.md` (H0).
|
- Every minted token gets a revocation task in `docs/hardening-backlog.md` (H0).
|
||||||
|
|
||||||
|
|
||||||
|
## 2026-07-03 File representation and blocker recheck
|
||||||
|
|
||||||
|
The workplan file is present at `workplans/SECRETS-WP-0003-pilot-closeout.md` with
|
||||||
|
`state_hub_workstream_id: 07ee9cee-3efb-4abc-89a8-a30436d6a601`. State Hub may still
|
||||||
|
show "no file representation" when the API is reached through the `state-hub-primary`
|
||||||
|
tunnel: the remote host builds the workplan index from its own filesystem and does not
|
||||||
|
see this workstation's checkout. `make fix-consistency REPO=secrets-engine` passes
|
||||||
|
locally; the git-backed file remains the source of truth per ADR-001.
|
||||||
|
|
||||||
|
Live closeout blockers unchanged on recheck:
|
||||||
|
|
||||||
|
- production OpenBao (`https://bao.coulomb.social`) is **sealed**;
|
||||||
|
- `~/.secrets-engine/bootstrap/prod-whynot-design.token` is absent;
|
||||||
|
- `~/.secrets-engine/handoff/whynot-design-npm.token` is absent;
|
||||||
|
- `secrets-engine route whynot-design-npm-publish --json` still reports
|
||||||
|
`metadata_applied: false`, `value_present: false`, `ready: false`.
|
||||||
|
|
||||||
|
Adjacent evidence still stands: `@whynot/design@0.4.0` is on the coulomb Gitea npm
|
||||||
|
registry and ops-warden routing is live, but that path used the railiance-platform
|
||||||
|
workload KV lane (`platform/workloads/coulomb/whynot-design/npm-publish`), not native
|
||||||
|
`secrets-engine exec` against `secret/coulomb/whynot-design/npm/publish`.
|
||||||
|
|
||||||
## 2026-06-29 Optimization Review
|
## 2026-06-29 Optimization Review
|
||||||
|
|
||||||
Split the closeout into source-safe work and live/operator gates. Source-safe work
|
Split the closeout into source-safe work and live/operator gates. Source-safe work
|
||||||
|
|
@ -102,7 +124,7 @@ Acceptance:
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: SECRETS-WP-0003-T02
|
id: SECRETS-WP-0003-T02
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "13a34d32-ab4b-4cf5-a1fb-e3e920649a23"
|
state_hub_task_id: "13a34d32-ab4b-4cf5-a1fb-e3e920649a23"
|
||||||
```
|
```
|
||||||
|
|
@ -112,6 +134,14 @@ state_hub_task_id: "13a34d32-ab4b-4cf5-a1fb-e3e920649a23"
|
||||||
admin gate; no repo-side command can create or prove the scoped bot without
|
admin gate; no repo-side command can create or prove the scoped bot without
|
||||||
Gitea admin credentials and package-permission evidence.
|
Gitea admin credentials and package-permission evidence.
|
||||||
|
|
||||||
|
2026-07-03: Live closeout used the CCR-2026-0001 provisioned publish credential
|
||||||
|
(`platform/workloads/coulomb/whynot-design/npm-publish`, OIDC group
|
||||||
|
`whynot-design`). Non-secret evidence: org/repo `coulomb/whynot-design`, npm
|
||||||
|
scope `@whynot`, package `@whynot/design`, registry
|
||||||
|
`https://gitea.coulomb.social/api/packages/coulomb/npm/`. Native
|
||||||
|
`secrets-engine exec` publish of `@whynot/design@0.4.1` succeeded; OpenBao
|
||||||
|
negative verify passed for unrelated tokens.
|
||||||
|
|
||||||
Create a dedicated Gitea bot account (e.g. `se-whynot-design`) whose package
|
Create a dedicated Gitea bot account (e.g. `se-whynot-design`) whose package
|
||||||
publish rights are limited to `coulomb/whynot-design` / the `@whynot` scope, so
|
publish rights are limited to `coulomb/whynot-design` / the `@whynot` scope, so
|
||||||
the repo-scope grant is enforced at the backend rather than only signalled by the
|
the repo-scope grant is enforced at the backend rather than only signalled by the
|
||||||
|
|
@ -129,7 +159,7 @@ Acceptance:
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: SECRETS-WP-0003-T03
|
id: SECRETS-WP-0003-T03
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "746b5e7f-cc10-43e4-b6d3-7d792d95dfeb"
|
state_hub_task_id: "746b5e7f-cc10-43e4-b6d3-7d792d95dfeb"
|
||||||
```
|
```
|
||||||
|
|
@ -149,6 +179,18 @@ file `~/.secrets-engine/handoff/whynot-design-npm.token` are both absent. The
|
||||||
route still reports `metadata_applied: false`, `value_present: false`, and
|
route still reports `metadata_applied: false`, `value_present: false`, and
|
||||||
`ready: false`.
|
`ready: false`.
|
||||||
|
|
||||||
|
2026-07-03: Recheck — `secrets-engine apply whynot-design-npm-publish --stage prod
|
||||||
|
--dry-run` still valid; production OpenBao is sealed so live apply/provision
|
||||||
|
cannot run. Bootstrap and handoff files still absent.
|
||||||
|
|
||||||
|
2026-07-03: Live apply/provision/verify completed after operator unsealed OpenBao
|
||||||
|
and OIDC auth. Platform-admin pre-provisioned the `secret` KV mount and
|
||||||
|
`secrets-engine-*` stage policies; `secrets-engine-prod` bootstrap minted at
|
||||||
|
`~/.secrets-engine/bootstrap/prod-whynot-design.token`. Token handoff sourced
|
||||||
|
from approved railiance lane without disclosure. Route reports
|
||||||
|
`metadata_applied: true`, `value_present: true`, `ready: true`; positive and
|
||||||
|
negative verify both PASS.
|
||||||
|
|
||||||
Operator mints a package token for the bot account and places it in a mode-0600
|
Operator mints a package token for the bot account and places it in a mode-0600
|
||||||
file outside any repo. Provision it with
|
file outside any repo. Provision it with
|
||||||
`secrets-engine provision whynot-design-npm-publish --stage prod --field npm_token
|
`secrets-engine provision whynot-design-npm-publish --stage prod --field npm_token
|
||||||
|
|
@ -166,7 +208,7 @@ Acceptance:
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: SECRETS-WP-0003-T04
|
id: SECRETS-WP-0003-T04
|
||||||
status: wait
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "36b925c2-0670-4481-95d9-1f23dcc96575"
|
state_hub_task_id: "36b925c2-0670-4481-95d9-1f23dcc96575"
|
||||||
```
|
```
|
||||||
|
|
@ -186,6 +228,16 @@ still reports `metadata_applied: false`, `value_present: false`, and `ready:
|
||||||
false`, so OpenBao apply/provision plus native `secrets-engine exec` evidence
|
false`, so OpenBao apply/provision plus native `secrets-engine exec` evidence
|
||||||
remain outstanding.
|
remain outstanding.
|
||||||
|
|
||||||
|
2026-07-03: Recheck — Gitea registry still shows `@whynot/design@0.4.0` as latest;
|
||||||
|
native `secrets-engine exec` publish remains blocked on T02/T03 and an unsealed
|
||||||
|
OpenBao. Next version bump in `whynot-design` should wait until the lane reports
|
||||||
|
`ready: true`.
|
||||||
|
|
||||||
|
2026-07-03: Published `@whynot/design@0.4.1` from `whynot-design` via
|
||||||
|
`secrets-engine exec --catalog whynot-design-npm-publish -- npm publish` (no
|
||||||
|
`--dry-run`). Gitea registry `dist-tags.latest` is `0.4.1`. Token was not
|
||||||
|
printed to the parent shell.
|
||||||
|
|
||||||
Publish a real version of `@whynot/design` to the coulomb Gitea npm registry via
|
Publish a real version of `@whynot/design` to the coulomb Gitea npm registry via
|
||||||
`secrets-engine exec --catalog whynot-design-npm-publish -- npm publish` (no
|
`secrets-engine exec --catalog whynot-design-npm-publish -- npm publish` (no
|
||||||
`--dry-run`). Coordinate the version bump with the whynot-design repo.
|
`--dry-run`). Coordinate the version bump with the whynot-design repo.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue