Compare commits

...

10 commits

Author SHA1 Message Date
86d6d20d7f Add Forgejo CI smoke workflow (enablement template)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
2026-07-08 12:37:57 +02:00
bde8ab2fac chore: archive SECRETS-WP-0003 whynot-design pilot closeout
All exit criteria met on 2026-07-03; workplan status set to archived and
moved to workplans/archived/ with completion-date prefix.
2026-07-08 00:34:07 +02:00
f374287a99 chore: record prod-whynot-design bootstrap token cleanup
Mark H0 bootstrap file shredded after SECRETS-WP-0003 closeout; accessor
revoke deferred while OpenBao is sealed (1h TTL likely expired).
2026-07-03 17:39:34 +02:00
32dfd4c78b 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.
2026-07-03 17:04:19 +02:00
0bf33a9a96 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-03:
  - update .custodian-brief.md for secrets-engine
2026-07-03 17:04:09 +02:00
2251cf7321 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-03:
  - update .custodian-brief.md for secrets-engine
2026-07-03 16:34:45 +02:00
7d09fc3aea Advance whynot pilot routing status 2026-06-30 17:33:52 +02:00
dc2099b9f0 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-06-30:
  - update .custodian-brief.md for secrets-engine
2026-06-30 15:17:30 +02:00
e0ab1b8420 Close warden-sign token lane 2026-06-30 01:01:55 +02:00
52e850f26b chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-06-30:
  - update .custodian-brief.md for secrets-engine
2026-06-30 01:00:51 +02:00
7 changed files with 202 additions and 45 deletions

View file

@ -2,29 +2,12 @@
# Custodian Brief — secrets-engine
**Domain:** infotech
**Last synced:** 2026-06-29 22:49 UTC
**Last synced:** 2026-07-03 15:04 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### Provision a scoped warden-sign token lane (ops-warden / FLEX-WP-0007 T4)
Progress: 2/5 done | workstream_id: `eb1bdff7-909c-4391-8b95-6baf1feb3a54`
**Open tasks:**
- ! T03 - Apply against production OpenBao via bootstrap token `4b414788`
*(wait: missing-approved-decision-and-bootstrap-token)*
- ! T04 - Out-of-band handoff and non-secret pointers `52b5cf88`
*(wait: awaiting-live-apply-and-out-of-band-handoff)*
- ! T05 - Confirm the joint smoke and signal ops-warden `aa0f281e`
### Close out the whynot-design npm publish pilot (real)
Progress: 1/5 done | workstream_id: `07ee9cee-3efb-4abc-89a8-a30436d6a601`
**Open tasks:**
- ! T02 - Stand up a dedicated Gitea bot account for the repo-scoped grant `13a34d32`
- ! T03 - Provision the real npm token without disclosure `746b5e7f`
- ! T04 - Real `npm publish` of @whynot/design through secrets-engine exec `36b925c2`
- ► T05 - Hand the routing contract to ops-warden (cross-repo) `461a7854`
*(none — repo may need first-session setup)*
---
## MCP Orientation (when available)

View file

@ -0,0 +1,29 @@
# Canonical CI smoke template (tier 1 routing drill).
# Copy to: .forgejo/workflows/ci-smoke.yaml in consumer repos.
name: CI Smoke
on:
push:
branches:
- main
workflow_dispatch:
jobs:
host-smoke:
runs-on: self-hosted
steps:
- name: Routing probe (host runner)
run: |
set -eu
echo "repository=${GITHUB_REPOSITORY:-unknown}"
echo "sha=${GITHUB_SHA:-unknown}"
echo "runner=${RUNNER_NAME:-unknown}"
uname -a
container-smoke:
runs-on: ubuntu-latest
steps:
- name: Routing probe (container label)
run: |
set -eu
echo "container-smoke ok for ${GITHUB_REPOSITORY:-unknown}"

View file

