diff --git a/SCOPE.md b/SCOPE.md index 3f5df07..45efdda 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -1,207 +1,244 @@ # SCOPE -> Lightweight boundary for agents and contributors. +> Implemented capability boundary for agents and contributors. Aspirational +> direction belongs in `INTENT.md`; current work and operational gates belong in +> `workplans/`. ## One-liner -secrets-engine is the workflow and automation interface for approved secret -custody, auth-capability handoff, delivery, and lifecycle work across build, -test, and production, with OpenBao as the enforcement backend. +secrets-engine is a decision-gated Python CLI that validates non-secret secret +lane metadata and orchestrates narrowly scoped OpenBao policy, AppRole, +provisioning, verification, delivery, routing, handoff, and revocation actions. -## Core Idea +It is an OpenBao workflow client, not a vault, authorization service, identity +provider, credential broker, or general secrets API. -OpenBao is the vault. secrets-engine is the day-to-day interaction layer that -connects cataloged secret lanes, scoped auth-capability lanes, approval -decisions, stage-specific OpenBao roles, safe delivery modes, and non-secret -evidence. +## Implemented Capabilities -## In Scope +### Catalog and validation -- Non-secret catalog of secret lanes, grants, consumers, stages, and delivery - modes. -- Non-secret catalog of scoped OpenBao auth capabilities where the protected - material is a narrow policy/AppRole grant rather than a KV value. -- Decision-aware planning and apply flows for OpenBao policies, auth roles, and - metadata. -- Build, test, and production privilege separation. -- Safe provisioning, verification, rotation, revocation, and deactivation - 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. -- Canonicalization of terms with info-tech-canon. +- Loads YAML catalog entries for `kv` and `auth-capability` lanes. +- Models `build`, `test`, and `prod` stages, exact mounts/paths/fields, + consumers, approvals, delivery modes, verification, lifecycle ownership, + workload-delivery metadata, and `standard`/`high` risk. +- Distinguishes engine-managed and existing KV mounts, and engine-managed, + existing, or absent native delivery auth. +- Rejects malformed entries, inline secret-looking values, wildcard paths, + unsupported modes, bootstrap-only approval for high-risk lanes, and high-risk + entries without rotation/deactivation owners. +- Records existing ESO/Kubernetes/OIDC workload delivery as metadata only; it + does not operate those delivery systems. -## Out of Scope +### Decision-gated planning and OpenBao metadata apply -- Replacing OpenBao as custody, policy, lease, or audit backend. -- Replacing flex-auth authorization decisions. -- Replacing user-engine/key-cape identity and claim lifecycle. -- Issuing SSH certificates, which remains ops-warden responsibility. -- Owning tunnels or remote transport, which remains ops-bridge responsibility. -- Storing raw secret values in this repo, State Hub, chat, prompts, or logs. -- Broad platform-root or platform-admin automation as a steady-state model. -- Handing broad OpenBao tokens to another subsystem when a narrower - cataloged capability can satisfy the request. +- Resolves a catalog lane by catalog id or `approval.decision_ref`. +- Resolves an approval from State Hub by id, with tracked local YAML mirrors as + a pilot/offline fallback. +- Fails privileged live commands closed when a required decision is missing, + unapproved, or superseded. Plans and `apply --dry-run` remain non-mutating. +- Renders guarded OpenBao plans for exact consumer ACL policies and AppRoles. +- Applies policy and AppRole metadata idempotently. Existing mounts render a + non-mutating check and are never created by apply. +- Rejects stage mismatches, wildcard paths, broad-admin names, forbidden + `sys/`, token, identity, root, or sudo semantics, and auth-capability paths + outside an exact allowlist. -## Relevant When +### KV provisioning -- An approved decision needs to become a narrow OpenBao policy/auth-role apply - without platform-root hand-typing. -- A workload or operator command needs a secret delivered **into the command** - without printing or exporting it (e.g. `npm publish`). -- A non-SSH credential need (API key, provider token, npm token, DB password, - scoped OpenBao token) is routed here by ops-warden. -- ops-warden needs an approved, narrow OpenBao capability such as - `ssh/sign/` access for its own SSH certificate flow, without receiving a - broad platform-root token. -- Build/test/production need different privilege, ceremony, and delivery rules - for the same kind of secret. -- A reviewer needs non-secret evidence of who applied/provisioned/verified what. +- Imports one declared field from a mode-0600 file outside Git worktrees. +- Generates random values only for non-production lanes. +- Keeps values out of CLI output and evidence records. -## Not Relevant When +This is a bootstrap/pilot primitive, not a safe general updater for existing +multi-field production paths. The current adapter invokes `bao kv put` with one +field and can replace sibling fields at that KV path; it also places the value +in the local `bao` subprocess argument vector. Do not use it for the admitted +shared multi-field lanes until merge-safe, non-argv provisioning is implemented. -- You need an **SSH certificate** (→ ops-warden `warden sign`). -- You need an **authorization decision** (→ flex-auth). -- You need **identity / OIDC / MFA / claim lifecycle** (→ user-engine / key-cape). -- You need a **tunnel** or remote transport (→ ops-bridge). -- You want OpenBao itself replaced as the custody/lease/audit backend (it is not). -- You want a raw secret value moved through Git, State Hub, chat, prompts, or logs - (never — delivery is exec-time or out-of-band only). +### Verification -## Current State +- KV positive verification logs in through the lane AppRole and reports whether + one declared field is present, without printing the field value. +- KV negative verification checks that a fixed invalid token cannot read the + path. +- Auth-capability verification checks the AppRole token's capabilities on exact + allowlisted and denial-probe paths. -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. +These are bounded policy/presence probes. They do not yet prove denial for a +real unrelated workload identity, validate every field by default, exercise a +provider operation, or produce OpenBao audit-request correlation. -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. +### Exec-time delivery -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. +- `exec-env` fetches one declared field through the lane AppRole and injects it + into a child process environment. +- `npm-config` creates a temporary mode-0600 npm config containing an environment + reference rather than the token, injects the value only into the child, and + deletes the config afterward. +- Child stdout and stderr are combined and streamed through token-pattern and + exact-value redaction. +- Undeclared fields and undeclared/unsupported exec modes are rejected before + value fetch. -## Hardening Trajectory +The OpenBao KV response is parsed in the parent process, so every field stored +at the path crosses that process boundary even though only the selected field is +injected. Scoped AppRole tokens rely on configured TTL/use limits; exec and +verification do not explicitly revoke them after use. -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: +### Auth-capability handoff -- 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. +- Models narrow non-KV AppRole grants such as exact `ssh/sign/` update + capability. +- Mints `role_id`/`secret_id` material only after approval and writes it to + distinct mode-0600 files outside Git worktrees without printing the + `secret_id`. -## How It Fits +The cataloged standalone `warden-sign` AppRole is currently parked by governance +and must not be applied as a break-glass or recovery path. OpenBao being sealed +cannot be recovered through that AppRole. -secrets-engine is the **interaction layer** in the NetKingdom security stack. It -sits between approval/identity systems and the OpenBao backend: +### Routing and evidence -- **OpenBao / railiance-platform** — enforces custody, policy, lease, audit. - secrets-engine drives it through least-privilege stage roles and validated - paths, never as root. -- **flex-auth / State Hub decisions** — authorize. secrets-engine requires and - verifies a decision before privileged action and writes non-secret evidence - 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 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. +- `route` returns a non-secret pointer containing lane ownership, decision + status, metadata/value-presence booleans, readiness, and a safe next command. +- Records scrubbed local JSONL evidence and posts a minimal State Hub progress + event on a best-effort basis. +- Keeps OpenBao audit logs as the backend source of truth. -Canonical cross-system boundary: `net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`. +Route readiness checks only the first declared KV field, and State Hub evidence +delivery is not durable or transactional. Treat route output as operational +guidance, not complete attestation for multi-field or high-risk lanes. -## Terminology +### Revocation currently available -| Term | Meaning | -| --- | --- | -| **lane / catalog id** | a non-secret entry describing a KV secret or auth capability, its OpenBao location, consumers, delivery, and approval | -| **auth-capability lane** | a catalog lane whose protected material is a narrow OpenBao policy/AppRole capability, not a stored KV value | -| **stage** | `build` / `test` / `prod` — separate OpenBao privilege contexts | -| **stage role** | `secrets-engine-{build,test,prod}` OpenBao role, confined to its prefix | -| **delivery mode** | how material leaves OpenBao: `exec-env`, `npm-config`, `read-check`, `wrapped`, `approle-login` | -| **org / repo** | Gitea organisation (`coulomb`) / repository (`whynot-design`) — explicit, not the overloaded "project" | -| **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 | +- For `auth-capability` lanes, live `revoke` deletes the AppRole and policy. +- For KV lanes, live `revoke` deletes all KV metadata/versions at the path. -## Related / Overlapping +KV revoke is destructive decommissioning, not soft deactivation: it currently +leaves the KV lane's consumer AppRole and policy in place. There is no general +lease/accessor revoke, rotation command, compromised state, or reversible lane +state machine. -- **ops-warden** — front door / SSH cert issuer; routes non-SSH needs here. -- **OpenBao (railiance-platform)** — the custody/policy/lease/audit backend. -- **flex-auth** — authorization decisions secrets-engine depends on. -- **user-engine / key-cape** — identity and claim lifecycle for consumers. -- **ops-bridge** — remote transport; may consume scoped delivery. -- **net-kingdom** — owns the cross-system security-infrastructure boundary doc. -- **info-tech-canon** — canonical terminology source. +## CLI Surface + +```text +secrets-engine catalog list|show +secrets-engine decision inspect +secrets-engine plan +secrets-engine apply [--dry-run] +secrets-engine provision +secrets-engine verify +secrets-engine handoff +secrets-engine exec +secrets-engine policy publication +secrets-engine route +secrets-engine revoke [--dry-run] +``` + +The implemented exec adapters are `exec-env` and `npm-config`. `read-check` is +verification, `approle-login` is auth-capability handoff metadata, and +`exec-file`/`wrapped` are reserved schema names without executable adapters. + +## Proven Operationally + +- The whynot-design npm pilot completed a real publish through native + `secrets-engine exec` without placing the token in the parent shell. +- Throwaway OpenBao integration tests exercise plan, apply, provisioning, + positive/negative verification, exec delivery, routing, revocation, and + idempotent metadata apply. +- Five existing high-risk `platform` mount lanes have reviewed catalog metadata + and guarded dry-run plans. Their native AppRoles are not live: workplan + `SECRETS-WP-0006` waits on per-lane approval, production authority, live + positive/negative verification, and routing cutover. + +## Not Implemented + +- A service API, daemon, UI, queue, scheduler, or remote multi-user service. +- OpenBao OIDC/service-auth login for steady-state secrets-engine operation. +- Native `exec-file` or response-wrapped delivery. +- Merge-safe multi-field KV updates or provider-side rotation. +- First-class rotate, compromise, suspend, reactivate, lease-status, or audit + report commands. +- Dual-control enforcement beyond accepting the catalog label. +- Direct flex-auth evaluation, claim validation, or identity authentication. +- Runtime tenancy isolation; `org`, `repo`, consumers, and stages are catalog + metadata plus local path/policy guards, not a tenant control plane. +- Management or health verification of ESO, Kubernetes Secrets, deployments, + provider accounts, SSH issuance, tunnels, or remote transport. +- Any backend other than the local `bao`/`vault` CLI speaking to OpenBao. + +## System Boundary + +- **OpenBao / railiance-platform** owns custody, policy enforcement, leases, and + audit. secrets-engine invokes it through supplied credentials. +- **flex-auth / State Hub decisions** own authorization. secrets-engine only + resolves and enforces recorded decision status. +- **user-engine / key-cape** own identity, OIDC, MFA, and claims. +- **ops-warden** issues SSH certificates and routes non-SSH credential needs; it + does not vend their values. +- **ops-bridge** owns tunnels and remote execution transport and may consume a + scoped delivery path. +- **workload/platform repositories** own ESO/Kubernetes delivery, provider + rotation, and application health. +- **info-tech-canon / net-kingdom** own canonical terminology and the + cross-system security boundary. + +Canonical boundary: +`net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`. + +## Security Rules + +- Never place raw secret values in Git, State Hub, chat, prompts, workplans, + normal logs, or evidence. +- Never treat catalog admission, a dry-run, or an old workload CCR as approval + for a new production auth surface. +- Never mutate an existing shared mount or replace workload delivery by + implication. +- Never use current single-field provisioning on a shared multi-field path. +- Never call KV `revoke` unless destructive deletion of all path versions is the + explicitly approved intent. +- Keep bootstrap and handoff material outside repositories with mode 0600 and + explicit expiry/revocation handling. + +## Where Current Work Lives + +- `workplans/` is the source of truth for open work and operational gates. +- `docs/hardening-backlog.md` tracks exit from bootstrap mode. +- `history/` contains dated capability and intent assessments. +- `INTENT.md` remains the stable aspirational direction. ## Provided Capabilities ```capability type: security -title: Decision-aware OpenBao policy/role apply -description: Turns an approved State Hub decision into a narrow, guarded OpenBao apply — - catalog lane to dry-run plan to idempotent ACL policy + AppRole write — through - least-privilege build/test/prod stage roles. Refuses unapproved, superseded, wildcard, - out-of-stage, or broad-admin plans before any backend call. Writes non-secret evidence. -keywords: [secrets, openbao, vault, policy, approle, catalog, decision, stage, least-privilege, netkingdom] +title: Guarded OpenBao lane planning and metadata apply +description: Validates cataloged KV and auth-capability lanes, renders exact policy/AppRole plans, + and applies approved metadata while rejecting missing decisions, stage mismatches, wildcards, + broad-admin names, and forbidden capability paths. Existing mounts are check-only. +keywords: [secrets, openbao, policy, approle, catalog, decision, stage, least-privilege] ``` ```capability type: security -title: Exec-time secret delivery -description: Delivers a secret into a child process only — never printing, exporting, or - persisting the value. npm-config injects a temporary mode-0600 .npmrc pointing at the - configured registry; exec-env injects a scoped env var. Temp config is cleaned up on - success, failure, and interruption; child output is redacted as a backstop. -keywords: [secrets, delivery, exec, npm, publish, token, injection, redaction, npmrc, openbao] -``` - -```capability -type: governance -title: Maturity-gated publication-scope policy -description: Binds npm publication scope to package maturity (build to gitea-wide, test to - org-wide, prod to repo-scoped) and gates the graduated table behind the netkingdom domain - reaching production grade. While dormant, every lane clamps to the safest repo-scope — - fail-safe, never fail-open. The injected token env-var name signals the effective blast radius. -keywords: [policy, maturity, publication-scope, governance, least-privilege, npm, gitea, netkingdom] +title: AppRole-scoped exec delivery +description: Fetches one declared KV field through a lane AppRole and injects it into a child + process using exec-env or a temporary npm config, with output redaction and cleanup. This is + CLI-local delivery; exec-file, wrapping, service delivery, and explicit token revocation are absent. +keywords: [secrets, delivery, exec, npm, injection, redaction, openbao] ``` ```capability type: security title: Scoped OpenBao auth-capability handoff -description: Models non-KV grants such as warden-sign as guarded policy/AppRole lanes. - Plans refuse wildcards, sys/auth/token/identity paths, root-like capabilities, and - non-update SSH signing paths; handoff emits only file paths and non-secret metadata - 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] +description: Generates an exact-path policy/AppRole plan and writes role-id/secret-id material to + strict out-of-repo files after approval. Operational use remains subject to lane-specific governance. +keywords: [openbao, approle, auth-capability, 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] +type: governance +title: Non-secret routing and evidence pointers +description: Reports decision/readiness metadata and records scrubbed local and best-effort State Hub + evidence without returning secret values. It is not a durable audit store or complete multi-field attestation. +keywords: [routing, evidence, state-hub, audit, secrets] ``` diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md index fcde1c4..466bcd6 100644 --- a/WORK-RECORDS.md +++ b/WORK-RECORDS.md @@ -9,12 +9,14 @@ | Kind | ID | Status | Lane | Source | | --- | --- | --- | --- | --- | | workplan | ADHOC-2026-08-21 | finished | — | workplans/ADHOC-2026-08-21.md | +| workplan | ADHOC-2026-08-23 | finished | — | workplans/ADHOC-2026-08-23.md | | workplan | SECRETS-WP-0001 | finished | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md | | workplan | SECRETS-WP-0002 | finished | — | workplans/SECRETS-WP-0002-bootstrap.md | | workplan | SECRETS-WP-0004 | finished | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md | | workplan | SECRETS-WP-0005 | finished | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md | | workplan | SECRETS-WP-0006 | active | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md | | task | ADHOC-2026-08-21-T01 | done | — | workplans/ADHOC-2026-08-21.md | +| task | ADHOC-2026-08-23-T01 | done | — | workplans/ADHOC-2026-08-23.md | | task | SECRETS-WP-0001-T01 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md | | task | SECRETS-WP-0001-T02 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md | | task | SECRETS-WP-0001-T03 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md | diff --git a/history/2026-08-23-scope-intent-capability-gap-assessment.md b/history/2026-08-23-scope-intent-capability-gap-assessment.md new file mode 100644 index 0000000..d8a9d82 --- /dev/null +++ b/history/2026-08-23-scope-intent-capability-gap-assessment.md @@ -0,0 +1,217 @@ +# Scope and Intent Capability Gap Assessment + +Date: 2026-08-23 +Author: codex +Compared: `SCOPE.md` against `INTENT.md` and the current implementation + +## Executive assessment + +The repository has a credible, tested CLI MVP, but it is not yet the complete +secure interaction and automation layer described by `INTENT.md`. + +The strongest implemented slice is: + +```text +catalog -> approval-status check -> guarded plan -> policy/AppRole apply + -> bounded presence/capability verification -> CLI-local exec/handoff + -> non-secret route/evidence pointer +``` + +The weakest slice is lifecycle safety beyond that pilot chain. Rotation is +metadata only, KV provisioning is not merge-safe for multi-field paths, KV +revoke is destructive and incomplete, approval integration is still a pilot +resolver rather than a production authorization contract, and service mode does +not exist. + +The intent remains directionally sound. The gap is maturity, not a need to move +the system boundary: OpenBao should remain the backend; flex-auth/State Hub +should authorize; key-cape/user-engine should own identity; ops-warden should +route; and secrets-engine should remain the guarded workflow layer. + +## Open-work assessment + +The only active repository workplan is `SECRETS-WP-0006`: + +- T05 waits on explicit per-lane approval and scoped production OpenBao apply + authority for five reviewed existing production lanes. +- T06 waits on successful native verification before ops-warden proxy retirement. + +No approval or production authority was available during this assessment. The +latest ops-warden message also parks the standalone `warden-sign` AppRole for +break-glass use and explicitly requests no credential action. There was no safe, +actionable live task, so documentation reconciliation was the appropriate work. + +## Intent scorecard + +| Intent area | Assessment | Current evidence | Material gap | +| --- | --- | --- | --- | +| Decision first | Partial | Privileged CLI handlers require a resolved status and reject missing, unapproved, or superseded decisions. | Resolution accepts tracked local fixtures, checks only coarse status, has no freshness/purpose/actor semantics, and does not enforce actual dual control. The five new CCR strings do not resolve through the State Hub UUID endpoint. | +| OpenBao enforces; engine orchestrates | Substantially aligned | Backend operations are isolated in `openbao.py`; catalog, plan, guards, delivery, routing, and evidence are separate modules. | Only the local `bao`/`vault` subprocess adapter exists. Some safety depends on local validation rather than backend-bound per-request authorization. | +| Stage-aware privilege | Partial | Stage names, stage mismatch rejection, build/test prefixes, static stage policies, and consumer policy/AppRole naming exist. | Production has no local owner-prefix invariant (`STAGE_PREFIX["prod"]` is empty). Static bootstrap stage policies and supplied credentials remain wider and longer-lived than per-action identity. | +| No values in coordination surfaces | Partial, with a concrete implementation risk | Catalog validation rejects secret-looking inline values; evidence is scrubbed; CLI output avoids values; exec output is redacted. | `kv_put` passes the raw value in the local `bao` subprocess argument vector. Exec/verification parse the complete KV path response in process memory. These do not put values in Git/State Hub, but they fall short of the strongest custody boundary in the intent. | +| Least friction without broad power | Partial | Human-readable dry-runs, one-command exec, route pointers, and exact consumer policies reduce hand-written OpenBao work. | Routine production still needs manual decision and credential bridging. There is no OIDC/service login, service API, or durable request orchestration. | +| Bootstrap honestly, then harden | Partial | Bootstrap files are mode checked, rejected inside Git worktrees, documented, and tracked in the hardening backlog. | Bootstrap mode is still part of the live CLI; one historical cleanup/revocation record remains incomplete; tracked local approval mirrors remain usable for production commands. | +| Prefer exec-time delivery | Partial | `exec-env` and `npm-config` are implemented, including temporary npm config cleanup and child-output redaction. | `exec-file` and `wrapped` are schema-only. Scoped login tokens are not explicitly revoked after exec/verify, and child delivery is local CLI execution only. | +| Auditable and reversible | Weak/partial | Scrubbed JSONL evidence and best-effort State Hub progress events exist; OpenBao remains the audit source. | Many failure paths produce no evidence, State Hub posting silently drops failures, actors are not cryptographically bound, no audit-report command exists, and KV revoke is destructive rather than reversible. | +| Typed multi-application catalog | Substantially aligned as metadata | Multiple KV lanes, an auth-capability lane, explicit org/repo/stage/consumer/field data, existing-mount semantics, and high-risk ownership checks are implemented. | This is not runtime multi-tenancy. Consumer claims are descriptive and are not authenticated or authorized by this process. | +| CLI and service API | CLI achieved; API absent | The documented CLI surface exists and the pilot flow has integration coverage. | No daemon, API, queue, scheduler, UI, remote protocol, or concurrency model exists. | +| Lifecycle: establish/access/rotate/deactivate | Establish/access partial; lifecycle incomplete | Apply, provision, verify, exec, handoff, and two forms of revoke exist. | No rotate command, compromise/suspend state, provider rotation, lease/accessor lifecycle, rollback orchestration, or safe soft deactivation exists. | + +## Highest-priority gaps + +### P0 — Provisioning is unsafe for shared multi-field paths + +`provision_from_file` reads one declared field and calls `OpenBaoClient.kv_put`. +That adapter invokes: + +```text +bao kv put / = +``` + +Two consequences matter: + +1. `kv put` replaces the data at a KV v2 path rather than merging sibling + fields. Updating one field can remove the others. +2. The raw value is present in the local subprocess argument vector while the + command runs. + +This is acceptable only as a constrained pilot/bootstrap primitive on a +single-field or disposable path. It must not be used on the newly admitted +issue-core, reuse-surface, Forgejo, or email paths. A production design needs a +merge-safe update mechanism that does not expose values through argv, plus +tests proving sibling preservation and failure cleanup. + +### P0 — KV revoke is destructive, incomplete, and inconsistent with dry-run + +For a KV lane, live `revoke` deletes all KV metadata/versions but leaves the +consumer AppRole and ACL policy. The dry-run text says it would delete both KV +metadata and the AppRole, which the live path does not do. + +This does not meet the intent's reversible lifecycle principle. The command +needs explicit operations with different approvals, for example: + +- suspend delivery by deleting/disabling AppRole credentials; +- deactivate consumer policy/auth; +- revoke leases/tokens by accessor; +- delete current value versions; +- irreversibly destroy KV metadata only under an explicit destruction action. + +Until then, KV revoke should be treated as destructive path deletion, not a +general revocation or deactivation workflow. + +### P0 — Production approval is not yet a complete authorization contract + +The resolver accepts `resolved`, `approved`, or `accepted` status and absence of +`superseded_by`. It does not validate action type, lane/stage binding, actor, +expiry, allowed fields, operation, approval count, or flex-auth result. +`dual-control` is a catalog label but is not enforced as two approvals. + +Tracked local decision mirrors are useful for demos and historical pilots but +are too permissive as a steady-state production authority source. Production +should require a canonical decision object bound to the exact action and should +fail closed when State Hub/flex-auth cannot prove that binding. + +## Important hardening gaps + +### P1 — Steady-state authentication is absent + +The CLI accepts a token from an environment variable or a mode-0600 bootstrap +file. It does not perform OpenBao OIDC, workload/service auth, short-lived +issuer exchange, or per-action identity binding. This keeps routine production +work dependent on attended external credential bridging. + +### P1 — Verification is narrower than the intent + +KV positive verification checks one field, defaulting to the first. Route +readiness also checks only the first field, so a multi-field lane can appear +ready while sibling fields are missing. KV negative verification uses a fixed +garbage token, not a real unrelated workload identity. Provider behavior and +application health are outside the check. + +High-risk lane acceptance should verify every declared field, use a real +unrelated identity or capabilities proof, capture OpenBao audit request ids, +and, where appropriate, call a value-safe provider/application smoke. + +### P1 — Delivery token lifecycle is implicit + +Exec and verification create AppRole Secret IDs and login tokens. Secret ID +use counts and token TTL/use bounds limit them, but the code does not revoke the +issued token explicitly on success, child failure, interruption, or verification +failure. Evidence does not include a safe lease/accessor lifecycle. + +### P1 — Evidence is informative, not a durable audit workflow + +Local JSONL is append-only by convention, not tamper-evident. State Hub posting +is best-effort and silently ignored on error. Apply/provision/handoff failures +are generally recorded only if a caller adds separate evidence; there is no +transaction id joining State Hub evidence to OpenBao audit entries, and no +`audit` command summarizes a lane. + +### P1 — Lifecycle metadata is not lifecycle automation + +Catalog entries require rotation/deactivation descriptions and owners, which is +valuable governance metadata. The engine does not execute those plans, manage +provider credential overlap, coordinate consumers, maintain compromised or +deactivated state, or verify rollback. + +## Longer-term product gaps + +### P2 — Service mode + +The intent describes a CLI and service API. Only the CLI exists. A service +should wait until approval binding, auth, delivery token lifecycle, evidence, +and destructive-operation semantics are hardened; exposing today's CLI directly +would amplify its pilot shortcuts. + +### P2 — Runtime tenancy and consumer identity + +The catalog can describe many applications and logical owners, but the engine +does not authenticate a tenant, resolve claims, isolate concurrent callers, or +enforce per-tenant quotas/policies. The current product is multi-application +metadata and path orchestration, not a multi-tenant service. + +### P2 — Backend abstraction + +OpenBao-specific behavior is isolated reasonably well, but there is only one +subprocess backend. “OpenBao as the initial enforcement backend” remains an +architectural option, not a demonstrated portable backend contract. + +## Current evolution phase + +Against the phases in `INTENT.md`: + +1. **Bootstrap:** implemented and still active. +2. **MVP:** achieved for the whynot-design npm pilot. +3. **Stage separation:** implemented in catalog/plan/static policy form, but + steady-state stage authentication and stronger production owner binding are + incomplete. +4. **Hardening:** started; existing-mount admission, risk classification, + exact-field guards, bounded AppRoles, and fail-closed decisions exist. The P0 + and P1 gaps above remain. +5. **Service mode:** not started. + +## Recommended next sequence + +1. Keep `SECRETS-WP-0006-T05` limited to approved metadata apply and explicit + per-field, positive/negative verification. Do not provision or revoke the + existing shared paths through the current KV lifecycle commands. +2. Fix provisioning transport and merge semantics, with sibling-preservation + and process-argument tests. +3. Split KV suspend/deactivate/destroy semantics and make dry-run match live + behavior. +4. Replace coarse/local production decision resolution with an action-bound, + expiring, dual-control-capable authorization contract. +5. Add steady-state OIDC/service auth and explicit child-token revocation. +6. Strengthen multi-field/readiness and unrelated-identity verification, then + correlate evidence with OpenBao audit request ids. +7. Implement rotation state and wrapped/file delivery before designing service + mode. + +## Conclusion + +`INTENT.md` still describes the right destination, but the accurate present +tense is a guarded OpenBao CLI MVP with one proven native workload pilot and +several reviewed-but-not-live production lane plans. The repository should not +yet advertise itself as a service API, complete lifecycle engine, runtime +multi-tenant system, wrapped-delivery broker, or production-safe general KV +updater. diff --git a/workplans/ADHOC-2026-08-23.md b/workplans/ADHOC-2026-08-23.md new file mode 100644 index 0000000..35f2e4f --- /dev/null +++ b/workplans/ADHOC-2026-08-23.md @@ -0,0 +1,39 @@ +--- +id: ADHOC-2026-08-23 +type: workplan +title: "Implemented scope and intent-gap reconciliation" +domain: infotech +repo: secrets-engine +status: finished +owner: codex +topic_slug: custodian +created: "2026-08-23" +updated: "2026-08-23" +--- + +# ADHOC-2026-08-23 - Implemented scope and intent-gap reconciliation + +## Reconcile implemented capability scope + +```task +id: ADHOC-2026-08-23-T01 +status: done +priority: medium +``` + +Checked the repository workplans and coordination inbox. The only active work, +`SECRETS-WP-0006-T05/T06`, remains waiting on external production approval and +authority; the current ops-warden message requested no credential action. + +Rewrote `SCOPE.md` as an implemented capability boundary rather than an +aspirational/current-work ledger, and recorded a dated assessment against +`INTENT.md` in +`history/2026-08-23-scope-intent-capability-gap-assessment.md`. The assessment +documents the achieved CLI MVP and the concrete approval, provisioning, +revocation, verification, auth, evidence, lifecycle, tenancy, and service-mode +gaps without exposing secret material. + +`statehub fix-consistency` was attempted twice and interrupted after repeated +60-second stalls in State Hub HTTP calls (`GET /topics/` and +`PATCH /repos/secrets-engine`). The progress event was recorded successfully, +but registrar/index consistency remains pending on State Hub availability.