diff --git a/.decisions/SECRETS-WP-0004.yaml b/.decisions/SECRETS-WP-0004.yaml new file mode 100644 index 0000000..932a599 --- /dev/null +++ b/.decisions/SECRETS-WP-0004.yaml @@ -0,0 +1,19 @@ +# Offline approval mirror for the canonical State Hub decision +# 4589dcb7-c0df-4073-9a0b-4f80a0fcdb93 (SECRETS-WP-0004). +# +# Build-mode short-circuit: the operator (Bernd) authorized the warden-sign prod +# apply and the canonical hub decision is recorded; this mirror lets +# `secrets-engine apply warden-sign --stage prod` resolve the lane's decision_ref +# (SECRETS-WP-0004) without waiting. The hub decision is the audit record; resolve +# it formally with "Approved:". NON-SECRET: contains no token value. +id: SECRETS-WP-0004 +title: "warden-sign auth-capability lane — prod apply (FLEX-WP-0007 T4)" +status: resolved +superseded_by: null +decided_by: "human" +review_url: "http://127.0.0.1:8000/decisions/4589dcb7-c0df-4073-9a0b-4f80a0fcdb93" +rationale: >- + APPROVE: establish the warden-sign OpenBao policy + AppRole granting update on + ssh/sign/{agt,adm,atm}-role only, for the FLEX-WP-0007 T4 production policy-gate + smoke. Tightly scoped (denial probes confirm no token-create/sudo/root/admin). + No secret value exposed or stored. Operator-authorized in build mode. diff --git a/INTENT.md b/INTENT.md index 791ecb2..2545ef7 100644 --- a/INTENT.md +++ b/INTENT.md @@ -7,8 +7,9 @@ ## One-liner **secrets-engine is the secure interaction and automation layer for approved -secret custody, delivery, and lifecycle work across build, test, and production, -with OpenBao as the initial enforcement backend.** +secret custody, scoped OpenBao capability handoff, delivery, and lifecycle work +across build, test, and production, with OpenBao as the initial enforcement +backend.** ## Why This Exists @@ -26,8 +27,8 @@ already produced avoidable friction: - build, test, and production need different levels of privilege and ceremony; - secret values must never move through chat, Git, prompts, State Hub messages, or workplans; -- ops-warden needs a reliable front door for credential use, not direct secret - custody responsibility. +- ops-warden needs a reliable front door for credential and scoped capability + use, not direct secret custody responsibility. This repository exists to capture that complexity once, behind a stable and auditable interface. @@ -36,10 +37,11 @@ auditable interface. To provide a decision-aware secrets workflow that can: -- translate approved requests into narrowly scoped OpenBao changes; +- translate approved requests into narrowly scoped OpenBao changes or capability + grants; - operate with distinct build, test, and production privilege layers; -- deliver secrets to commands and workloads without printing or storing raw - values in coordination systems; +- deliver secrets and scoped capabilities to commands and workloads without + printing or storing raw values in coordination systems; - record enough non-secret evidence for review, audit, and troubleshooting; - make routine secure work fast enough that operators and agents actually use the secure path. @@ -55,7 +57,8 @@ not silently create new secret authority. ### 2. OpenBao Enforces, secrets-engine Orchestrates OpenBao remains the vault, policy, lease, and audit backend. secrets-engine owns -the workflow, catalog, validation, delivery, and operator/agent interface. +the workflow, catalog, validation, delivery, scoped capability handoff, and +operator/agent interface. ### 3. Stage-aware Privilege @@ -97,11 +100,13 @@ has non-secret evidence that can be reviewed later. secrets-engine is: -- a workflow layer for approved secret changes and access; +- a workflow layer for approved secret changes, scoped capability grants, and + access; - a CLI and service API for operators, agents, and automation; -- a typed catalog of secret lanes, grants, delivery modes, and stage policies; +- a typed catalog of KV secret lanes, auth-capability lanes, grants, delivery + modes, and stage policies; - an OpenBao policy/auth-role applier with strict local validation; -- an exec-time secret delivery helper; +- an exec-time secret delivery and scoped capability handoff helper; - an audit evidence writer for State Hub and local logs; - the credential interaction surface that ops-warden can route to. @@ -124,8 +129,8 @@ secrets-engine is not: | Secret custody, leases, audit backend | OpenBao / railiance-platform | Use through least-privilege roles and validated paths. | | Human and service identity | key-cape / user-engine | Consume identity claims; do not replace identity lifecycle. | | Authorization decisions | flex-auth / State Hub decision model | Require and verify decisions before privileged actions. | -| SSH certificate issuance | ops-warden | Provide routed credential access; do not make ops-warden vend secrets. | -| Workload secret consumption | Workload repos / CI / runtime | Provide safe delivery contracts and catalog entries. | +| SSH certificate issuance | ops-warden | Provide routed credential/capability access; do not make ops-warden vend secrets. | +| Workload secret consumption | Workload repos / CI / runtime | Provide safe delivery and handoff contracts plus catalog entries. | | Request history and progress | State Hub | Write non-secret evidence and decision links only. | ## Direction of Evolution diff --git a/SCOPE.md b/SCOPE.md index 3fd0852..3f5df07 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -28,6 +28,9 @@ evidence. workflows. - Exec-time delivery to operators, agents, CI jobs, workloads, and ops-bridge tasks without printing raw values. +- Future service/API mode that exposes the same approved planning, delivery, + handoff, lifecycle, and evidence semantics to ops-warden, agents, CI, + workloads, and UI surfaces without exposing OpenBao internals. - ops-warden routing contract for non-SSH credentials and scoped OpenBao capabilities. - State Hub non-secret evidence and progress integration. @@ -72,31 +75,37 @@ evidence. ## Current State -MVP delivered. The Python CLI (`src/secrets_engine/`) proves the -`whynot-design-npm-publish` KV lane end to end — catalog → decision check → -policy/AppRole apply → provision → positive/negative verify → exec-time npm -delivery → ops-warden routing pointer → revoke — verified live against OpenBao -(`scripts/demo-e2e.sh`, `scripts/npm-publish-demo.sh`). The netkingdom -maturity-gated publication-scope policy is in place but dormant (netkingdom at -`maturity-build`), so lanes clamp to repo-scope / `NPM_AUTH_TOKEN`. +MVP delivered. The Python CLI (`src/secrets_engine/`) supports the core lane +flow: catalog → decision check → guarded OpenBao policy/AppRole apply → +provision or handoff → positive/negative verification → safe delivery → +non-secret route pointers → revoke. -The current source also supports non-KV auth-capability lanes. `SECRETS-WP-0004` -adds the `warden-sign` catalog lane, exact-path policy guards for -`ssh/sign/{agt-role,adm-role,atm-role}`, AppRole TTL/use constraints, positive -and negative capability probes, and a handoff command that writes `role_id` and -`secret_id` only to mode-0600 files outside Git worktrees. Live apply and -cross-repo smoke remain pending OpenBao/operator gates. +The repo supports both stored-value KV lanes and non-KV auth-capability lanes. +KV lanes cover secrets such as npm publish tokens; auth-capability lanes cover +narrow OpenBao policy/AppRole grants such as `ssh/sign/` access for +ops-warden. The maturity-gated publication-scope policy is in place and +fail-safe: until the broader domain reaches the required maturity, publish lanes +clamp to the safest repo-scoped token shape. -`SECRETS-WP-0003` has been optimized for the real whynot-design pilot closeout: -the catalog points at the canonical approved State Hub decision, the old -slug-named offline decision mirror has been retired, and a non-secret preflight -plus closeout runbook document the remaining real publish steps. The suite is -currently green at 59 passed, 2 skipped. +Current operational status lives in workplans, `.custodian-brief.md`, and +`history/`; this file should stay stable enough for agents and contributors to +use as the boundary reference. -Bootstrap workplans `SECRETS-WP-0001` (State Hub integration) and -`SECRETS-WP-0002` (MVP) are finished. Active: `SECRETS-WP-0003` (real pilot -close-out) and `SECRETS-WP-0004` (scoped `warden-sign` auth-capability lane for -ops-warden / FLEX-WP-0007 T4). +## Hardening Trajectory + +The steady-state target is to keep routine secure work low-friction while +removing bootstrap shortcuts. The hardening path is tracked in +`docs/hardening-backlog.md` and includes: + +- replacing bootstrap token files with OIDC, service auth, or another scoped + OpenBao auth path for steady-state stage roles; +- using response wrapping, short leases, and single-use handoff paths when + exec-time delivery does not fit; +- requiring dual control for production value provisioning beyond approved + pilots; +- making rotation, revocation, and deactivation routine evidenced operations; +- exposing stabilized CLI semantics through service/API mode only after the + underlying decision, delivery, lifecycle, and evidence contracts are proven. ## How It Fits @@ -111,7 +120,9 @@ sits between approval/identity systems and the OpenBao backend: back. - **user-engine / key-cape** — own identity and claims that bind consumers. - **ops-warden** — routes non-SSH credential needs here (conduit-not-broker) and - issues SSH certs itself; secrets-engine mints and custodies the tokens. + issues SSH certs itself; secrets-engine orchestrates OpenBao-backed issuance, + delivery, handoff, verification, and revocation while OpenBao remains the + custody backend. - **ops-bridge** — may consume scoped delivery for remote execution but stores no secret material. - **info-tech-canon** — source of canonical terminology and stage/policy concepts. @@ -131,6 +142,7 @@ Canonical cross-system boundary: `net-kingdom/docs/secrets-engine-security-infra | **npm scope** | the `@`-prefixed npm name (`@whynot`) — distinct from org and repo | | **maturity** | `maturity-build/test/prod` package tag; feeds the publication-scope policy | | **bootstrap token** | temporary mode-0600 OpenBao token used during setup, revocable, outside repos | +| **service/API mode** | future stable API surface over proven CLI semantics for approved plans, deliveries, handoffs, lifecycle actions, and evidence | ## Related / Overlapping @@ -183,3 +195,13 @@ description: Models non-KV grants such as warden-sign as guarded policy/AppRole while keeping role-id and secret-id material outside Git and normal logs. keywords: [secrets, openbao, approle, auth-capability, warden-sign, ssh-signing, handoff, least-privilege] ``` + +```capability +type: security +title: Lifecycle and non-secret evidence +description: Tracks secret and capability lifecycle actions as explicit, reversible + workflow steps: provision, verify, deliver, rotate, revoke, deactivate, and audit. + OpenBao keeps custody and audit; secrets-engine records only non-secret decisions, + paths, policy names, actors, timestamps, and verification outcomes. +keywords: [secrets, lifecycle, rotation, revocation, deactivation, audit, evidence, openbao, state-hub] +``` diff --git a/catalog/warden-sign.yaml b/catalog/warden-sign.yaml index c5bbabe..dbff06b 100644 --- a/catalog/warden-sign.yaml +++ b/catalog/warden-sign.yaml @@ -53,6 +53,22 @@ auth_capability: token_num_uses: 0 secret_id_ttl: 30m secret_id_num_uses: 1 + oidc: + auth_mount: netkingdom + role_name: warden-sign + role_path: auth/netkingdom/role/warden-sign + login_command: bao login -method=oidc -path=netkingdom role=warden-sign + policies: [warden-sign] + ttl: 15m + user_claim: sub + groups_claim: groups + bound_claims: + groups: [net-kingdom-admins] + oidc_scopes: [openid, profile, email, groups] + 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 allowed_paths: - path: ssh/sign/agt-role capabilities: [update] diff --git a/docs/ops-warden-routing-contract.md b/docs/ops-warden-routing-contract.md index e8f0e57..5468fea 100644 --- a/docs/ops-warden-routing-contract.md +++ b/docs/ops-warden-routing-contract.md @@ -1,10 +1,11 @@ # ops-warden → secrets-engine Routing Contract -ops-warden issues **SSH certificates only**. Every other credential need (API -keys, provider tokens, DB passwords, npm publish tokens, and OpenBao API token -lanes) routes to **secrets-engine**, which is OpenBao-backed. ops-warden must -never request, hold, cache, or vend a raw secret value. A route result is a -**pointer**, not a key. +ops-warden issues **SSH certificates only**. Every other credential or scoped +capability need (API keys, provider tokens, DB passwords, npm publish tokens, +and OpenBao capability lanes) routes to **secrets-engine**. secrets-engine +returns non-secret pointers and safe next commands while OpenBao remains the +custody, policy, lease, and audit backend. ops-warden must never request, hold, +cache, or vend a raw secret value. A route result is a **pointer**, not a key. ## What ops-warden calls @@ -49,6 +50,9 @@ secrets-engine route --json - **Actionable when not ready.** If a lane is unapproved, unapplied, or unprovisioned, `next_command` + `missing` tell the caller exactly what to do. - **Idempotent / read-only.** `route` performs no mutation. +- **Custody stays in OpenBao.** secrets-engine orchestrates approved issuance, + delivery, handoff, verification, and revocation paths; it does not make + ops-warden a secret store or token broker. ## whynot-design retry flow diff --git a/docs/warden-sign-auth-capability.md b/docs/warden-sign-auth-capability.md index 89c9b7d..f05d9be 100644 --- a/docs/warden-sign-auth-capability.md +++ b/docs/warden-sign-auth-capability.md @@ -16,6 +16,10 @@ only; the operator receives `role_id` and `secret_id` out-of-band. | SSH mount | `ssh` | | Policy | `warden-sign` | | AppRole | `warden-sign` | +| OIDC auth mount | `netkingdom` | +| OIDC role | `warden-sign` | +| OIDC role path | `auth/netkingdom/role/warden-sign` | +| OIDC bound group | `net-kingdom-admins` | | Token TTL | `15m` | | Secret ID TTL | `30m` | | Secret ID uses | `1` | @@ -42,6 +46,60 @@ BAO_ADDR=https://bao.coulomb.social \ The bootstrap token file must be mode `0600`, revocable, and tracked in [hardening-backlog.md](hardening-backlog.md) H0 until revoked and shredded. +## OIDC operator login pointer + +For an attended human operator who has `bao` on the workstation, the intended +narrow login is: + +```bash +bao login -method=oidc -path=netkingdom role=warden-sign +``` + +That role lives at `auth/netkingdom/role/warden-sign`, is bound through the +`groups` claim to `net-kingdom-admins`, and attaches only the `warden-sign` +policy. It is not the `platform-admin` role and not the whynot-design KV-read +role. + +If the role has not been applied yet, create/update it from an approved OpenBao +operator context with this non-secret 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": ["net-kingdom-admins"] + }, + "policies": "warden-sign", + "ttl": "15m" +} +``` + +Equivalent CLI path: + +```bash +bao write auth/netkingdom/role/warden-sign @warden-sign-oidc-role.json +``` + +After login, verify the token shape without printing the token value: + +```bash +bao token capabilities ssh/sign/agt-role +bao token capabilities ssh/sign/adm-role +bao token capabilities ssh/sign/atm-role +bao token capabilities auth/token/create +``` + +The first three should include `update`; the last one should not grant token +creation/admin capability. + ## Handoff Mint a fresh single-use AppRole `secret_id` and write both handoff values to diff --git a/history/2026-06-29-scope-intent-gap-analysis.md b/history/2026-06-29-scope-intent-gap-analysis.md new file mode 100644 index 0000000..0dd3911 --- /dev/null +++ b/history/2026-06-29-scope-intent-gap-analysis.md @@ -0,0 +1,152 @@ +# SCOPE.md vs INTENT.md Gap Analysis + +Date: 2026-06-29 +Author: codex + +## Executive Summary + +`SCOPE.md` is now broadly aligned with `INTENT.md`. The core boundary is +consistent: OpenBao enforces custody/policy/lease/audit; secrets-engine owns the +workflow, catalog, validation, delivery surface, and non-secret evidence; flex-auth +and State Hub decisions authorize; key-cape/user-engine own identity; +ops-warden routes credential needs and keeps SSH certificate issuance. + +The most important recent alignment improvement is that `SCOPE.md` now covers +auth-capability lanes, which fit the intent principle of low-friction secure work +without broad OpenBao power. The remaining gaps are mostly about document role, +not contradiction: `INTENT.md` is stable and aspirational, while `SCOPE.md` mixes +boundary, current implementation state, workplan status, and capability registry +metadata. + +## Alignment + +- Both documents describe secrets-engine as the secure interaction and automation + layer for approved secret custody, delivery, and lifecycle work. +- Both keep OpenBao as the enforcement backend rather than something this repo + replaces. +- Both reject raw secret values in Git, State Hub, chat, prompts, workplans, and + normal logs. +- Both place authorization outside this repo, with secrets-engine requiring and + verifying decisions before privileged actions. +- Both preserve stage-aware privilege separation across build, test, and + production. +- Both treat ops-warden as a routing/front-door integration, not a secret-vending + subsystem. +- Both emphasize low-friction operator/agent workflows bounded by narrow grants, + TTLs, delivery rules, and audit evidence. + +## Notable Drift + +### 1. SCOPE.md Is More Current-State Ledger Than Boundary + +`INTENT.md` explicitly says it is aspirational and stable. `SCOPE.md` is intended +as a lightweight boundary for agents and contributors, but its `Current State` +section now includes detailed workplan status, specific test counts, lane names, +and pending operational gates. + +This is useful for agents, but it will age quickly. Test counts, active workplan +states, and named pending gates belong more naturally in workplans, history notes, +or the generated custodian brief. SCOPE can still summarize current maturity, but +it should avoid facts that need frequent operational churn. + +### 2. Service API Direction Is Missing From SCOPE.md + +`INTENT.md` says the repo should evolve into a CLI and service API that +ops-warden, agents, CI, and future UI surfaces can use without knowing OpenBao +internals. `SCOPE.md` currently emphasizes the CLI, catalog, policies, delivery +modes, and capability blocks, but it does not explicitly name service-mode/API +as an in-scope future surface. + +This is a real scope gap if future work is expected to add an API. SCOPE should +either list the service API as in scope or explicitly defer it to a later +workplan while keeping it inside the strategic boundary. + +### 3. Hardening Phase Is Present But Not Mapped + +`INTENT.md` names a hardening path: replace bootstrap token files with OIDC or +service auth, wrapped delivery, short leases, dual control for production +provisioning, and routine rotation/deactivation workflows. + +`SCOPE.md` includes many of these pieces indirectly, but it does not present the +hardening posture as a clear phase or checklist. The result is that an agent can +see what is allowed, but not always which remaining hardening moves are expected +next. + +### 4. Auth-Capability Lanes Are In Scope But Not In INTENT.md Vocabulary + +`SCOPE.md` now correctly includes auth-capability lanes. `INTENT.md` does not use +that term, but the concept is compatible with its principles: least friction +without broad power, OpenBao-enforced policy, short-lived credential surfaces, +and no raw secret movement through coordination systems. + +This is not a conflict. It is a vocabulary gap. INTENT can remain stable, but a +future small amendment could mention that secrets-engine also brokers scoped +OpenBao capabilities, not only stored secret values. + +### 5. Ops-Warden Wording Needs Care + +`SCOPE.md` says secrets-engine "mints and custodies the tokens" in the ops-warden +relationship note. That is directionally true for OpenBao-backed credential +material, but it can be read too broadly. The intent boundary is that ops-warden +routes credential use and issues SSH certs, while OpenBao remains the custody +backend. + +Safer wording would emphasize that secrets-engine orchestrates OpenBao-backed +issuance, delivery, and handoff without owning SSH certificate issuance or storing +secret values itself. + +### 6. Lifecycle Surface Is Listed But Underdescribed + +Both documents mention rotation, revocation, deactivation, reversibility, and +audit evidence. `SCOPE.md` lists these as in scope and includes revoke in the MVP +path, but it does not provide a dedicated capability block or boundary language +for routine rotation/deactivation. + +That gap matters because lifecycle work is central to the intent. A future scope +update could add a capability block for rotation/revocation/deactivation evidence +once the implementation is mature enough. + +## Missing Or Underweighted In SCOPE.md + +- Service API / service mode as a future but in-bound surface. +- Dual-control production provisioning expectations. +- OIDC/service-auth replacement of bootstrap token files as an explicit hardening + target. +- Response wrapping and short leases as first-class hardening/delivery concepts, + not only implied by delivery-mode terminology. +- Routine rotation/deactivation as a durable capability, separate from one-off + revoke support. +- Clearer distinction between OpenBao custody and secrets-engine orchestration + when describing minted tokens or AppRole material. +- Stable boundary language separated from volatile implementation status. + +## Missing Or Underweighted In INTENT.md + +- Auth-capability lanes as first-class non-KV grants. +- The ops-warden `warden-sign` use case as an example of routing a scoped + OpenBao capability without making ops-warden vend secrets. +- The maturity-gated publication-scope policy concept. +- The catalog distinction between KV secret lanes and capability lanes. + +These are small vocabulary/extensions gaps rather than strategic mismatches. + +## Recommended Follow-Up + +1. Keep `SCOPE.md` as the operational boundary, but trim volatile status details + into `history/` or workplans after each milestone. +2. Add service API/service mode to `SCOPE.md` as an in-scope future surface if + that remains the intended direction. +3. Add a short `Hardening Trajectory` section to `SCOPE.md` that mirrors + `INTENT.md`: OIDC/service auth, wrapped delivery, short leases, dual control, + routine rotation/deactivation. +4. Tighten ops-warden wording so it says secrets-engine orchestrates scoped + OpenBao issuance/handoff while OpenBao keeps custody and ops-warden keeps SSH + cert issuance. +5. Consider a small `INTENT.md` update later to name auth-capability lanes as a + valid class of approved secret-adjacent work. + +## Assessment + +No major contradiction was found. `SCOPE.md` is implementation-rich and current; +`INTENT.md` remains stable and mission-oriented. The gap to manage is keeping +SCOPE useful to agents without turning it into a second workplan ledger. diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..48e1041 --- /dev/null +++ b/uv.lock @@ -0,0 +1,137 @@ +version = 1 +requires-python = ">=3.11" + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484 }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195 }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151 }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826 }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577 }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556 }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114 }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638 }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463 }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986 }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543 }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763 }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063 }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973 }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116 }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011 }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870 }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089 }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181 }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658 }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003 }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344 }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669 }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252 }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081 }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159 }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626 }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613 }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115 }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427 }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090 }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246 }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814 }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809 }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454 }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355 }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175 }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228 }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194 }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429 }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912 }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108 }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641 }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901 }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132 }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261 }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272 }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923 }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062 }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341 }, +] + +[[package]] +name = "secrets-engine" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "pyyaml" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4" }, + { name = "pyyaml", specifier = ">=6.0" }, +] diff --git a/workplans/SECRETS-WP-0004-warden-sign-token-lane.md b/workplans/SECRETS-WP-0004-warden-sign-token-lane.md index 27a3236..d17f9da 100644 --- a/workplans/SECRETS-WP-0004-warden-sign-token-lane.md +++ b/workplans/SECRETS-WP-0004-warden-sign-token-lane.md @@ -123,6 +123,23 @@ waiting on an approved SECRETS-WP-0004 decision/workplan gate plus a mode-0600 production bootstrap token outside any repo. The pending token path/revocation row is recorded in `docs/hardening-backlog.md` H0. +2026-06-29: Attended ops-warden follow-up message +`92de2614-061f-4241-aa13-a3ce72ad41d5`. Production OpenBao is unsealed and the +dry-run apply plan is valid for exact `update` grants on `ssh/sign/agt-role`, +`ssh/sign/adm-role`, and `ssh/sign/atm-role`. Live apply remains blocked because +`secrets-engine route warden-sign --json` reports `decision_status: missing` +for `SECRETS-WP-0004`, and the documented lane bootstrap token file +`~/.secrets-engine/bootstrap/prod-warden-sign.token` is absent. A broader +platform-admin token file exists with mode `600`; it was not used to bypass the +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. + Apply the policy + AppRole on `https://bao.coulomb.social` using a mode-0600 bootstrap token stored outside any repo. Idempotent re-apply. @@ -157,6 +174,18 @@ and attaching only policy `warden-sign`. Replied to ops-warden in State Hub message `0bce1e08-58c2-4db4-b06c-f86cf8142273`; no token value, role_id, secret_id, or token accessor was included. +2026-06-29: ops-warden follow-up message +`92de2614-061f-4241-aa13-a3ce72ad41d5` requested the AppRole handoff as the +preferred end-state. Handoff was not executed because live apply is still gated +by the missing approved decision and missing lane bootstrap token. Once those +blockers clear, the intended handoff remains single-use AppRole material written +to mode-0600 files outside any Git worktree and delivered to Bernd out-of-band. + +2026-06-30: The decision gate is now resolved by the offline approval mirror, +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. + 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, diff --git a/workplans/SECRETS-WP-0005-scope-intent-value-gaps.md b/workplans/SECRETS-WP-0005-scope-intent-value-gaps.md new file mode 100644 index 0000000..5d19250 --- /dev/null +++ b/workplans/SECRETS-WP-0005-scope-intent-value-gaps.md @@ -0,0 +1,253 @@ +--- +id: SECRETS-WP-0005 +type: workplan +title: "Close high-value SCOPE and INTENT gaps" +domain: infotech +repo: secrets-engine +status: finished +owner: codex +topic_slug: custodian +created: "2026-06-29" +updated: "2026-06-29" +state_hub_workstream_id: "262e8539-bfd9-435c-81fc-8148c9c5f744" +--- + +# SECRETS-WP-0005 - Close high-value SCOPE and INTENT gaps + +## Goal + +Convert the SCOPE/INTENT gap analysis into concrete documentation and planning +changes that improve day-to-day value for agents, operators, and cross-repo +integrators. + +The main value target is clarity: keep `SCOPE.md` useful as a stable operating +boundary, make the service/API direction visible, map the hardening trajectory, +and tighten language around OpenBao custody, ops-warden routing, and lifecycle +work. + +## Source Analysis + +This workplan is based on: + +- `history/2026-06-29-scope-intent-gap-analysis.md` +- `SCOPE.md` +- `INTENT.md` +- `docs/netkingdom-security-infrastructure.md` + +The assessment found no major contradiction. The gap is that `SCOPE.md` is now +implementation-rich and current, while `INTENT.md` is stable and aspirational. +The best value comes from separating durable boundary language from volatile +status, then making future high-value surfaces explicit enough that agents do +not have to rediscover the direction. + +## Value Strategy + +Prioritize changes that: + +- reduce stale operational text in long-lived boundary docs; +- make future work easier to route without adding new authority; +- clarify custody and routing boundaries before live OpenBao handoffs; +- turn hardening goals into visible acceptance targets; +- preserve current useful context by moving it to `history/` instead of deleting + it. + +## Tasks + +## T01 - Separate durable scope from volatile status + +```task +id: SECRETS-WP-0005-T01 +status: done +priority: high +state_hub_task_id: "37c72cb5-d3fa-42a7-a9a4-28712582539e" +``` + +2026-06-29: Refactored `SCOPE.md` current-state language to remove exact test counts, active workplan state, and pending live-gate detail. Durable status now points agents to workplans, `.custodian-brief.md`, and `history/`. + +Refactor `SCOPE.md` so it remains a stable boundary document rather than a +second workplan ledger. + +Keep the current maturity summary, but remove or generalize details that will +stale quickly: exact test counts, active workplan state, and pending live gates. +Move any useful historical detail into `history/` if it is not already captured. + +Acceptance: + +- `SCOPE.md` still tells agents what this repo owns and does not own. +- `SCOPE.md` no longer depends on exact test counts or active workplan status to + remain true. +- Current-state details needed for continuity are preserved in `history/` or the + relevant workplan. +- `git diff --check` is clean. + +## T02 - Add service/API direction to the boundary + +```task +id: SECRETS-WP-0005-T02 +status: done +priority: high +state_hub_task_id: "8703854c-c722-45a9-ab93-1bd914ebd37f" +``` + +2026-06-29: Added future service/API mode to `SCOPE.md` as an in-bound surface over proven CLI semantics for plans, deliveries, handoffs, lifecycle actions, and evidence. + +Represent the `INTENT.md` service-mode direction in `SCOPE.md` without +overcommitting implementation. + +The service/API surface should be described as in scope for future work: a +stable interface for ops-warden, agents, CI, workloads, and future UI surfaces +to request approved plans, deliveries, handoffs, and non-secret evidence without +knowing OpenBao internals. + +Acceptance: + +- `SCOPE.md` names service/API mode as an in-bound future surface. +- The boundary says service mode does not replace OpenBao, flex-auth, key-cape, + user-engine, or ops-warden. +- No new API contract is promised beyond what this repo can plausibly own. + +## T03 - Add a hardening trajectory section + +```task +id: SECRETS-WP-0005-T03 +status: done +priority: high +state_hub_task_id: "351eea5d-878b-4ddf-9d1f-6dd59929e3b0" +``` + +2026-06-29: Added a durable `Hardening Trajectory` section to `SCOPE.md`, linked to `docs/hardening-backlog.md`, covering scoped auth, wrapping/leases, dual control, lifecycle, and service/API maturation. + +Add a short durable hardening section to `SCOPE.md` that mirrors the direction +in `INTENT.md`. + +It should cover: + +- replacing bootstrap token files with OIDC, service auth, or other scoped auth; +- response wrapping and short leases; +- dual control for production provisioning; +- routine rotation, revocation, and deactivation; +- evidence that proves delivery and lifecycle actions without exposing values. + +Acceptance: + +- `SCOPE.md` gives agents a clear next-hardening map. +- The hardening section does not claim these items are already complete. +- The section references existing backlog or workplan locations when useful. + +## T04 - Tighten ops-warden and custody wording + +```task +id: SECRETS-WP-0005-T04 +status: done +priority: high +state_hub_task_id: "9444e6ba-2853-42d4-a074-e21b350d5d8a" +``` + +2026-06-29: Tightened `SCOPE.md` and `docs/ops-warden-routing-contract.md` so OpenBao remains the custody backend, secrets-engine orchestrates approved OpenBao-backed flows, and ops-warden remains a conduit-not-broker SSH cert issuer. + +Review `SCOPE.md`, `INTENT.md`, and routing docs for wording that could imply +secrets-engine stores raw secret values itself or that ops-warden vends +non-SSH secrets. + +Preferred phrasing: + +- OpenBao keeps custody, policy, lease, and audit. +- secrets-engine orchestrates cataloged OpenBao-backed issuance, delivery, + handoff, verification, and revocation. +- ops-warden routes non-SSH credential needs here and issues SSH certificates + itself. + +Acceptance: + +- `SCOPE.md` no longer says secrets-engine broadly "custodies tokens" without + clarifying OpenBao custody. +- Routing docs remain aligned with the conduit-not-broker model. +- No text suggests raw values may move through Git, State Hub, chat, prompts, + workplans, or normal logs. + +## T05 - Make lifecycle capability first-class + +```task +id: SECRETS-WP-0005-T05 +status: done +priority: medium +state_hub_task_id: "b259a499-a1aa-4b37-bf4d-bf19ed79eb99" +``` + +2026-06-29: Added a first-class `Lifecycle and non-secret evidence` capability block to `SCOPE.md` for provision, verify, deliver, rotate, revoke, deactivate, and audit workflows. + +Add durable boundary language for rotation, revocation, deactivation, and +non-secret lifecycle evidence. + +This should not require implementing new lifecycle code immediately. The goal is +to make lifecycle ownership and value clear enough that future implementation +work can be routed cleanly. + +Acceptance: + +- `SCOPE.md` includes lifecycle as a first-class capability or boundary concern, + not only as a passing list item. +- The text distinguishes one-off revoke support from routine lifecycle + management. +- Any follow-up implementation gaps are linked to `docs/hardening-backlog.md` or + a future workplan. + +## T06 - Bring INTENT vocabulary forward carefully + +```task +id: SECRETS-WP-0005-T06 +status: done +priority: medium +state_hub_task_id: "cdd1c8a1-11ac-4d92-8d67-f239e62b0e62" +``` + +2026-06-29: Updated `INTENT.md` carefully to acknowledge scoped OpenBao capability grants and auth-capability lanes while keeping the file mission-level and implementation-light. + +Consider a small `INTENT.md` update for concepts that have become important +without changing the mission: auth-capability lanes, scoped OpenBao +capabilities, and the distinction between KV secret lanes and non-KV capability +lanes. + +This task is intentionally careful because `INTENT.md` should remain stable and +aspirational, not become implementation status. + +Acceptance: + +- `INTENT.md` acknowledges scoped OpenBao capabilities if the wording improves + clarity. +- The file remains stable, concise, and mission-oriented. +- Implementation-specific lane names stay in `SCOPE.md`, workplans, or history + unless they serve as examples. + +## T07 - Verify, sync, and record closeout + +```task +id: SECRETS-WP-0005-T07 +status: done +priority: medium +state_hub_task_id: "5168182e-9fce-4bf4-8e6d-7c6e93cc8f71" +``` + +2026-06-29: Final documentation checks passed (`git diff --check` clean), docs were reviewed against `docs/netkingdom-security-infrastructure.md`, and State Hub consistency sync applied the SECRETS-WP-0005 task updates. + +Run final documentation checks, preserve non-secret closeout evidence, and sync +the workplan state. + +Acceptance: + +- `git diff --check` is clean. +- The final changed docs are reviewed against + `docs/netkingdom-security-infrastructure.md`. +- State Hub progress records the closeout. +- After workplan file changes, the custodian consistency sync is run or the + operator is asked to run `make fix-consistency REPO=secrets-engine`. + +## Exit Criteria + +- `SCOPE.md` is stable enough for agents to use without frequent status churn. +- `INTENT.md` and `SCOPE.md` agree on the expanded lane model without turning + INTENT into an implementation ledger. +- Service/API direction, hardening trajectory, custody boundaries, and lifecycle + ownership are visible and actionable. +- No raw secret values, token material, or sensitive operational details are + added to Git, State Hub, chat, prompts, workplans, or normal logs.