@ -14,19 +14,20 @@ Every minted bootstrap token has a revocation task. Track each here:
| Token file | Stage | Minted | TTL | Revoked? |
| --- | --- | --- | --- | --- |
| `~/.secrets-engine/bootstrap/prod.token` | prod | (n/a — demo uses dev server) | 1h | n/a |
| `~/.secrets-engine/bootstrap/prod-warden-sign.token` | prod | pending SECRETS-WP-0004 live apply | 1h | pending |
| `~/.secrets-engine/bootstrap/prod-whynot-design.token` | prod | pending SECRETS-WP-0003 live apply/provision | 1h | pending |
| `~/.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 | SECRETS-WP-0003 live apply/provision/publish 2026-07-03 | 1h | file shredded 2026-07-03; accessor revoke deferred (OpenBao sealed; 1h TTL likely expired) |
Revoke: `bao token revoke -accessor <accessor>` then `shred -u <file>`.
For SECRETS-WP-0004, revoke the scoped `warden-sign` token/accessor after the
FLEX-WP-0007 T4 smoke or when its `15m` TTL expires, and remove the handoff
files under `~/.secrets-engine/handoff/`.
For SECRETS-WP-0004, the scoped `warden-sign` token used for the 2026-06-29
smoke had a `15m` TTL; explicit accessor revocation and handoff-file cleanup are
operator-side hygiene if any material remains. Do not record accessors or file
contents in this repo.
## H0a — Revoke pilot workload tokens
| 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

View file

@ -198,3 +198,14 @@ BAO_ADDR=https://bao.coulomb.social \
secrets-engine revoke warden-sign \
--bootstrap-token-file ~/.secrets-engine/bootstrap/prod-warden-sign.token
```
## Closeout status
On 2026-06-29 ops-warden reported the joint production smoke as passed against
the flex-auth runtime and production OpenBao. Non-secret evidence only:
`warden sign agt-state-hub-bridge` returned policy decision
`decision:032b096c433ad80c`, `--ttl 999` was denied with
`ttl_out_of_bounds` before OpenBao signing, and the vault-backed allow path used
the scoped `warden-sign` lane. `policy.enabled` remains off until the ecosystem
moves from build-stage/pre-testing into the maturity posture where live
enforcement is appropriate.

View file

