Document scope alignment and warden-sign readiness

This commit is contained in:
tegwick 2026-06-30 00:52:05 +02:00
parent d8aadaffe3
commit ae685f3a0a
10 changed files with 736 additions and 41 deletions

View file

@ -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.

View file

@ -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

View file

@ -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/<role>` 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]
```

View file

@ -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]

View file

@ -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 <catalog-id> --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

View file

@ -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

View file

@ -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.

137
uv.lock generated Normal file
View file

@ -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" },
]

View file

@ -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,

View file

@ -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.