@ -140,8 +140,14 @@ class OpenBaoClient:
except json.JSONDecodeError:
pass
enable = self._run(["auth", "enable", "approle"])
if enable.returncode != 0 and "already in use" not in enable.stderr:
raise BackendError(f"could not enable approle: {enable.stderr.strip()}")
if enable.returncode == 0:
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(
self,
@ -234,8 +240,17 @@ class OpenBaoClient:
if self.kv_mount_exists(mount):
return
enable = self._run(["secrets", "enable", "-path", mount, "kv-v2"])
if enable.returncode != 0 and "already in use" not in enable.stderr:
raise BackendError(f"could not enable kv at {mount}: {enable.stderr.strip()}")
if enable.returncode == 0:
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:
"""Write a single field. `value` is a secret and is passed via stdin-free

View file

@ -4,11 +4,11 @@ type: workplan
title: "Provision a scoped warden-sign token lane (ops-warden / FLEX-WP-0007 T4)"
domain: infotech
repo: secrets-engine
status: active
status: finished
owner: codex
topic_slug: custodian
created: "2026-06-29"
updated: "2026-06-29"
updated: "2026-06-30"
state_hub_workstream_id: "eb1bdff7-909c-4391-8b95-6baf1feb3a54"
---
@ -23,7 +23,8 @@ narrow capability), not a KV value. Post the non-secret pointers to State Hub an
hand the token/secret_id to the operator out-of-band.
This unblocks FLEX-WP-0007 T4 (the joint OpenBao + policy-gate production smoke),
after which `policy.enabled: true` can go live on CoulombCore.
after which the verified gate can be banked until `policy.enabled: true`
is appropriate for the ecosystem maturity stage.
## Context
@ -113,7 +114,7 @@ Acceptance:
```task
id: SECRETS-WP-0004-T03
status: wait
status: done
priority: high
state_hub_task_id: "4b414788-d670-496b-9c57-074464a012c4"
```
@ -136,9 +137,18 @@ missing lane decision or the documented bootstrap handoff.
2026-06-30: Approval mirror `.decisions/SECRETS-WP-0004.yaml` is now present
and `secrets-engine route warden-sign --json` reports `decision_status:
resolved` for canonical decision `4589dcb7-c0df-4073-9a0b-4f80a0fcdb93`.
Readiness remains false because the OpenBao `warden-sign` policy/AppRole has
not been applied (`metadata_applied: false`), and the documented lane bootstrap
token file is still absent. Live apply and handoff were not executed.
Readiness remained false at that checkpoint because the OpenBao `warden-sign`
policy/AppRole had not yet been applied (`metadata_applied: false`), and the
documented lane bootstrap token file was still absent. Live apply and handoff
were not executed in that checkpoint.
2026-06-30 closeout: ops-warden later reported that production OpenBao was
unsealed, the secrets-engine `warden-sign` lane was applied, and a scoped
AppRole token with `ssh/sign/agt-role` update capability was verified through
the vault-backed smoke. No token value, role_id, secret_id, token accessor, or
raw smoke log is recorded here. The documented bootstrap-token file path remains
part of the hardening/audit backlog, but live lane metadata is no longer the
blocker.
Apply the policy + AppRole on `https://bao.coulomb.social` using a mode-0600
bootstrap token stored outside any repo. Idempotent re-apply.
@ -154,7 +164,7 @@ Acceptance:
```task
id: SECRETS-WP-0004-T04
status: wait
status: done
priority: high
state_hub_task_id: "52b5cf88-029f-4f4b-8fe9-0a8dc30378b5"
```
@ -186,6 +196,13 @@ so handoff is waiting on live OpenBao apply plus an attended, out-of-band
bootstrap path. No `role_id`, `secret_id`, token value, token accessor, or
smoke output was written to Git or State Hub.
2026-06-30 closeout: the scoped warden-sign handoff path was exercised by the
operator/ops-warden outside Git and State Hub. The only recorded evidence is the
non-secret result: the vault-backed smoke used backend `vault` and policy
decision `decision:032b096c433ad80c`. `policy.enabled` is intentionally left off
until testing/production maturity; that is a separate operator posture decision,
not an unfinished secrets-engine handoff.
Define and execute the handoff: mint a fresh `secret_id`, deliver it (with the
`role_id`) to the operator out-of-band; warden does `approle login` to obtain a
`VAULT_TOKEN`. Post the non-secret pointers on the ops-warden thread (policy name,
@ -202,14 +219,22 @@ Acceptance:
```task
id: SECRETS-WP-0004-T05
status: wait
status: done
priority: medium
state_hub_task_id: "aa0f281e-976d-4fcd-b8a3-78582117f86f"
```
2026-06-29: Offline tests pass (`59 passed, 2 skipped`) and route/dry-run CLI
checks produce non-secret pointers. Joint production smoke and ops-warden signal
remain waiting on live OpenBao apply, handoff, and operator-run smoke evidence.
remained waiting on live OpenBao apply, handoff, and operator-run smoke evidence
at that checkpoint.
2026-06-30 closeout: ops-warden reported the joint smoke passed with non-secret
evidence only: allow path `warden sign agt-state-hub-bridge` returned
policy_decision_id `decision:032b096c433ad80c`, excessive TTL `--ttl 999` was
rejected with `ttl_out_of_bounds` before OpenBao, and the vault-backed allow path
used the scoped warden-sign lane. flex-auth closed `FLEX-WP-0007-T04` from this
evidence, so secrets-engine can close the credential/capability lane too.
Confirm the unblock end to end, then reply to ops-warden (msg 077ac90d) with the
pointers and runbook alignment. The reply is the explicit "we will signal
@ -231,3 +256,16 @@ Acceptance:
external condition).
- ops-warden has the non-secret pointers; no secret value crossed State Hub.
- The bootstrap token and the minted credential have revocation tasks.
## Closeout Evidence
2026-06-30: SECRETS-WP-0004 is finished from the same non-secret smoke evidence
used to close `FLEX-WP-0007-T04`:
- `warden-sign` policy/AppRole lane applied in production OpenBao after operator unseal.
- Scoped token capability verified for `ssh/sign/agt-role` update during the vault-backed smoke.
- Allow smoke: `warden sign agt-state-hub-bridge` -> `decision:032b096c433ad80c`.
- Deny smoke: `--ttl 999` -> `ttl_out_of_bounds` before OpenBao signing.
- No raw token, AppRole `secret_id`, `role_id`, token accessor, or smoke log was written to Git, State Hub, prompts, chat, or normal logs.
- `policy.enabled` remains off by build-stage maturity decision and can be flipped later by the ops-warden operator when testing/production posture requires live enforcement.

View file

@ -4,11 +4,11 @@ type: workplan
title: "Close out the whynot-design npm publish pilot (real)"
domain: infotech
repo: secrets-engine
status: active
status: archived
owner: codex
topic_slug: custodian
created: "2026-06-29"
updated: "2026-06-29"
updated: "2026-07-08"
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).
## 2026-07-08 Closeout complete
All tasks T01T05 are done. Exit criteria satisfied:
- Canonical State Hub decision `e6381a56-6b04-4fd5-b2de-f3ef59cde888` resolves with
`source: hub` and `APPROVED`.
- Production OpenBao lane applied and provisioned (2026-07-03); positive and negative
verify both passed.
- `@whynot/design@0.4.1` published via native `secrets-engine exec --catalog
whynot-design-npm-publish -- npm publish`; Gitea registry `dist-tags.latest` is
`0.4.1`.
- `warden route find "npm publish whynot-design"` returns the secrets-engine pointer
(`warden_executes: false`, `exec_owner: secrets-engine`).
- Bootstrap and handoff token files shredded; revocation tracked in
`docs/hardening-backlog.md` H0/H0a.
Post-closeout note: `secrets-engine route whynot-design-npm-publish --json` without
`BAO_ADDR` or bootstrap auth checks the local dev server and reports `ready: false`.
With `BAO_ADDR=https://bao.coulomb.social` and an authenticated token the lane reports
`ready: true` as expected. Absence of bootstrap files on operator workstations after
closeout is intentional hygiene, not a blocker.
## 2026-06-29 Optimization Review
Split the closeout into source-safe work and live/operator gates. Source-safe work
@ -102,7 +124,7 @@ Acceptance:
```task
id: SECRETS-WP-0003-T02
status: wait
status: done
priority: high
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
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
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
@ -129,7 +159,7 @@ Acceptance:
```task
id: SECRETS-WP-0003-T03
status: wait
status: done
priority: high
state_hub_task_id: "746b5e7f-cc10-43e4-b6d3-7d792d95dfeb"
```
@ -140,6 +170,27 @@ whynot-design Gitea bot package token. Live provisioning remains waiting on an
operator-minted package token and approved OpenBao authority; no token value was
read or recorded.
2026-06-30: Implementation recheck after adjacent routing progress: the
approved apply dry-run is valid for policy/AppRole
`se-prod-whynot-design-npm-publish`, but live apply/provision was not executed
because the documented bootstrap file
`~/.secrets-engine/bootstrap/prod-whynot-design.token` and package-token handoff
file `~/.secrets-engine/handoff/whynot-design-npm.token` are both absent. The
route still reports `metadata_applied: false`, `value_present: false`, and
`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
file outside any repo. Provision it with
`secrets-engine provision whynot-design-npm-publish --stage prod --field npm_token
@ -157,7 +208,7 @@ Acceptance:
```task
id: SECRETS-WP-0003-T04
status: wait
status: done
priority: high
state_hub_task_id: "36b925c2-0670-4481-95d9-1f23dcc96575"
```
@ -167,6 +218,26 @@ A real publish is still waiting on T02/T03 plus a coordinated version bump in th
external `whynot-design` repo and operator confirmation of the published package
version.
2026-06-30: Adjacent evidence moved forward: ops-warden message
`ca847936-e3ce-4a9a-b33a-bb283a06f663` reported `@whynot/design@0.4.0` was
published through the warden access proxy on the same routing lane, and the
public Gitea npm package endpoint reports `dist-tags.latest: 0.4.0`. This proves
the package-side publication exists, but it does not close this native
secrets-engine task: `secrets-engine route whynot-design-npm-publish --json`
still reports `metadata_applied: false`, `value_present: false`, and `ready:
false`, so OpenBao apply/provision plus native `secrets-engine exec` evidence
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
`secrets-engine exec --catalog whynot-design-npm-publish -- npm publish` (no
`--dry-run`). Coordinate the version bump with the whynot-design repo.
@ -183,7 +254,7 @@ Acceptance:
```task
id: SECRETS-WP-0003-T05
status: progress
status: done
priority: medium
state_hub_task_id: "461a7854-6229-4bc1-8d94-f6e2c4e5fa79"
```
@ -194,6 +265,15 @@ whynot-design pointer payload and sent State Hub message
waiting on ops-warden updating/confirming its own routing catalog so
`warden route find "npm publish whynot-design"` resolves here.
2026-06-30: Confirmed the adjacent ops-warden routing update is live. `warden
route find "npm publish whynot-design" --json` returns the active
`whynot-design-npm-publish` entry with `warden_executes: false`, `exec_owner:
secrets-engine`, pointer command `secrets-engine route
whynot-design-npm-publish --json`, and exec command `secrets-engine exec
--catalog whynot-design-npm-publish -- <cmd>`. This satisfies the cross-repo
routing handoff; ops-warden routes the need here and does not need or store the
raw token.
Coordinate with the ops-warden repo so `warden route find` points npm publish
credential needs at secrets-engine, returning the `secrets-engine route` pointer
rather than a value. This is a handoff/coordination task; the route catalog entry