Declare Engine/Lifecycle against security layer model v0.7
Replace the gate-house review note with this repository's own declaration: INTENT.md frontmatter, layer.yaml, and a published PEP stance map. SCOPE.md and agent boundary docs now match that layer. The review under history/ identifies the implementation remainder; SECRETS-WP-0008 is the follow-on workplan. SECRETS-IN-0001 is closed. The layer is not contested. Catalog "custody" is a finding: OpenBao owns custody, this engine owns the lifecycle API over it. SSH-CA signing is accepted as a proposed engine API and declined as a Staff lane. Assistant: grok Assistant-Session: 01a04cea-cb33-7c63-bad7-c1b0f9f0076b
This commit is contained in:
parent
b1f0f7b666
commit
1945e16685
14 changed files with 1177 additions and 108 deletions
|
|
@ -1,12 +1,15 @@
|
||||||
## Repo boundary
|
## Repo boundary
|
||||||
|
|
||||||
This repo owns the **secrets-engine** workflow/interaction layer only. It does
|
This repo owns the **secrets-engine** Lifecycle engine only (NetKingdom
|
||||||
not own:
|
security layer model v0.7: Engine / Lifecycle). It does not own:
|
||||||
|
|
||||||
- Secret custody, policy, lease, and audit backend → OpenBao / railiance-platform
|
- Secret custody, policy, lease, and audit backend → OpenBao / railiance-platform
|
||||||
- SSH certificate issuance → ops-warden (`warden sign`)
|
- SSH certificate issuance (Staff PEP) → ops-warden (`warden sign`)
|
||||||
- Tunnels and remote transport → ops-bridge
|
- Tunnels and remote transport → ops-bridge
|
||||||
- Authorization decisions → flex-auth
|
- Authorization decisions → access-engine (`flex-auth`)
|
||||||
|
- Approval objects → approval-engine
|
||||||
|
- Evidence custody and integrity → audit-core
|
||||||
- Identity and claim lifecycle → user-engine / key-cape
|
- Identity and claim lifecycle → user-engine / key-cape
|
||||||
|
- Security doctrine and the layer model → gate-house / net-kingdom canon
|
||||||
- Cross-system security boundary doc → net-kingdom/docs/
|
- Cross-system security boundary doc → net-kingdom/docs/
|
||||||
- Request history and progress index → State Hub (read model)
|
- Request history and progress index → State Hub (read model)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
**Purpose:** secrets-engine is a headless, multi-application, multi-tenant secrets workflow and automation layer that orchestrates approved secret custody, delivery, and lifecycle work across build, test, and production stages, with OpenBao as the initial enforcement backend.
|
**Purpose:** secrets-engine is the Lifecycle engine for approved credential work: a deterministic API over OpenBao that orchestrates cataloged custody, delivery, and lifecycle actions across build, test, and production. It does not render authorization decisions.
|
||||||
|
|
||||||
**Domain:** infotech
|
**Domain:** infotech
|
||||||
**Repo slug:** secrets-engine
|
**Repo slug:** secrets-engine
|
||||||
|
|
|
||||||
19
AGENTS.md
19
AGENTS.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Repo Identity
|
## Repo Identity
|
||||||
|
|
||||||
**Purpose:** secrets-engine is a headless, multi-application, multi-tenant secrets workflow and automation layer that orchestrates approved secret custody, delivery, and lifecycle work across build, test, and production stages, with OpenBao as the initial enforcement backend.
|
**Purpose:** secrets-engine is the Lifecycle engine for approved credential work: a deterministic API over OpenBao that orchestrates cataloged custody, delivery, and lifecycle actions across build, test, and production. It does not render authorization decisions.
|
||||||
|
|
||||||
**Domain:** infotech
|
**Domain:** infotech
|
||||||
**Repo slug:** secrets-engine
|
**Repo slug:** secrets-engine
|
||||||
|
|
@ -166,17 +166,24 @@ Read `docs/netkingdom-security-infrastructure.md` before changing secret
|
||||||
catalogs, OpenBao policies, auth roles, delivery modes, or ops-warden routing.
|
catalogs, OpenBao policies, auth roles, delivery modes, or ops-warden routing.
|
||||||
|
|
||||||
Core rules:
|
Core rules:
|
||||||
- OpenBao is the custody, policy, lease, and audit backend.
|
- Layer: Engine / Lifecycle (`INTENT.md`, `layer.yaml`). PEP stance:
|
||||||
- secrets-engine owns workflow, catalog, decision checks, safe delivery, and
|
`pep-stance.yaml`.
|
||||||
non-secret evidence.
|
- OpenBao is the custody, policy, lease, and audit backend (Tooling).
|
||||||
- flex-auth decides authorization; user-engine/key-cape own identity and claims.
|
- secrets-engine is the Lifecycle API over that backend: catalog, decision
|
||||||
|
consumption, safe delivery, and non-secret evidence. It does not render
|
||||||
|
authorization decisions.
|
||||||
|
- `access-engine` (`flex-auth`) decides authorization; user-engine/key-cape own
|
||||||
|
identity and claims; `audit-core` owns evidence custody.
|
||||||
- ops-warden routes non-SSH credential requests here and must not vend secrets.
|
- ops-warden routes non-SSH credential requests here and must not vend secrets.
|
||||||
|
SSH certificate issuance remains ops-warden's Staff PEP.
|
||||||
- ops-bridge may consume scoped delivery for remote execution but must not store
|
- ops-bridge may consume scoped delivery for remote execution but must not store
|
||||||
secret material.
|
secret material.
|
||||||
- info-tech-canon is the source for canonical terminology and stage/policy
|
- info-tech-canon is the source for canonical terminology and stage/policy
|
||||||
concepts as they harden.
|
concepts as they harden. gate-house owns the layer model.
|
||||||
- Never write raw secret values to Git, State Hub, chat, prompts, workplans, or
|
- Never write raw secret values to Git, State Hub, chat, prompts, workplans, or
|
||||||
normal logs.
|
normal logs.
|
||||||
|
- Never claim local evidence or a missing record proves occurrence or
|
||||||
|
non-occurrence.
|
||||||
|
|
||||||
<!-- Append repo-specific agent instructions below this marker.
|
<!-- Append repo-specific agent instructions below this marker.
|
||||||
The state-hub template sync preserves content after this line. -->
|
The state-hub template sync preserves content after this line. -->
|
||||||
|
|
|
||||||
206
INTENT.md
206
INTENT.md
|
|
@ -1,40 +1,78 @@
|
||||||
|
---
|
||||||
|
layer: Engine
|
||||||
|
role: Lifecycle
|
||||||
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||||||
|
companion: net-kingdom/SECURITY-COMPANION.md
|
||||||
|
declaration: layer.yaml
|
||||||
|
pep_stance: pep-stance.yaml
|
||||||
|
declared_at: "2026-08-29"
|
||||||
|
---
|
||||||
|
|
||||||
# INTENT
|
# INTENT
|
||||||
|
|
||||||
> **NetKingdom layering review — 2026-08-28.** This repository's role was reviewed
|
> **Layer: Engine. Role: Lifecycle.** This is this repository's own declaration
|
||||||
> against the NetKingdom IT-security layer model: **Taxonomy → Tooling → Engines →
|
> under the accepted NetKingdom Security Layer Model
|
||||||
> Staff**, layered by determinism and by the kind of artifact each layer produces.
|
> (`net-kingdom/canon/standards/security-layer-model_v0.7.md`) and its working
|
||||||
> Findings and the argument behind them:
|
> companion (`net-kingdom/SECURITY-COMPANION.md`). The machine-readable form
|
||||||
> `gate-house/history/2026-08-28-security-layer-model-and-gate-house-recut.md`.
|
> required by §11 is `layer.yaml`. A layer stated about this repository by
|
||||||
> The model is `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed),
|
> another repository is not a declaration; this file, in this repository's
|
||||||
> ratified by `gate-house/decisions/decisions.md` GH-DEC-2026-001.
|
> voice, is.
|
||||||
>
|
>
|
||||||
> The layer rule that binds every repository: **Staff never touches tooling
|
> secrets-engine is a **deterministic API over OpenBao** for one modeled
|
||||||
> directly. It acts only through engine APIs.**
|
> concept: the cataloged credential lane and its lifecycle. The same
|
||||||
|
> authoritative inputs — catalog entry, access-engine decision record, and
|
||||||
|
> OpenBao state — must yield the same plan, apply, delivery, and lifecycle
|
||||||
|
> result. That is why this repository is an Engine, not Staff, even though
|
||||||
|
> operators and agents invoke it at runtime.
|
||||||
>
|
>
|
||||||
> **This repository is Engine — deterministic API for a modeled concept.** Add the layer label. Credential custody, materialization, and lifecycle remain secrets-engine's. Two boundaries to make explicit: the decision that authority exists is access-engine's, and the doctrine governing when and how authority may be materialized is gate-house's. secrets-engine implements; it does not author the rules or render the decision.
|
> **It is not a decision point.** `access-engine` (today `flex-auth`) renders
|
||||||
|
> whether authority exists. gate-house authors the doctrine that may reach that
|
||||||
|
> decision only as a request claim or a versioned policy rule. OpenBao is
|
||||||
|
> Tooling: custody, policy enforcement, leases, and backend audit. This engine
|
||||||
|
> materializes an already-rendered decision into scoped OpenBao work. A
|
||||||
|
> credential is an artifact of authority, never its source.
|
||||||
>
|
>
|
||||||
> *This note records what should change. The body below is not yet adapted.*
|
> **It is PEP-shaped.** Apply, provision, exec delivery, handoff, suspend,
|
||||||
|
> deactivate, and destroy cause protected side effects, so the four PEP
|
||||||
|
> obligations in §6.4 bind: no side effect without a decision record or a
|
||||||
|
> recorded stance; no replay of a verdict outside its binding and lifetime;
|
||||||
|
> a published unreachable-engine stance at `pep-stance.yaml`; reconstructability
|
||||||
|
> bounded by §9.6. Being PEP-shaped does not change the layer.
|
||||||
|
>
|
||||||
|
> **Proposed surfaces, not yet assented as shipped APIs.** ops-warden has
|
||||||
|
> declared its SSH-CA signing write as an engine gap with intended owner
|
||||||
|
> secrets-engine. kings-guard has proposed secret-use evidence against this
|
||||||
|
> engine. This repository **accepts both as proposed Lifecycle surfaces** and
|
||||||
|
> **declines operational SSH-lane stewardship**: `ops-warden` remains the Staff
|
||||||
|
> PEP that requests a certificate after a decision. What belongs here is the
|
||||||
|
> engine API those Staff repositories should call instead of OpenBao. Until
|
||||||
|
> those surfaces exist, the gaps stay proposed, not silently taken.
|
||||||
|
>
|
||||||
|
> **Finding on the §4 catalog cell.** The catalog row currently says this
|
||||||
|
> repository owns "credential abstraction, custody, lifecycle". Custody belongs
|
||||||
|
> to OpenBao. This engine owns the lifecycle API *over* that custody. The
|
||||||
|
> wording should not assign a Tooling property to an Engine.
|
||||||
|
|
||||||
> This file captures why this repository exists, the direction it is moving
|
> This file captures why this repository exists, the direction it is moving
|
||||||
> toward, and the kind of system it is meant to become. It is intentionally
|
> toward, and the kind of system it is meant to become. It is intentionally
|
||||||
> aspirational and stable, not a description of current implementation.
|
> aspirational and stable, not a description of current implementation.
|
||||||
|
> See `SCOPE.md` for what is implemented today.
|
||||||
|
|
||||||
## One-liner
|
## One-liner
|
||||||
|
|
||||||
**secrets-engine is the secure interaction and automation layer for approved
|
**secrets-engine is the Lifecycle engine for approved credential work: a
|
||||||
secret custody, scoped OpenBao capability handoff, delivery, and lifecycle work
|
deterministic API that turns an access-engine decision into scoped OpenBao
|
||||||
across build, test, and production, with OpenBao as the initial enforcement
|
custody, delivery, and lifecycle actions across build, test, and production.**
|
||||||
backend.**
|
|
||||||
|
|
||||||
## Why This Exists
|
## Why This Exists
|
||||||
|
|
||||||
Secret management is too important to be handled through scattered manual UI
|
Secret management is too important to be handled through scattered manual UI
|
||||||
steps, copied commands, chat handoffs, and ad hoc token files.
|
steps, copied commands, chat handoffs, and ad hoc token files.
|
||||||
|
|
||||||
OpenBao is the right place to enforce custody, policy, lease, and audit. It is
|
OpenBao is the right Tooling for custody, policy, lease, and audit. It is not,
|
||||||
not, by itself, the right daily interaction surface for operators, agents,
|
by itself, the right daily interaction surface for operators, agents, workloads,
|
||||||
workloads, and approval workflows. Direct use of OpenBao UI and CLI surfaces has
|
and approval workflows. Direct use of OpenBao UI and CLI surfaces has already
|
||||||
already produced avoidable friction:
|
produced avoidable friction:
|
||||||
|
|
||||||
- approved decisions still require a human to bridge low-level OpenBao details;
|
- approved decisions still require a human to bridge low-level OpenBao details;
|
||||||
- agents and operators hit interface mismatches before reaching the security
|
- agents and operators hit interface mismatches before reaching the security
|
||||||
|
|
@ -42,111 +80,145 @@ already produced avoidable friction:
|
||||||
- build, test, and production need different levels of privilege and ceremony;
|
- build, test, and production need different levels of privilege and ceremony;
|
||||||
- secret values must never move through chat, Git, prompts, State Hub messages,
|
- secret values must never move through chat, Git, prompts, State Hub messages,
|
||||||
or workplans;
|
or workplans;
|
||||||
- ops-warden needs a reliable front door for credential and scoped capability
|
- Staff repositories such as ops-warden need an Engine API for credential and
|
||||||
use, not direct secret custody responsibility.
|
scoped-capability work, not a direct OpenBao client and not secret-vending
|
||||||
|
responsibility of their own.
|
||||||
|
|
||||||
This repository exists to capture that complexity once, behind a stable and
|
This repository exists to capture that complexity once, behind a stable,
|
||||||
auditable interface.
|
deterministic, and auditable interface.
|
||||||
|
|
||||||
## The Mission
|
## The Mission
|
||||||
|
|
||||||
To provide a decision-aware secrets workflow that can:
|
To provide a decision-aware Lifecycle engine that can:
|
||||||
|
|
||||||
- translate approved requests into narrowly scoped OpenBao changes or capability
|
- consume an access-engine decision and refuse to proceed without one, or
|
||||||
|
record the application of a declared unreachable-engine stance in its place;
|
||||||
|
- translate that decision into narrowly scoped OpenBao changes or capability
|
||||||
grants;
|
grants;
|
||||||
- operate with distinct build, test, and production privilege layers;
|
- operate with distinct build, test, and production privilege layers;
|
||||||
- deliver secrets and scoped capabilities to commands and workloads without
|
- deliver secrets and scoped capabilities to commands and workloads without
|
||||||
printing or storing raw values in coordination systems;
|
printing or storing raw values in coordination systems;
|
||||||
- record enough non-secret evidence for review, audit, and troubleshooting;
|
- emit non-secret evidence under the §9.6 bound — the archive proves records
|
||||||
|
it holds were not altered or truncated after arrival, not that every event
|
||||||
|
was sent, and not that absence means non-occurrence;
|
||||||
- make routine secure work fast enough that operators and agents actually use
|
- make routine secure work fast enough that operators and agents actually use
|
||||||
the secure path.
|
the Engine path instead of touching OpenBao.
|
||||||
|
|
||||||
## Core Principles
|
## Core Principles
|
||||||
|
|
||||||
### 1. Decision First
|
### 1. Decision elsewhere, materialization here
|
||||||
|
|
||||||
Secret establishment, access, rotation, and deactivation start from an explicit
|
Secret establishment, access, rotation, and deactivation start from an
|
||||||
request and decision. The engine may automate the work after approval; it does
|
access-engine decision record naming the request it was rendered for.
|
||||||
not silently create new secret authority.
|
This engine may automate the work after that decision; it does not render,
|
||||||
|
cache, or substitute one. Compiled catalog data that would determine an
|
||||||
|
outcome before the engine runs is still deciding, and is forbidden.
|
||||||
|
|
||||||
### 2. OpenBao Enforces, secrets-engine Orchestrates
|
### 2. OpenBao is Tooling; this engine is the API over it
|
||||||
|
|
||||||
OpenBao remains the vault, policy, lease, and audit backend. secrets-engine owns
|
OpenBao remains the vault, policy, lease, and audit backend. secrets-engine
|
||||||
the workflow, catalog, validation, delivery, scoped capability handoff, and
|
owns the catalog, validation, delivery, scoped capability handoff, lifecycle
|
||||||
operator/agent interface.
|
operations, and the operator/agent/Staff interface to those operations. Staff
|
||||||
|
must not hold a direct OpenBao client for work this engine is meant to expose.
|
||||||
|
|
||||||
### 3. Stage-aware Privilege
|
### 3. Stage-aware privilege
|
||||||
|
|
||||||
Build, test, and production are separate security contexts. Each has its own
|
Build, test, and production are separate security contexts. Each has its own
|
||||||
OpenBao role, policy boundary, approval expectation, TTL limits, and delivery
|
OpenBao role, policy boundary, approval expectation, TTL limits, and delivery
|
||||||
rules.
|
rules. Stage is the current equivalent scope for the PEP stance map until
|
||||||
|
security-zone membership is consumed as a claim.
|
||||||
|
|
||||||
### 4. No Secret Values in Coordination Surfaces
|
### 4. No secret values in coordination surfaces
|
||||||
|
|
||||||
Git, State Hub, workplans, chat, prompts, issue comments, and normal logs carry
|
Git, State Hub, workplans, chat, prompts, issue comments, and normal logs carry
|
||||||
only non-secret metadata. Raw values are delivered through OpenBao, wrapped
|
only non-secret metadata. Raw values are delivered through OpenBao, wrapped
|
||||||
responses, local exec-time injection, or short-lived bootstrap files with strict
|
responses, local exec-time injection, or short-lived bootstrap files with strict
|
||||||
permissions.
|
permissions.
|
||||||
|
|
||||||
### 5. Least Friction Without Broad Power
|
### 5. Least friction without broad power
|
||||||
|
|
||||||
The common path should be one clear command or review action. That ease must not
|
The common path should be one clear command or Engine API call. That ease must
|
||||||
require handing platform-root or platform-admin power to routine automation.
|
not require handing platform-root or platform-admin power to routine
|
||||||
|
automation, and it must not mint standing credentials for agents. Agent
|
||||||
|
authority is per task, time-bounded, and attributable to the principal the
|
||||||
|
agent acts for.
|
||||||
|
|
||||||
### 6. Bootstrap Honestly, Then Harden
|
### 6. Bootstrap honestly, then harden
|
||||||
|
|
||||||
During infrastructure setup it is acceptable to use temporary root-created
|
During infrastructure setup it is acceptable to use temporary root-created
|
||||||
OpenBao credentials stored outside repositories with mode 0600 and explicit
|
OpenBao credentials stored outside repositories with mode 0600 and explicit
|
||||||
revocation. Those bootstrap shortcuts must be tracked as temporary and replaced
|
revocation. Those bootstrap shortcuts must be tracked as temporary, must never
|
||||||
by narrower auth roles.
|
become an implicit fallback, and must be replaced by narrower service identity
|
||||||
|
bound to OpenBao.
|
||||||
|
|
||||||
### 7. Prefer Exec-time Delivery
|
### 7. Prefer exec-time delivery
|
||||||
|
|
||||||
When a workload or operator command needs a secret, the default delivery mode is
|
When a workload or operator command needs a secret, the default delivery mode is
|
||||||
process-local injection for the duration of that command. The engine should make
|
process-local injection for the duration of that command. Every such allow has
|
||||||
this easier than copying or inspecting a secret value.
|
an explicit lifetime — a TTL, or a binding to a session that ends. The engine
|
||||||
|
should make this easier than copying or inspecting a secret value.
|
||||||
|
|
||||||
### 8. Auditable and Reversible
|
### 8. Evidence is bounded, not omniscient
|
||||||
|
|
||||||
Every apply, read, delivery, lease, verification, revocation, and deactivation
|
Every apply, read, delivery, lease, verification, revocation, and deactivation
|
||||||
has non-secret evidence that can be reviewed later.
|
emits non-secret evidence. Load-bearing events — those a control would be
|
||||||
|
unsound without — require atomic local emission and a declared cadence or
|
||||||
|
heartbeat. Attributive events should seek atomicity; where they trade it away,
|
||||||
|
the trade is declared and completeness is not claimed. Evidence belongs in
|
||||||
|
`audit-core`. Local JSONL and State Hub notes are not a substitute for that
|
||||||
|
engine.
|
||||||
|
|
||||||
|
### 9. Adaptive systems may only tighten
|
||||||
|
|
||||||
|
This engine may shorten a lifetime, refuse a delivery, suspend a lane, or
|
||||||
|
require a fresh decision. It must not manufacture authority, widen a grant, or
|
||||||
|
treat silence from `access-engine` as permission.
|
||||||
|
|
||||||
## What This Is
|
## What This Is
|
||||||
|
|
||||||
secrets-engine is:
|
secrets-engine is:
|
||||||
|
|
||||||
- a workflow layer for approved secret changes, scoped capability grants, and
|
- the Lifecycle engine for cataloged credential lanes;
|
||||||
access;
|
- a CLI today and a service API for operators, agents, CI, and Staff
|
||||||
- a CLI and service API for operators, agents, and automation;
|
repositories that must not speak OpenBao;
|
||||||
- a typed catalog of KV secret lanes, auth-capability lanes, grants, delivery
|
- a typed catalog of KV secret lanes, auth-capability lanes, grants, delivery
|
||||||
modes, and stage policies;
|
modes, and stage policies;
|
||||||
- an OpenBao policy/auth-role applier with strict local validation;
|
- an OpenBao policy/auth-role applier with strict local validation;
|
||||||
- an exec-time secret delivery and scoped capability handoff helper;
|
- an exec-time secret delivery and scoped capability handoff helper;
|
||||||
- an audit evidence writer for State Hub and local logs;
|
- a PEP at every protected side effect, with a published unreachable-engine
|
||||||
- the credential interaction surface that ops-warden can route to.
|
stance;
|
||||||
|
- the credential interaction surface that ops-warden routes to after a
|
||||||
|
decision.
|
||||||
|
|
||||||
## What This Is Not
|
## What This Is Not
|
||||||
|
|
||||||
secrets-engine is not:
|
secrets-engine is not:
|
||||||
|
|
||||||
- a replacement for OpenBao;
|
- a replacement for OpenBao, or the owner of custody;
|
||||||
- an identity provider or MFA system;
|
- an identity provider or MFA system;
|
||||||
- an authorization decision engine;
|
- an authorization decision engine, an approval store, or a maturity engine;
|
||||||
- an application-specific secret store;
|
- an application-specific secret store;
|
||||||
- a place to persist raw secret values outside OpenBao;
|
- a place to persist raw secret values outside OpenBao;
|
||||||
- a prompt-time secret injection mechanism for LLMs;
|
- a prompt-time secret injection mechanism for LLMs;
|
||||||
- a bypass around review, approval, or production custody.
|
- a bypass around review, approval, or production custody;
|
||||||
|
- the operational owner of the SSH certificate lane — that Staff PEP remains
|
||||||
|
ops-warden's; this engine may later expose the signing API it should call;
|
||||||
|
- an observation or containment system — kings-guard proposes, this engine
|
||||||
|
does not watch production, and actuation is unowned estate-wide.
|
||||||
|
|
||||||
## System Boundary
|
## System Boundary
|
||||||
|
|
||||||
| Concern | Primary owner | secrets-engine responsibility |
|
| Concern | Primary owner | secrets-engine responsibility |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Secret custody, leases, audit backend | OpenBao / railiance-platform | Use through least-privilege roles and validated paths. |
|
| Secret custody, leases, backend audit | OpenBao (Tooling) / railiance-platform | Lifecycle API over least-privilege roles and validated paths. |
|
||||||
|
| Authorization decisions | access-engine (`flex-auth`) | Consume a decision record; never render or cache one. |
|
||||||
|
| Approval object | approval-engine | Consume an approval as an input claim; never store or mutate it. |
|
||||||
|
| Security doctrine | gate-house | Apply doctrine only as it arrives on the decision or in a versioned policy package. |
|
||||||
| Human and service identity | key-cape / user-engine | Consume identity claims; do not replace identity lifecycle. |
|
| 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 (Staff PEP) | ops-warden | Route and, when the surface exists, expose the OpenBao SSH-CA API; do not take the lane. |
|
||||||
| SSH certificate issuance | ops-warden | Provide routed credential/capability access; do not make ops-warden vend secrets. |
|
| Evidence custody and integrity | audit-core | Emit non-secret events under the §9.6 bound; do not become the archive. |
|
||||||
| Workload secret consumption | Workload repos / CI / runtime | Provide safe delivery and handoff contracts plus catalog entries. |
|
| 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. |
|
| Request history and progress | State Hub | Write non-secret progress pointers only; not a security state plane. |
|
||||||
|
|
||||||
## Direction of Evolution
|
## Direction of Evolution
|
||||||
|
|
||||||
|
|
@ -161,10 +233,16 @@ The repository should evolve through these phases:
|
||||||
4. **Hardening:** replace bootstrap token files with OIDC/service auth, wrapped
|
4. **Hardening:** replace bootstrap token files with OIDC/service auth, wrapped
|
||||||
delivery, short leases, dual control for production provisioning, and routine
|
delivery, short leases, dual control for production provisioning, and routine
|
||||||
rotation/deactivation workflows.
|
rotation/deactivation workflows.
|
||||||
5. **Service mode:** expose an API that ops-warden, agents, CI, and future UI
|
5. **Layer-model conformance:** published PEP stance equals shipped behaviour;
|
||||||
surfaces can use without knowing OpenBao internals.
|
live side effects hold an access-engine decision record or a recorded stance;
|
||||||
|
evidence classified and emitted to audit-core; proposed SSH-CA and secret-use
|
||||||
|
surfaces accepted or declined in this repository's own contract, not only in
|
||||||
|
other repositories' gap registers.
|
||||||
|
6. **Service mode:** expose a deterministic API that ops-warden, agents, CI, and
|
||||||
|
future UI surfaces can use without knowing OpenBao internals.
|
||||||
|
|
||||||
## Guiding Question
|
## Guiding Question
|
||||||
|
|
||||||
**How can approved secret work become low-friction for humans and agents while
|
**How can approved secret work become low-friction for humans and agents while
|
||||||
keeping raw values, OpenBao privileges, and production impact tightly bounded?**
|
keeping raw values, OpenBao privileges, and production impact tightly bounded
|
||||||
|
to a decision this engine did not render?**
|
||||||
|
|
|
||||||
15
README.md
15
README.md
|
|
@ -4,15 +4,20 @@ Headless, multi-application, multi-tenant secrets workflow and automation layer
|
||||||
for approved secret custody, delivery, and lifecycle work across build, test,
|
for approved secret custody, delivery, and lifecycle work across build, test,
|
||||||
and production stages.
|
and production stages.
|
||||||
|
|
||||||
OpenBao remains the custody and enforcement backend. `secrets-engine` owns the
|
**Layer: Engine / Lifecycle** under the accepted NetKingdom Security Layer
|
||||||
operator and agent interaction model: catalog, decision checks, plan/apply,
|
Model (`layer.yaml`). OpenBao remains the custody and enforcement backend.
|
||||||
guarded provisioning, verification, delivery, evidence, lifecycle metadata, and
|
`secrets-engine` is the deterministic API over it: catalog, decision
|
||||||
native-access deactivation. Local evidence can be inspected through an
|
consumption, plan/apply, guarded provisioning, verification, delivery,
|
||||||
|
evidence, lifecycle metadata, and native-access deactivation. It does not
|
||||||
|
render authorization decisions. Local evidence can be inspected through an
|
||||||
allowlisted per-lane `audit` summary without exposing record detail.
|
allowlisted per-lane `audit` summary without exposing record detail.
|
||||||
|
|
||||||
## Start Here
|
## Start Here
|
||||||
|
|
||||||
- [INTENT.md](INTENT.md) - why this repository exists.
|
- [INTENT.md](INTENT.md) - why this repository exists, including the Engine /
|
||||||
|
Lifecycle declaration.
|
||||||
|
- [layer.yaml](layer.yaml) - machine-readable layer declaration and proposed
|
||||||
|
surfaces.
|
||||||
- [ProductRequirementsDocument.md](ProductRequirementsDocument.md) - product
|
- [ProductRequirementsDocument.md](ProductRequirementsDocument.md) - product
|
||||||
requirements and MVP scope.
|
requirements and MVP scope.
|
||||||
- [NetKingdom security infrastructure boundary pointer](docs/netkingdom-security-infrastructure.md)
|
- [NetKingdom security infrastructure boundary pointer](docs/netkingdom-security-infrastructure.md)
|
||||||
|
|
|
||||||
103
SCOPE.md
103
SCOPE.md
|
|
@ -3,15 +3,20 @@
|
||||||
> Implemented capability boundary for agents and contributors. Aspirational
|
> Implemented capability boundary for agents and contributors. Aspirational
|
||||||
> direction belongs in `INTENT.md`; current work and operational gates belong in
|
> direction belongs in `INTENT.md`; current work and operational gates belong in
|
||||||
> `workplans/`.
|
> `workplans/`.
|
||||||
|
>
|
||||||
|
> **Layer declaration (accepted model v0.7):** Engine / Lifecycle. Machine-readable
|
||||||
|
> form: `layer.yaml`. PEP stance: `pep-stance.yaml`. This file states what the
|
||||||
|
> implementation currently does inside that layer; it does not restate doctrine.
|
||||||
|
|
||||||
## One-liner
|
## One-liner
|
||||||
|
|
||||||
secrets-engine is a decision-gated Python CLI that validates non-secret secret
|
secrets-engine is the Lifecycle engine for cataloged credential work: a
|
||||||
lane metadata and orchestrates narrowly scoped OpenBao policy, AppRole,
|
decision-gated Python CLI that validates non-secret lane metadata and
|
||||||
provisioning, verification, delivery, routing, handoff, and revocation actions.
|
orchestrates narrowly scoped OpenBao policy, AppRole, provisioning,
|
||||||
|
verification, delivery, routing, handoff, and revocation actions.
|
||||||
|
|
||||||
It is an OpenBao workflow client, not a vault, authorization service, identity
|
It is a deterministic API over OpenBao, not a vault, not a policy decision
|
||||||
provider, credential broker, or general secrets API.
|
point, not an identity provider, and not a general secrets API.
|
||||||
|
|
||||||
## Implemented Capabilities
|
## Implemented Capabilities
|
||||||
|
|
||||||
|
|
@ -33,15 +38,19 @@ provider, credential broker, or general secrets API.
|
||||||
|
|
||||||
- Resolves a catalog lane by catalog id or `approval.decision_ref`.
|
- Resolves a catalog lane by catalog id or `approval.decision_ref`.
|
||||||
- Resolves legacy lane decisions from State Hub by id, with tracked local YAML
|
- Resolves legacy lane decisions from State Hub by id, with tracked local YAML
|
||||||
mirrors retained only for non-production and explicit throwaway demos.
|
mirrors retained only for non-production and explicit throwaway demos. This is
|
||||||
- Fails every production live command closed while State Hub lacks the durable
|
not an access-engine decision record.
|
||||||
action-authorization endpoint. A local mirror can unlock a prod-labeled lane
|
- Fails every production live command closed while there is no durable
|
||||||
only when an explicit unsafe-demo switch, disabled Hub URL, and loopback
|
access-engine / ActionAuthorization record. That fail-closed row is the
|
||||||
OpenBao target are all present. Plans and `apply --dry-run` remain usable.
|
published unreachable-engine stance for `prod` in `pep-stance.yaml`. A local
|
||||||
|
mirror can unlock a prod-labeled lane only when an explicit unsafe-demo
|
||||||
|
switch, disabled Hub URL, and loopback OpenBao target are all present. Plans
|
||||||
|
and `apply --dry-run` remain usable.
|
||||||
- Builds and validates the flex-auth `ActionAuthorization` profile, including
|
- Builds and validates the flex-auth `ActionAuthorization` profile, including
|
||||||
exact lane/stage/action/target/actor/purpose matching, bounded validity,
|
exact lane/stage/action/target/actor/purpose matching, bounded validity,
|
||||||
State Hub authority, request digest and decision binding, accepted policy
|
State Hub authority, request digest and decision binding, accepted policy
|
||||||
package/version, and an independently required distinct-approver threshold.
|
package/version, and an independently required distinct-approver threshold.
|
||||||
|
Validation is consume-only; this process does not evaluate policy.
|
||||||
- Renders guarded OpenBao plans for exact consumer ACL policies and AppRoles.
|
- Renders guarded OpenBao plans for exact consumer ACL policies and AppRoles.
|
||||||
- Applies policy and AppRole metadata idempotently. Existing mounts render a
|
- Applies policy and AppRole metadata idempotently. Existing mounts render a
|
||||||
non-mutating check and are never created by apply.
|
non-mutating check and are never created by apply.
|
||||||
|
|
@ -116,7 +125,8 @@ cannot be recovered through that AppRole.
|
||||||
event on a best-effort basis. Posts carry stable idempotency/source headers.
|
event on a best-effort basis. Posts carry stable idempotency/source headers.
|
||||||
Each requested State Hub delivery receives an append-only local `delivered`,
|
Each requested State Hub delivery receives an append-only local `delivered`,
|
||||||
`queued`, `failed`, or `skipped-no-topic` companion record; edge-relay queued
|
`queued`, `failed`, or `skipped-no-topic` companion record; edge-relay queued
|
||||||
receipts retain only the non-secret outbox id.
|
receipts retain only the non-secret outbox id. This trail is attributive:
|
||||||
|
completeness is not claimed, and it is not `audit-core`.
|
||||||
- Every live privileged CLI handler records an attempt before lane-approval
|
- Every live privileged CLI handler records an attempt before lane-approval
|
||||||
resolution and a terminal success, verification failure, rejection,
|
resolution and a terminal success, verification failure, rejection,
|
||||||
interruption, or typed backend/input failure. Failure evidence contains the
|
interruption, or typed backend/input failure. Failure evidence contains the
|
||||||
|
|
@ -211,9 +221,11 @@ verification, `approle-login` is auth-capability handoff metadata, and
|
||||||
- First-class rotate, compromise, reactivate, lease-status, or audit report
|
- First-class rotate, compromise, reactivate, lease-status, or audit report
|
||||||
commands; lifecycle operations currently execute plans without persistent
|
commands; lifecycle operations currently execute plans without persistent
|
||||||
lane state.
|
lane state.
|
||||||
- Resolution of a durable State Hub action authorization and wiring its
|
- Resolution of a durable access-engine decision record / State Hub
|
||||||
validated approval threshold to each production handler.
|
ActionAuthorization and wiring its validated approval threshold to each
|
||||||
- Direct flex-auth evaluation, JWT signature verification, or identity
|
production handler. The consumer validator exists; the serving endpoint does
|
||||||
|
not, so live production remains fail-closed.
|
||||||
|
- Direct access-engine evaluation, JWT signature verification, or identity
|
||||||
authentication. KeyCape claims receive only a consumer preflight; OpenBao is
|
authentication. KeyCape claims receive only a consumer preflight; OpenBao is
|
||||||
responsible for cryptographic JWT validation.
|
responsible for cryptographic JWT validation.
|
||||||
- Runtime tenancy isolation; `org`, `repo`, consumers, and stages are catalog
|
- Runtime tenancy isolation; `org`, `repo`, consumers, and stages are catalog
|
||||||
|
|
@ -221,32 +233,55 @@ verification, `approle-login` is auth-capability handoff metadata, and
|
||||||
- Management or health verification of ESO, Kubernetes Secrets, deployments,
|
- Management or health verification of ESO, Kubernetes Secrets, deployments,
|
||||||
provider accounts, SSH issuance, tunnels, or remote transport.
|
provider accounts, SSH issuance, tunnels, or remote transport.
|
||||||
- Any backend other than the local `bao`/`vault` CLI speaking to OpenBao.
|
- Any backend other than the local `bao`/`vault` CLI speaking to OpenBao.
|
||||||
|
- An SSH-CA signing engine API. ops-warden still signs through its declared
|
||||||
|
OpenBao gap; this repository has accepted that surface as proposed only.
|
||||||
|
- A secret-use evidence engine API for kings-guard. `route` and `audit` are
|
||||||
|
operator summaries over local JSONL, not an observation surface.
|
||||||
|
- Emission to `audit-core`. Evidence today is local JSONL plus best-effort
|
||||||
|
State Hub progress notes, classified attributive, completeness not claimed.
|
||||||
|
- Named stance-application records (stage, failure mode, decision id present
|
||||||
|
only where rendered). Fail-closed production currently surfaces as a
|
||||||
|
`DecisionError` on the privileged-evidence path.
|
||||||
|
- Security-zone membership as a request claim. PEP scope is catalog stage.
|
||||||
|
|
||||||
## System Boundary
|
## System Boundary
|
||||||
|
|
||||||
- **OpenBao / railiance-platform** owns custody, policy enforcement, leases, and
|
- **OpenBao / railiance-platform** (Tooling) owns custody, policy enforcement,
|
||||||
audit. secrets-engine invokes it through supplied credentials.
|
leases, and backend audit. secrets-engine is the Lifecycle API over it.
|
||||||
- **flex-auth / State Hub decisions** own authorization. secrets-engine only
|
- **access-engine (`flex-auth`)** owns authorization decisions. secrets-engine
|
||||||
resolves and enforces recorded decision status.
|
consumes a decision record or applies its published unreachable-engine stance;
|
||||||
|
it does not evaluate policy.
|
||||||
|
- **approval-engine** owns the durable approval object. secrets-engine may
|
||||||
|
consume an approval as an input claim and must not store or mutate one.
|
||||||
|
- **gate-house** owns security doctrine. Doctrine reaches this engine only as it
|
||||||
|
already reached the decision, never as a side channel.
|
||||||
|
- **audit-core** owns evidence custody and integrity. Local JSONL and State Hub
|
||||||
|
notes are not that archive.
|
||||||
- **user-engine / key-cape** own identity, OIDC, MFA, and claims.
|
- **user-engine / key-cape** own identity, OIDC, MFA, and claims.
|
||||||
- **ops-warden** issues SSH certificates and routes non-SSH credential needs; it
|
- **ops-warden** issues SSH certificates (Staff PEP) and routes non-SSH
|
||||||
does not vend their values.
|
credential needs here; it does not vend their values. The SSH-CA write
|
||||||
|
surface is a proposed engine API, not a transferred lane.
|
||||||
- **ops-bridge** owns tunnels and remote execution transport and may consume a
|
- **ops-bridge** owns tunnels and remote execution transport and may consume a
|
||||||
scoped delivery path.
|
scoped delivery path.
|
||||||
- **workload/platform repositories** own ESO/Kubernetes delivery, provider
|
- **workload/platform repositories** own ESO/Kubernetes delivery, provider
|
||||||
rotation, and application health.
|
rotation, and application health.
|
||||||
- **info-tech-canon / net-kingdom** own canonical terminology and the
|
- **info-tech-canon / net-kingdom** own canonical terminology and the
|
||||||
cross-system security boundary.
|
cross-system security boundary. **gate-house** owns the layer model.
|
||||||
|
|
||||||
Canonical boundary:
|
Canonical boundary:
|
||||||
`net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`.
|
`net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`.
|
||||||
|
Layer model: `net-kingdom/canon/standards/security-layer-model_v0.7.md`.
|
||||||
|
Working companion: `net-kingdom/SECURITY-COMPANION.md`.
|
||||||
|
|
||||||
## Security Rules
|
## Security Rules
|
||||||
|
|
||||||
- Never place raw secret values in Git, State Hub, chat, prompts, workplans,
|
- Never place raw secret values in Git, State Hub, chat, prompts, workplans,
|
||||||
normal logs, or evidence.
|
normal logs, or evidence.
|
||||||
- Never treat catalog admission, a dry-run, or an old workload CCR as approval
|
- Never render or cache an authorization decision. Catalog admission, a dry-run,
|
||||||
for a new production auth surface.
|
an old workload CCR, or a local fixture is not an access-engine allow.
|
||||||
|
- Never treat silence from `access-engine` as permission. Production live
|
||||||
|
actions fail closed; any unreachable-engine residue must be the published
|
||||||
|
stance, recorded, never implicit.
|
||||||
- Never mutate an existing shared mount or replace workload delivery by
|
- Never mutate an existing shared mount or replace workload delivery by
|
||||||
implication.
|
implication.
|
||||||
- Never add KV destruction back to ordinary `revoke`; irreversible custody
|
- Never add KV destruction back to ordinary `revoke`; irreversible custody
|
||||||
|
|
@ -254,7 +289,22 @@ Canonical boundary:
|
||||||
approved action. The live path remains disabled until that approval contract
|
approved action. The live path remains disabled until that approval contract
|
||||||
exists.
|
exists.
|
||||||
- Keep bootstrap and handoff material outside repositories with mode 0600 and
|
- Keep bootstrap and handoff material outside repositories with mode 0600 and
|
||||||
explicit expiry/revocation handling.
|
explicit expiry/revocation handling. Bootstrap is not an implicit fallback
|
||||||
|
from service identity.
|
||||||
|
- Never claim that local evidence or a missing record proves occurrence or
|
||||||
|
non-occurrence. Completeness is not claimed.
|
||||||
|
|
||||||
|
## Layer-model obligations (current vs intended)
|
||||||
|
|
||||||
|
| Obligation | Current | Intended |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Layer declaration | `INTENT.md` frontmatter + `layer.yaml` | Keep in this repository's own voice |
|
||||||
|
| One decision point | Consumer validator for ActionAuthorization; production live fail-closed | Consume an access-engine decision record before every protected side effect |
|
||||||
|
| PEP stance | `pep-stance.yaml`; prod fail-closed, build/test fail-open relative to access-engine | Published map equals shipped behaviour; stance application recorded by name |
|
||||||
|
| Evidence bound | Attributive local JSONL + best-effort State Hub | Load-bearing vs attributive classified; load-bearing to `audit-core` with cadence |
|
||||||
|
| SSH-CA surface | Proposed; not shipped | Engine API for ops-warden's Staff PEP; lane stewardship stays with ops-warden |
|
||||||
|
| Secret-use evidence | `route` / `audit` over local JSONL | Engine surface of lease/revocation/mount/rotation metadata |
|
||||||
|
| Agent credential | Bootstrap token file still accepted; KeyCape scaffold unwired | Per-task, time-bounded service identity; no standing engine credential |
|
||||||
|
|
||||||
## Where Current Work Lives
|
## Where Current Work Lives
|
||||||
|
|
||||||
|
|
@ -262,6 +312,7 @@ Canonical boundary:
|
||||||
- `docs/hardening-backlog.md` tracks exit from bootstrap mode.
|
- `docs/hardening-backlog.md` tracks exit from bootstrap mode.
|
||||||
- `history/` contains dated capability and intent assessments.
|
- `history/` contains dated capability and intent assessments.
|
||||||
- `INTENT.md` remains the stable aspirational direction.
|
- `INTENT.md` remains the stable aspirational direction.
|
||||||
|
- `layer.yaml` and `pep-stance.yaml` are the layer-model declaration surface.
|
||||||
|
|
||||||
## Provided Capabilities
|
## Provided Capabilities
|
||||||
|
|
||||||
|
|
@ -298,7 +349,7 @@ title: Non-secret routing and evidence pointers
|
||||||
description: Reports decision/readiness metadata and records scrubbed local and best-effort State Hub
|
description: Reports decision/readiness metadata and records scrubbed local and best-effort State Hub
|
||||||
evidence without returning secret values. Append-only delivery receipts expose State Hub failures,
|
evidence without returning secret values. Append-only delivery receipts expose State Hub failures,
|
||||||
and an allowlisted audit command summarizes lane operations and cleanup. KV verification can attest a
|
and an allowlisted audit command summarizes lane operations and cleanup. KV verification can attest a
|
||||||
supplied real unrelated identity, but the engine does not own identity selection. This is not a durable
|
supplied real unrelated identity, but the engine does not own identity selection. This is attributive
|
||||||
remote audit store.
|
local evidence, not audit-core and not a secret-use observation API.
|
||||||
keywords: [routing, evidence, state-hub, audit, secrets]
|
keywords: [routing, evidence, state-hub, audit, secrets]
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,14 @@ belongs to NetKingdom because it defines cross-system security infrastructure
|
||||||
responsibilities and boundaries across OpenBao, flex-auth, user-engine/key-cape,
|
responsibilities and boundaries across OpenBao, flex-auth, user-engine/key-cape,
|
||||||
ops-warden, ops-bridge, info-tech-canon, State Hub, and agents.
|
ops-warden, ops-bridge, info-tech-canon, State Hub, and agents.
|
||||||
|
|
||||||
|
The accepted layer model and working companion, which this repository now
|
||||||
|
declares against as Engine / Lifecycle, live at:
|
||||||
|
|
||||||
|
```text
|
||||||
|
net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||||||
|
net-kingdom/SECURITY-COMPANION.md
|
||||||
|
```
|
||||||
|
|
||||||
secrets-engine consumes that boundary and implements the secrets workflow,
|
secrets-engine consumes that boundary and implements the secrets workflow,
|
||||||
catalog, stage policies, OpenBao apply/delivery mechanics, and evidence model
|
catalog, stage policies, OpenBao apply/delivery mechanics, and evidence model
|
||||||
that the canonical document assigns to it.
|
that the canonical document assigns to it.
|
||||||
|
|
|
||||||
163
history/2026-08-29-layer-model-scope-intent-review.md
Normal file
163
history/2026-08-29-layer-model-scope-intent-review.md
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
# Review: Security layer model v0.7 vs INTENT, SCOPE, and implementation
|
||||||
|
|
||||||
|
Date: 2026-08-29
|
||||||
|
Author: grok
|
||||||
|
Standard: `net-kingdom/canon/standards/security-layer-model_v0.7.md` (accepted)
|
||||||
|
Companion: `net-kingdom/SECURITY-COMPANION.md` v0.2
|
||||||
|
Compared: adapted `INTENT.md`, updated `SCOPE.md`, current CLI implementation
|
||||||
|
Intake closed by this session: `SECRETS-IN-0001`
|
||||||
|
|
||||||
|
## Executive assessment
|
||||||
|
|
||||||
|
The accepted layer model confirms what this repository already was in practice
|
||||||
|
and had not yet declared in its own voice: **Engine, role Lifecycle** — a
|
||||||
|
deterministic API over OpenBao for cataloged credential lanes. The gate-house
|
||||||
|
review note at the top of `INTENT.md` was not a declaration. That note is now
|
||||||
|
replaced by frontmatter, prose, `layer.yaml`, and a published PEP stance map.
|
||||||
|
|
||||||
|
The intent remains directionally sound. The layer model does not move the
|
||||||
|
system boundary (OpenBao stays Tooling; `access-engine` stays the only PDP;
|
||||||
|
ops-warden stays the SSH Staff PEP). It **tightens the contract** this engine
|
||||||
|
owes at every protected side effect, and it **names two proposed surfaces**
|
||||||
|
this repository had not answered: an SSH-CA signing API, and secret-use
|
||||||
|
evidence for kings-guard.
|
||||||
|
|
||||||
|
`SCOPE.md` and the implementation already describe a guarded OpenBao CLI MVP
|
||||||
|
with one proven native workload pilot. Against the new intent they are
|
||||||
|
**aligned on layer and ownership, behind on PEP, decision, and evidence
|
||||||
|
obligations**. Several of those obligations overlap active work in
|
||||||
|
`SECRETS-WP-0007`; the new work is the layer-model remainder, not a restart of
|
||||||
|
CLI hardening.
|
||||||
|
|
||||||
|
A finding is raised against the §4 catalog cell, not against the proposed
|
||||||
|
layer: the catalog says this repository owns "custody". Custody is OpenBao's.
|
||||||
|
This engine owns the lifecycle API over that custody.
|
||||||
|
|
||||||
|
## What was declared
|
||||||
|
|
||||||
|
| Artifact | Content |
|
||||||
|
| --- | --- |
|
||||||
|
| `INTENT.md` frontmatter | `layer: Engine`, `role: Lifecycle` |
|
||||||
|
| `INTENT.md` body | Own-voice declaration, PEP shape, evidence bound, proposed surfaces |
|
||||||
|
| `layer.yaml` | Machine-readable declaration; owned OpenBao contact; no decision surface |
|
||||||
|
| `pep-stance.yaml` | Unreachable-engine stance by catalog stage; prod fail-closed |
|
||||||
|
| `scripts/check_layer_conformance.py` | Mechanical check of the above |
|
||||||
|
| `tests/test_layer_conformance.py` | Declaration + published map equals shipped prod fail-closed |
|
||||||
|
|
||||||
|
Contest of the proposed **layer** (Engine): none. The determinism test holds.
|
||||||
|
|
||||||
|
Contest of **catalog wording**: yes — "custody" should not appear as this
|
||||||
|
engine's owned property.
|
||||||
|
|
||||||
|
Answers to proposed ownerships:
|
||||||
|
|
||||||
|
| Proposed surface | Answer |
|
||||||
|
| --- | --- |
|
||||||
|
| SSH-CA signing write (`ops-warden` §5.3 gap) | **Accept** as a Lifecycle engine API. **Decline** operational SSH-lane stewardship. ops-warden remains the Staff PEP. |
|
||||||
|
| Secret-use evidence (`kings-guard`) | **Accept** as a proposed Lifecycle engine surface, bounded by §9.6. Not shipped. |
|
||||||
|
|
||||||
|
## INTENT vs SCOPE
|
||||||
|
|
||||||
|
No contradiction on layer, owners, or forbidden claims. Drift is maturity:
|
||||||
|
|
||||||
|
| Intent claim | SCOPE today | Gap kind |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Engine / Lifecycle declaration | Declared | Closed this session |
|
||||||
|
| Consume an access-engine decision before every protected side effect | Consumer validator exists; production live fail-closed because the durable object is not served | Implementation (WP-0007-T04 + WP-0008-T02) |
|
||||||
|
| Published PEP stance equals shipped behaviour, stance application recorded | Map published; prod fail-closed matches; records are `DecisionError`, not named stance fields | Implementation (WP-0008-T01) |
|
||||||
|
| Evidence to `audit-core` under §9.6 | Local JSONL + best-effort State Hub; attributive; completeness not claimed | Implementation (WP-0008-T03) |
|
||||||
|
| SSH-CA engine API | Not implemented; ops-warden still writes OpenBao | Proposed surface (WP-0008-T04) |
|
||||||
|
| Secret-use evidence API | `route` / `audit` summarize local JSONL | Proposed surface (WP-0008-T05) |
|
||||||
|
| No standing agent credential | Bootstrap token file still accepted; KeyCape scaffold unwired to OpenBao | Hardening (WP-0007-T05 / WP-0008-T06) |
|
||||||
|
| Service API | CLI only | Deferred until WP-0007 exit criteria |
|
||||||
|
| Every allow has a lifetime | Delivery sessions self-revoke; decision TTL waits on durable authorization | Partial |
|
||||||
|
| Doctrine as claims | Catalog/policies are local YAML | Later; do not compile outcomes here |
|
||||||
|
|
||||||
|
`SCOPE.md` remains the implemented-capability ledger. Volatile workplan status
|
||||||
|
stays out of it. The new durable additions are the layer table, the updated
|
||||||
|
system boundary, and the explicit not-implemented layer-model surfaces.
|
||||||
|
|
||||||
|
## INTENT vs implementation
|
||||||
|
|
||||||
|
The strongest implemented slice is unchanged:
|
||||||
|
|
||||||
|
```text
|
||||||
|
catalog -> approval-status or fail-closed prod gate -> guarded plan
|
||||||
|
-> policy/AppRole apply -> bounded presence/capability verification
|
||||||
|
-> CLI-local exec/handoff -> non-secret route/evidence pointer
|
||||||
|
```
|
||||||
|
|
||||||
|
That slice is a Lifecycle engine **shape**. It is not yet a conforming PEP.
|
||||||
|
|
||||||
|
### Scorecard against the accepted model
|
||||||
|
|
||||||
|
| Rule | Assessment | Evidence | Material gap |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| §3.3 Lifecycle | Aligned in shape | OpenBao isolated in `openbao.py`; catalog/plan/delivery/lifecycle are the API | Service API absent; CLI is the only surface |
|
||||||
|
| §6 one decision point | Partial, fail-closed | `authorization.py` validates a supplied object and does not evaluate policy. Production live commands refuse without a durable ActionAuthorization. Build/test still accept State Hub status or a local fixture | Local/hub status is not an access-engine decision record. Risk of compiled early decision if fixtures return for production |
|
||||||
|
| §6.1 compiled data | Watch | Catalog admission and publication-scope policy clamp lanes; they must not become the allow | Keep catalog descriptive; effects stay in the decision |
|
||||||
|
| §6.4 PEP obligation 1 | Partial | Privileged handlers record attempt/terminal evidence; production refusal is a `DecisionError` | Stance application is not recorded as named fields (stage, failure mode, decision id present only where rendered) |
|
||||||
|
| §6.4 PEP obligation 2 | Aligned as declared | No verdict cache; `verdict_caching: none` | Must remain none when ActionAuthorization is live |
|
||||||
|
| §6.4 PEP obligation 3 | Published, not yet loaded | `pep-stance.yaml` is total over build/test/prod/unknown; tests pin prod fail-closed to `_require_lane_approval` | Code still hardcodes the gate rather than loading the map. Build/test fail-open is relative to access-engine, not a manufactured allow — that residue is itself a gap |
|
||||||
|
| §6.4 PEP obligation 4 | Attributive | Local JSONL + hub receipts; OpenBao remains backend audit | Completeness not claimed (correct). No `audit-core` emit |
|
||||||
|
| §9.6 load-bearing vs attributive | Undeclared in code | `layer.yaml` classifies today's trail as attributive | Destroy, revoke, and dual-control provision will become load-bearing once they are production-live. They need atomic local outbox + cadence/heartbeat **before** any control branches on them |
|
||||||
|
| §9.7 lifetime | Partial | AppRole sessions self-revoke; ActionAuthorization has `expires_at` in the consumer schema | Production never reaches the lifetime because live prod is disabled. Bootstrap tokens remain standing credentials |
|
||||||
|
| §20.2 credentials after a decision | Principle aligned; production blocked | Fail-closed is the honest residue while the PDP object is unserved | Do not reopen production on hub status |
|
||||||
|
| Staff must not touch OpenBao | External | ops-warden still has the SSH-CA write gap with intended owner here | Engine surface not shipped; do not take the Staff lane |
|
||||||
|
| Agent rule 1 (no standing credential) | Not met | `--bootstrap-token-file` and `BAO_TOKEN` are the live auth path | KeyCape scaffold exists and is deliberately unwired |
|
||||||
|
| Observation / actuation | Correctly not claimed | Companion §10: nothing is observed in production; nothing can be contained automatically | Do not plan as if either existed |
|
||||||
|
|
||||||
|
### Overlap with active workplans
|
||||||
|
|
||||||
|
`SECRETS-WP-0007` already owns CLI hardening that the 2026-08-23 assessment
|
||||||
|
called P0/P1: merge-safe provision (done), lifecycle split (in progress),
|
||||||
|
exact-action authorization (in progress), session self-revocation (in
|
||||||
|
progress), verification/evidence (in progress). Those tasks stay there.
|
||||||
|
|
||||||
|
What the layer model **adds**, and what `SECRETS-WP-0008` is for:
|
||||||
|
|
||||||
|
1. Bind the published PEP stance to shipped behaviour and record stance
|
||||||
|
application by name.
|
||||||
|
2. Treat the durable ActionAuthorization as an **access-engine decision
|
||||||
|
record** under §6.4, not as a State Hub status check, once WP-0007-T04's
|
||||||
|
endpoint exists.
|
||||||
|
3. Classify evidence and emit it to `audit-core`.
|
||||||
|
4. Answer the two proposed surfaces (SSH-CA API, secret-use evidence) in this
|
||||||
|
repository's own contract.
|
||||||
|
5. Retire standing engine credentials as a layer obligation, not only as
|
||||||
|
bootstrap hygiene.
|
||||||
|
|
||||||
|
Do not start service mode, runtime tenancy, or a second custody backend from
|
||||||
|
this review. Companion §10 still holds: nothing is observed in production, and
|
||||||
|
nothing can be contained automatically.
|
||||||
|
|
||||||
|
## Recommended sequence
|
||||||
|
|
||||||
|
1. Keep `SECRETS-WP-0007` as the CLI-hardening track. Do not reopen live
|
||||||
|
production on coarse hub status.
|
||||||
|
2. Land `SECRETS-WP-0008-T01` — load `pep-stance.yaml` as the source of the
|
||||||
|
fail-closed gate and record stance application fields.
|
||||||
|
3. When the durable authorization object is served, consume it as a decision
|
||||||
|
record (`WP-0008-T02` / `WP-0007-T04`) with digest+lifetime replay rules.
|
||||||
|
4. Classify evidence; emit load-bearing classes to `audit-core` with a local
|
||||||
|
outbox; declare cadence or heartbeat.
|
||||||
|
5. Publish the SSH-CA engine contract with ops-warden before writing a client
|
||||||
|
replacement. Keep their Staff PEP.
|
||||||
|
6. Publish the secret-use evidence contract with kings-guard. `audit` is not
|
||||||
|
that contract.
|
||||||
|
7. Wire service identity only after the platform-owned OpenBao JWT role exists.
|
||||||
|
Bootstrap remains break-glass.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
`INTENT.md` now declares Engine / Lifecycle in this repository's own voice and
|
||||||
|
accepts the two proposed surfaces without taking Staff work. `SCOPE.md` is
|
||||||
|
honest about the CLI MVP and the new not-implemented obligations. The
|
||||||
|
implementation is a Lifecycle engine in shape and a partial PEP in behaviour:
|
||||||
|
production fail-closed is the correct residue, build/test still run on a
|
||||||
|
pre-decision-record approval path, and evidence is attributive local notes
|
||||||
|
rather than `audit-core`.
|
||||||
|
|
||||||
|
The repository should not advertise itself as a service API, a second PDP, a
|
||||||
|
custody backend, an SSH issuer, or an observation system. Follow-on work is
|
||||||
|
`SECRETS-WP-0008`.
|
||||||
|
|
@ -7,13 +7,21 @@ id: SECRETS-IN-0001
|
||||||
kind: intake
|
kind: intake
|
||||||
title: 'Declaration requested: state this repository''s layer in INTENT.md (security
|
title: 'Declaration requested: state this repository''s layer in INTENT.md (security
|
||||||
layer model §11)'
|
layer model §11)'
|
||||||
status: open
|
status: closed
|
||||||
origin: cross-repo
|
origin: cross-repo
|
||||||
origin_ref: net-kingdom security-layer-model_v0.4 §11
|
origin_ref: net-kingdom security-layer-model_v0.7 §11
|
||||||
priority: low
|
priority: low
|
||||||
owner: secrets-engine
|
owner: secrets-engine
|
||||||
requested_by: gate-house
|
requested_by: gate-house
|
||||||
proposed_layer: Engine
|
proposed_layer: Engine
|
||||||
|
resolution: >-
|
||||||
|
Declared Engine / Lifecycle in INTENT.md frontmatter and layer.yaml on
|
||||||
|
2026-08-29 against accepted v0.7. Layer not contested. Catalog cell
|
||||||
|
"custody" is a finding: OpenBao owns custody; this engine owns the
|
||||||
|
lifecycle API over it. SSH-CA signing accepted as a proposed engine API
|
||||||
|
and declined as a Staff lane. Secret-use evidence accepted as proposed.
|
||||||
|
Review: history/2026-08-29-layer-model-scope-intent-review.md.
|
||||||
|
Workplan: SECRETS-WP-0008.
|
||||||
description: 'A conformance sweep on 2026-08-28 found this repository has no layer
|
description: 'A conformance sweep on 2026-08-28 found this repository has no layer
|
||||||
declaration of its own. It carries a layering review note gate-house wrote into
|
declaration of its own. It carries a layering review note gate-house wrote into
|
||||||
the top of its INTENT.md on 2026-08-24, and that note names a layer — but the words
|
the top of its INTENT.md on 2026-08-24, and that note names a layer — but the words
|
||||||
|
|
|
||||||
144
layer.yaml
Normal file
144
layer.yaml
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
# secrets-engine — NetKingdom security layer declaration
|
||||||
|
#
|
||||||
|
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||||||
|
# Companion: net-kingdom/SECURITY-COMPANION.md
|
||||||
|
# Voice: INTENT.md (this repository's own declaration, §11)
|
||||||
|
# Validate: python3 scripts/check_layer_conformance.py
|
||||||
|
#
|
||||||
|
# §11 requires a machine-readable form because prose cannot distinguish a
|
||||||
|
# declaration from a transcribed review. ops-warden offered the layer.yaml
|
||||||
|
# shape estate-wide; this file is that shape adapted for a Lifecycle engine
|
||||||
|
# rather than a Staff repository.
|
||||||
|
#
|
||||||
|
# §5 (Staff never touches Tooling) does not apply to this repository's OpenBao
|
||||||
|
# client. A Lifecycle engine is the deterministic API over Tooling it fronts.
|
||||||
|
# OpenBao contact here is owned, not a §5.3 gap.
|
||||||
|
|
||||||
|
schema_version: "0.1"
|
||||||
|
framework: netkingdom-security-layer-model
|
||||||
|
standard_version: "0.7"
|
||||||
|
repository: secrets-engine
|
||||||
|
layer: engine
|
||||||
|
role: lifecycle
|
||||||
|
declared_by: INTENT.md
|
||||||
|
declared_at: "2026-08-29"
|
||||||
|
|
||||||
|
# §3.3: a Lifecycle engine is a deterministic API over Tooling it owns.
|
||||||
|
# OpenBao remains the vault; this engine fronts it.
|
||||||
|
owned_tooling:
|
||||||
|
- id: openbao-lifecycle
|
||||||
|
tooling: OpenBao
|
||||||
|
modules:
|
||||||
|
- src/secrets_engine/openbao.py
|
||||||
|
operations:
|
||||||
|
- "bao policy/auth/kv subprocess adapter"
|
||||||
|
- "CAS-aware KV create/patch via JSON input files, never argv values"
|
||||||
|
note: >-
|
||||||
|
This is the owned Lifecycle contact, not a Staff §5 shape. A new direct
|
||||||
|
OpenBao client outside the listed modules is a finding.
|
||||||
|
|
||||||
|
# §6: no repository other than access-engine exposes an authorization decision
|
||||||
|
# surface. secrets-engine consumes and validates a supplied ActionAuthorization
|
||||||
|
# object; it does not evaluate policy.
|
||||||
|
decision_surfaces_exposed: none
|
||||||
|
|
||||||
|
# §6.4 — apply, provision, exec, handoff, revoke, and lifecycle mutations
|
||||||
|
# cause protected side effects. Being PEP-shaped does not change the layer.
|
||||||
|
pep_shaped: true
|
||||||
|
pep_stance: pep-stance.yaml
|
||||||
|
protected_actions:
|
||||||
|
- apply
|
||||||
|
- provision
|
||||||
|
- verify
|
||||||
|
- exec
|
||||||
|
- handoff
|
||||||
|
- revoke
|
||||||
|
- lifecycle-suspend
|
||||||
|
- lifecycle-deactivate
|
||||||
|
- lifecycle-destroy
|
||||||
|
|
||||||
|
# §13 proposed capabilities. Owner status is proposed, not assented, until
|
||||||
|
# the surface exists in this repository's own contract.
|
||||||
|
proposed_capabilities:
|
||||||
|
|
||||||
|
- id: ssh-ca-signing-surface
|
||||||
|
state: unowned-capability
|
||||||
|
capability: >-
|
||||||
|
Deterministic engine API for OpenBao SSH-CA signing, so a Staff PEP
|
||||||
|
(ops-warden) does not hold a direct VaultCA write.
|
||||||
|
intended_owner: secrets-engine
|
||||||
|
owner_status: proposed
|
||||||
|
blocked_on: >-
|
||||||
|
No engine API exists yet. ops-warden continues to sign through its
|
||||||
|
declared §5.3 gap. This repository accepts the engine surface and
|
||||||
|
declines operational ownership of the SSH access lane.
|
||||||
|
review: "2026-11-28"
|
||||||
|
consequence: >-
|
||||||
|
ops-warden's ssh-ca-signing-write gap remains the production path.
|
||||||
|
|
||||||
|
- id: secret-use-evidence
|
||||||
|
state: unowned-capability
|
||||||
|
capability: >-
|
||||||
|
Lease, revocation, mount, rotation, and delivery-session metadata
|
||||||
|
exposed as an engine surface for kings-guard secret-abuse posture.
|
||||||
|
intended_owner: secrets-engine
|
||||||
|
owner_status: proposed
|
||||||
|
blocked_on: >-
|
||||||
|
Local JSONL plus best-effort State Hub notes exist; they are not an
|
||||||
|
engine API and they are not audit-core. Completeness is not claimed.
|
||||||
|
review: "2026-11-28"
|
||||||
|
consequence: >-
|
||||||
|
kings-guard secret-abuse posture stays fixture-driven.
|
||||||
|
|
||||||
|
# Contacts that are not Tooling, recorded so the check is total.
|
||||||
|
non_tooling_clients:
|
||||||
|
|
||||||
|
- id: state-hub-decisions-and-progress
|
||||||
|
target: state-hub
|
||||||
|
layer: not-catalogued
|
||||||
|
modules:
|
||||||
|
- src/secrets_engine/decisions.py
|
||||||
|
- src/secrets_engine/evidence.py
|
||||||
|
operation: "HTTP GET /decisions/{id} and POST /progress/"
|
||||||
|
write: true
|
||||||
|
note: >-
|
||||||
|
Outside §5 by the scope rule: State Hub is not a §4 Tooling row.
|
||||||
|
Decisions consumed from it are a gap relative to access-engine, not a
|
||||||
|
Tooling contact. Progress notes are not a security state plane.
|
||||||
|
|
||||||
|
- id: access-engine-action-authorization
|
||||||
|
target: access-engine (flex-auth)
|
||||||
|
layer: engine
|
||||||
|
modules:
|
||||||
|
- src/secrets_engine/authorization.py
|
||||||
|
operation: "Local validation of a supplied ActionAuthorization object"
|
||||||
|
write: false
|
||||||
|
note: >-
|
||||||
|
Engine-to-engine consume, not a decision surface. The durable State Hub
|
||||||
|
endpoint that would serve the object is not yet available; production
|
||||||
|
live actions therefore fail closed (see pep-stance.yaml).
|
||||||
|
|
||||||
|
- id: key-cape-service-auth-scaffold
|
||||||
|
target: key-cape
|
||||||
|
layer: tooling
|
||||||
|
modules:
|
||||||
|
- src/secrets_engine/service_auth.py
|
||||||
|
operation: "HTTPS client_credentials exchange; not connected to OpenBao"
|
||||||
|
write: false
|
||||||
|
note: >-
|
||||||
|
key-cape is catalogued Tooling. This contact is an identity-token
|
||||||
|
preflight only and is deliberately not a write into OpenBao. Wiring it
|
||||||
|
as OpenBao JWT login remains blocked on the platform-owned role.
|
||||||
|
|
||||||
|
# §9.6 — what this repository may claim about evidence it writes today.
|
||||||
|
evidence_bound:
|
||||||
|
kind: attributive
|
||||||
|
proves:
|
||||||
|
- local JSONL records that were written were not rewritten by this engine
|
||||||
|
does_not_prove:
|
||||||
|
- that a record was ever sent to audit-core
|
||||||
|
- absence of a record as evidence of non-occurrence
|
||||||
|
- completeness of the trail
|
||||||
|
destination_today: "local JSONL plus best-effort State Hub progress notes"
|
||||||
|
intended_destination: audit-core
|
||||||
|
completeness_claimed: false
|
||||||
85
pep-stance.yaml
Normal file
85
pep-stance.yaml
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
# secrets-engine — PEP unreachable-engine stance map
|
||||||
|
#
|
||||||
|
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md §6.4, §9.3
|
||||||
|
# Companion: net-kingdom/SECURITY-COMPANION.md §5
|
||||||
|
# Voice: INTENT.md / layer.yaml
|
||||||
|
# Validate: pytest tests/test_layer_conformance.py
|
||||||
|
#
|
||||||
|
# §6.4 obligation 3 requires a declared unreachable-engine stance that is
|
||||||
|
# total, scoped per zone or equivalent, carries no implicit default and no
|
||||||
|
# per-call discretion, and is published rather than held in code comments.
|
||||||
|
# Catalog stage is the equivalent scope until security-zone membership arrives
|
||||||
|
# as a claim on the decision.
|
||||||
|
#
|
||||||
|
# The property that makes this worth reading: tests/test_layer_conformance.py
|
||||||
|
# asserts this map against the shipped production fail-closed gate in
|
||||||
|
# secrets_engine.cli._require_lane_approval. A published map free to drift
|
||||||
|
# from the code is worse than none.
|
||||||
|
|
||||||
|
schema_version: "0.1"
|
||||||
|
framework: netkingdom-security-layer-model
|
||||||
|
standard_version: "0.7"
|
||||||
|
repository: secrets-engine
|
||||||
|
pep_shape: true
|
||||||
|
declared_by: INTENT.md
|
||||||
|
decision_engine: access-engine # flex-auth until the governed rename
|
||||||
|
scope: catalog-stage # equivalent scope; not security-zones yet
|
||||||
|
|
||||||
|
protected_action: >-
|
||||||
|
OpenBao metadata apply, KV provision, verification, exec delivery,
|
||||||
|
auth-capability handoff, native revoke, and lifecycle
|
||||||
|
suspend/deactivate/destroy
|
||||||
|
|
||||||
|
# Total by construction over every catalog stage plus unknown.
|
||||||
|
# No implicit default — an unlisted value is a config error, not a fallback.
|
||||||
|
# "fail_closed" means no protected side effect without a durable
|
||||||
|
# access-engine / ActionAuthorization record.
|
||||||
|
# "fail_open" here means the engine-unreachable residue: proceed only under
|
||||||
|
# the existing lane-approval check (State Hub or local fixture), which is
|
||||||
|
# itself a tracked gap relative to access-engine, not a manufactured allow.
|
||||||
|
stance:
|
||||||
|
build: fail_open
|
||||||
|
test: fail_open
|
||||||
|
prod: fail_closed
|
||||||
|
unknown: fail_closed
|
||||||
|
|
||||||
|
# Explicit, three-factor exception. Not a stance row and not a default.
|
||||||
|
# All three must hold or the production gate remains closed.
|
||||||
|
demo_exception:
|
||||||
|
id: unsafe-local-demo
|
||||||
|
requires:
|
||||||
|
- "SECRETS_ENGINE_UNSAFE_DEMO=1"
|
||||||
|
- "hub URL empty"
|
||||||
|
- "OpenBao target is loopback"
|
||||||
|
applies_to: prod
|
||||||
|
note: >-
|
||||||
|
Throwaway local demonstration only. Not a production residue and not
|
||||||
|
available when any one factor is missing.
|
||||||
|
|
||||||
|
on_apply:
|
||||||
|
recorded_fields:
|
||||||
|
- stage
|
||||||
|
- action
|
||||||
|
- approval_status # rejected when the stance refuses
|
||||||
|
- error_type # DecisionError when fail_closed fires
|
||||||
|
- decision_id # present only where a decision was resolved
|
||||||
|
written_to:
|
||||||
|
- "local JSONL (.evidence/evidence-YYYY-MM-DD.jsonl)"
|
||||||
|
- "best-effort State Hub progress note"
|
||||||
|
never_recorded: "any secret material, token, password, or raw value"
|
||||||
|
gap: >-
|
||||||
|
Stance application is currently recorded as a DecisionError on the
|
||||||
|
privileged-evidence path, not as named stance fields (stage, failure
|
||||||
|
mode, decision id present only where rendered). Closing that gap is
|
||||||
|
SECRETS-WP-0008-T01.
|
||||||
|
|
||||||
|
# §6.4 obligation 2 — the verdict is never cached. A retry of the same
|
||||||
|
# canonical request digest inside the decision lifetime is the decision
|
||||||
|
# being used as issued; a different resource is not.
|
||||||
|
verdict_caching: none
|
||||||
|
|
||||||
|
# §6.4 obligation 4 / §9.6 — attributive today. No control branches on the
|
||||||
|
# presence of a local evidence record. Completeness is not claimed.
|
||||||
|
reconstructability:
|
||||||
|
bound: "§9.6 attributive — completeness is not claimed"
|
||||||
|
declared_at: layer.yaml#evidence_bound
|
||||||
178
scripts/check_layer_conformance.py
Normal file
178
scripts/check_layer_conformance.py
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Check secrets-engine against the NetKingdom security layer model (§3.3, §6, §11).
|
||||||
|
|
||||||
|
Read-only. This is the Engine/Lifecycle adaptation of the ops-warden reference
|
||||||
|
checker. §5 Staff shapes do not apply to the owned OpenBao contact.
|
||||||
|
|
||||||
|
Mechanical checks:
|
||||||
|
|
||||||
|
- a machine-readable declaration exists and says Engine / Lifecycle
|
||||||
|
- INTENT.md frontmatter matches that declaration
|
||||||
|
- no authorization decision surface is exposed
|
||||||
|
- the PEP stance map is published at the path named in the declaration
|
||||||
|
- every OpenBao subprocess adapter lives in a module listed as owned tooling
|
||||||
|
|
||||||
|
Exit 0 clean, 1 finding, 2 declaration malformed.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
SRC = ROOT / "src" / "secrets_engine"
|
||||||
|
DECL = ROOT / "layer.yaml"
|
||||||
|
INTENT = ROOT / "INTENT.md"
|
||||||
|
|
||||||
|
BAO_ARGV = re.compile(
|
||||||
|
r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b|self\.bao_bin)\s*,"""
|
||||||
|
)
|
||||||
|
DECISION_SURFACE = re.compile(
|
||||||
|
r"""\b(evaluate_policy|check_permission|render_decision|pdp_decide)\b"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_declaration() -> dict:
|
||||||
|
if not DECL.exists():
|
||||||
|
print(f"MISSING: {DECL} — secrets-engine must declare in its own voice (§11)")
|
||||||
|
raise SystemExit(2)
|
||||||
|
decl = yaml.safe_load(DECL.read_text())
|
||||||
|
for key in (
|
||||||
|
"layer",
|
||||||
|
"role",
|
||||||
|
"repository",
|
||||||
|
"standard_version",
|
||||||
|
"owned_tooling",
|
||||||
|
"decision_surfaces_exposed",
|
||||||
|
"pep_shaped",
|
||||||
|
"pep_stance",
|
||||||
|
):
|
||||||
|
if key not in decl:
|
||||||
|
print(f"MALFORMED: layer.yaml has no {key!r}")
|
||||||
|
raise SystemExit(2)
|
||||||
|
if decl["layer"] != "engine":
|
||||||
|
print(f"MALFORMED: declared layer is {decl['layer']!r}, expected 'engine'")
|
||||||
|
raise SystemExit(2)
|
||||||
|
if decl["role"] != "lifecycle":
|
||||||
|
print(f"MALFORMED: declared role is {decl['role']!r}, expected 'lifecycle'")
|
||||||
|
raise SystemExit(2)
|
||||||
|
if decl["repository"] != "secrets-engine":
|
||||||
|
print(f"MALFORMED: repository is {decl['repository']!r}")
|
||||||
|
raise SystemExit(2)
|
||||||
|
return decl
|
||||||
|
|
||||||
|
|
||||||
|
def intent_frontmatter() -> dict:
|
||||||
|
text = INTENT.read_text(encoding="utf-8")
|
||||||
|
if not text.startswith("---"):
|
||||||
|
print("MALFORMED: INTENT.md has no YAML frontmatter (§11 / companion §2)")
|
||||||
|
raise SystemExit(2)
|
||||||
|
end = text.find("\n---", 3)
|
||||||
|
if end < 0:
|
||||||
|
print("MALFORMED: INTENT.md frontmatter is unclosed")
|
||||||
|
raise SystemExit(2)
|
||||||
|
return yaml.safe_load(text[3:end]) or {}
|
||||||
|
|
||||||
|
|
||||||
|
def owned_modules(decl: dict) -> set[str]:
|
||||||
|
names: set[str] = set()
|
||||||
|
for entry in decl.get("owned_tooling", []):
|
||||||
|
for module in entry.get("modules", []):
|
||||||
|
names.add(Path(module).name)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def scan_bao_modules() -> dict[str, list[int]]:
|
||||||
|
found: dict[str, list[int]] = {}
|
||||||
|
for path in sorted(SRC.rglob("*.py")):
|
||||||
|
hits: list[int] = []
|
||||||
|
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
||||||
|
stripped = line.strip()
|
||||||
|
if stripped.startswith("#"):
|
||||||
|
continue
|
||||||
|
if BAO_ARGV.search(line):
|
||||||
|
hits.append(n)
|
||||||
|
if hits:
|
||||||
|
found[path.name] = hits
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def scan_decision_surfaces() -> dict[str, list[int]]:
|
||||||
|
found: dict[str, list[int]] = {}
|
||||||
|
for path in sorted(SRC.rglob("*.py")):
|
||||||
|
hits: list[int] = []
|
||||||
|
for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
|
||||||
|
if DECISION_SURFACE.search(line):
|
||||||
|
hits.append(n)
|
||||||
|
if hits:
|
||||||
|
found[path.name] = hits
|
||||||
|
return found
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--report", action="store_true")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
decl = load_declaration()
|
||||||
|
front = intent_frontmatter()
|
||||||
|
ok = True
|
||||||
|
|
||||||
|
if str(front.get("layer", "")).lower() != "engine":
|
||||||
|
ok = False
|
||||||
|
print("FINDING: INTENT.md frontmatter layer is not Engine")
|
||||||
|
if str(front.get("role", "")).lower() != "lifecycle":
|
||||||
|
ok = False
|
||||||
|
print("FINDING: INTENT.md frontmatter role is not Lifecycle")
|
||||||
|
|
||||||
|
if decl["decision_surfaces_exposed"] not in {None, "none"}:
|
||||||
|
ok = False
|
||||||
|
print("FINDING: decision_surfaces_exposed is not none — §6 forbids a second PDP")
|
||||||
|
|
||||||
|
surfaces = scan_decision_surfaces()
|
||||||
|
if surfaces:
|
||||||
|
ok = False
|
||||||
|
print("FINDING: possible authorization decision surface in source:")
|
||||||
|
for name, lines in sorted(surfaces.items()):
|
||||||
|
print(f" src/secrets_engine/{name}: line(s) {', '.join(map(str, lines[:6]))}")
|
||||||
|
|
||||||
|
stance = ROOT / str(decl["pep_stance"])
|
||||||
|
if decl.get("pep_shaped") and not stance.is_file():
|
||||||
|
ok = False
|
||||||
|
print(f"FINDING: pep_shaped but {decl['pep_stance']} is missing (§6.4 / §13.1)")
|
||||||
|
|
||||||
|
found = scan_bao_modules()
|
||||||
|
owned = owned_modules(decl)
|
||||||
|
undeclared = {name: lines for name, lines in found.items() if name not in owned}
|
||||||
|
if undeclared:
|
||||||
|
ok = False
|
||||||
|
print("FINDING: OpenBao adapter outside owned_tooling modules:")
|
||||||
|
for name, lines in sorted(undeclared.items()):
|
||||||
|
print(f" src/secrets_engine/{name}: line(s) {', '.join(map(str, lines[:6]))}")
|
||||||
|
|
||||||
|
if args.report:
|
||||||
|
print(
|
||||||
|
f"{decl['repository']} — layer: {decl['layer']} "
|
||||||
|
f"role: {decl['role']} (model v{decl['standard_version']})"
|
||||||
|
)
|
||||||
|
print(f"declared by {decl['declared_by']}")
|
||||||
|
print(f"pep stance: {decl['pep_stance']}")
|
||||||
|
print(f"owned OpenBao modules: {sorted(owned)}")
|
||||||
|
print(f"OpenBao argv adapters found: {sorted(found)}")
|
||||||
|
|
||||||
|
if ok and not args.report:
|
||||||
|
print(
|
||||||
|
"PASS — Engine/Lifecycle declaration present, no decision surface, "
|
||||||
|
f"{len(found)} OpenBao adapter module(s) owned."
|
||||||
|
)
|
||||||
|
elif ok:
|
||||||
|
print("\nPASS — declaration, owned tooling, and PEP stance path hold.")
|
||||||
|
return 0 if ok else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
117
tests/test_layer_conformance.py
Normal file
117
tests/test_layer_conformance.py
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
"""Layer-model conformance (security-layer-model_v0.7 §3.3, §6, §11).
|
||||||
|
|
||||||
|
The declaration must be this repository's own, machine-readable, and equal to
|
||||||
|
the shipped production fail-closed gate. A published stance map that may drift
|
||||||
|
from the code is worse than none.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from secrets_engine.catalog import validate_entry
|
||||||
|
from secrets_engine.cli import _require_lane_approval
|
||||||
|
from secrets_engine.errors import DecisionError
|
||||||
|
|
||||||
|
from tests.test_catalog import VALID
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
SCRIPT = ROOT / "scripts" / "check_layer_conformance.py"
|
||||||
|
DECL = ROOT / "layer.yaml"
|
||||||
|
STANCE = ROOT / "pep-stance.yaml"
|
||||||
|
INTENT = ROOT / "INTENT.md"
|
||||||
|
|
||||||
|
|
||||||
|
def _decl() -> dict:
|
||||||
|
return yaml.safe_load(DECL.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def _stance() -> dict:
|
||||||
|
return yaml.safe_load(STANCE.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_declares_engine_lifecycle_in_its_own_voice():
|
||||||
|
assert DECL.exists(), "no layer.yaml — §11 requires a machine-readable declaration"
|
||||||
|
data = _decl()
|
||||||
|
assert data["repository"] == "secrets-engine"
|
||||||
|
assert data["layer"] == "engine"
|
||||||
|
assert data["role"] == "lifecycle"
|
||||||
|
assert data["declared_by"] == "INTENT.md"
|
||||||
|
assert data["decision_surfaces_exposed"] == "none"
|
||||||
|
assert data["pep_shaped"] is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_intent_frontmatter_matches_declaration():
|
||||||
|
text = INTENT.read_text(encoding="utf-8")
|
||||||
|
assert text.startswith("---"), "companion §2 requires INTENT.md frontmatter"
|
||||||
|
end = text.find("\n---", 3)
|
||||||
|
front = yaml.safe_load(text[3:end])
|
||||||
|
assert front["layer"] == "Engine"
|
||||||
|
assert front["role"] == "Lifecycle"
|
||||||
|
assert front["declaration"] == "layer.yaml"
|
||||||
|
assert front["pep_stance"] == "pep-stance.yaml"
|
||||||
|
|
||||||
|
|
||||||
|
def test_checker_passes_on_the_real_tree():
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, str(SCRIPT)],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, result.stdout + result.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_proposed_capabilities_carry_gap_record_fields():
|
||||||
|
for cap in _decl()["proposed_capabilities"]:
|
||||||
|
for field in ("capability", "intended_owner", "blocked_on", "review", "state"):
|
||||||
|
assert cap.get(field), f"{cap.get('id')} missing {field}"
|
||||||
|
assert cap["state"] == "unowned-capability"
|
||||||
|
assert cap["owner_status"] == "proposed"
|
||||||
|
|
||||||
|
|
||||||
|
def test_stance_map_is_total_over_catalog_stages():
|
||||||
|
stance = _stance()["stance"]
|
||||||
|
required = {"build", "test", "prod", "unknown"}
|
||||||
|
assert required <= set(stance), f"stance not total; missing {required - set(stance)}"
|
||||||
|
assert set(stance.values()) <= {"fail_open", "fail_closed"}
|
||||||
|
assert stance["prod"] == "fail_closed"
|
||||||
|
assert stance["unknown"] == "fail_closed"
|
||||||
|
assert _stance()["verdict_caching"] == "none"
|
||||||
|
|
||||||
|
|
||||||
|
def test_published_prod_stance_equals_shipped_fail_closed(monkeypatch):
|
||||||
|
"""pep-stance.yaml prod: fail_closed must equal _require_lane_approval."""
|
||||||
|
assert _stance()["stance"]["prod"] == "fail_closed"
|
||||||
|
entry = validate_entry(dict(VALID, stage="prod", approval={"model": "bootstrap-only"}))
|
||||||
|
cfg = SimpleNamespace(hub_url="http://127.0.0.1:8000", bao_addr="http://127.0.0.1:8200")
|
||||||
|
monkeypatch.delenv("SECRETS_ENGINE_UNSAFE_DEMO", raising=False)
|
||||||
|
with pytest.raises(DecisionError, match="live production remains disabled"):
|
||||||
|
_require_lane_approval(cfg, entry, "apply")
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_stage_is_not_the_production_fail_closed_gate(tmp_path, monkeypatch):
|
||||||
|
"""build is fail_open relative to access-engine: lane approval still applies."""
|
||||||
|
assert _stance()["stance"]["build"] == "fail_open"
|
||||||
|
(tmp_path / ".decisions").mkdir()
|
||||||
|
(tmp_path / ".decisions" / "x.yaml").write_text(
|
||||||
|
"id: x\ntitle: approved\nstatus: resolved\nsuperseded_by: null\n"
|
||||||
|
)
|
||||||
|
import secrets_engine.cli as cli
|
||||||
|
|
||||||
|
monkeypatch.setattr(cli, "repo_root", lambda: tmp_path)
|
||||||
|
entry = validate_entry(
|
||||||
|
dict(
|
||||||
|
VALID,
|
||||||
|
stage="build",
|
||||||
|
path="build/team/thing",
|
||||||
|
approval={"model": "decision", "decision_ref": "x"},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cfg = SimpleNamespace(hub_url="", bao_addr="http://127.0.0.1:8200")
|
||||||
|
assert _require_lane_approval(cfg, entry, "apply").id == "x"
|
||||||
222
workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md
Normal file
222
workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
---
|
||||||
|
id: SECRETS-WP-0008
|
||||||
|
type: workplan
|
||||||
|
title: "Evolve the Lifecycle engine to the accepted security layer model"
|
||||||
|
domain: infotech
|
||||||
|
repo: secrets-engine
|
||||||
|
status: ready
|
||||||
|
owner: grok
|
||||||
|
topic_slug: custodian
|
||||||
|
created: "2026-08-29"
|
||||||
|
updated: "2026-08-29"
|
||||||
|
---
|
||||||
|
|
||||||
|
# SECRETS-WP-0008 - Evolve the Lifecycle engine to the accepted security layer model
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Close the gaps between the 2026-08-29 layer declaration (Engine / Lifecycle)
|
||||||
|
and the obligations the accepted NetKingdom Security Layer Model v0.7 places on
|
||||||
|
a PEP-shaped Lifecycle engine.
|
||||||
|
|
||||||
|
Source review: `history/2026-08-29-layer-model-scope-intent-review.md`.
|
||||||
|
Declaration surface already landed this session: `INTENT.md` frontmatter,
|
||||||
|
`layer.yaml`, `pep-stance.yaml`, and `tests/test_layer_conformance.py`.
|
||||||
|
|
||||||
|
This workplan does **not** restart CLI hardening owned by `SECRETS-WP-0007`.
|
||||||
|
It adds the layer-model remainder: stance binding, decision-record consumption,
|
||||||
|
`audit-core` evidence, and the two proposed engine surfaces.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Taking ops-warden's SSH access lane or becoming a credential broker.
|
||||||
|
- Rendering or caching authorization decisions.
|
||||||
|
- Observation in production or automatic containment (companion §10: both are
|
||||||
|
at zero estate-wide).
|
||||||
|
- Service mode, runtime tenancy, or a second custody backend.
|
||||||
|
- Reopening live production on State Hub status or local fixtures.
|
||||||
|
|
||||||
|
## Coordination
|
||||||
|
|
||||||
|
- `SECRETS-WP-0007-T04` owns the consumer validator and the fail-closed
|
||||||
|
production gate until a durable ActionAuthorization object is served.
|
||||||
|
- `SECRETS-WP-0007-T05` owns delivery-session self-revocation and the KeyCape
|
||||||
|
scaffold; this workplan owns the layer-model "no standing credential" bar.
|
||||||
|
- railiance-platform owns production OpenBao and the JWT role.
|
||||||
|
- `access-engine` / State Hub own serving the decision record.
|
||||||
|
- `audit-core` owns evidence custody.
|
||||||
|
- ops-warden owns the SSH Staff PEP and must assent any SSH-CA API contract.
|
||||||
|
- kings-guard owns secret-abuse posture and must assent the evidence surface.
|
||||||
|
- gate-house owns statute §13.1 inventory of PEP stance maps.
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
## Publish stance application as shipped behaviour
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T01
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
`pep-stance.yaml` is published and tests pin `prod: fail_closed` to
|
||||||
|
`_require_lane_approval`. The gate is still hardcoded, and a refusal is
|
||||||
|
recorded as a `DecisionError` rather than named stance fields.
|
||||||
|
|
||||||
|
Load the published map as the source of shipped defaults. When the
|
||||||
|
unreachable-engine residue is applied, record at least stage, failure mode, and
|
||||||
|
decision id present only where a decision was rendered. Keep the three-factor
|
||||||
|
unsafe-demo exception out of the stance table. Assert map equality in
|
||||||
|
`tests/test_layer_conformance.py` the way ops-warden's stance test does.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- `_require_lane_approval` (or its successor) reads `pep-stance.yaml`.
|
||||||
|
- Changing the YAML without changing the code fails the test, and the reverse.
|
||||||
|
- Fail-closed production evidence includes named stance fields, never a secret.
|
||||||
|
- Build/test remain fail-open *relative to access-engine* and still require
|
||||||
|
the existing lane-approval check; that residue stays documented as a gap
|
||||||
|
until T02.
|
||||||
|
|
||||||
|
## Consume access-engine decision records
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T02
|
||||||
|
status: wait
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Blocked on the durable ActionAuthorization serving path owned with
|
||||||
|
`SECRETS-WP-0007-T04` / State Hub / `access-engine`.
|
||||||
|
|
||||||
|
Once that object is served, a protected side effect holds a decision record
|
||||||
|
identifying the request it was rendered for. Replay is permitted iff the
|
||||||
|
canonical request digest matches and the lifetime holds. Do not cache the
|
||||||
|
verdict. Do not treat State Hub status, a local fixture, or catalog admission
|
||||||
|
as the decision.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- Every live privileged production handler passes one shared consume function.
|
||||||
|
- Wrong digest, expired lifetime, superseded status, or missing record fail
|
||||||
|
closed before OpenBao.
|
||||||
|
- Evidence carries the decision id; a fail-closed residue still records the
|
||||||
|
stance instead.
|
||||||
|
- Local fixtures cannot authorize steady-state production.
|
||||||
|
|
||||||
|
## Emit evidence under the §9.6 bound
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T03
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Classify each privileged action as load-bearing or attributive. Today's trail
|
||||||
|
is attributive local JSONL plus best-effort State Hub notes; completeness is
|
||||||
|
already not claimed and must stay that way until the destination is
|
||||||
|
`audit-core`.
|
||||||
|
|
||||||
|
Load-bearing classes (at least live destroy, production revoke/suspend of a
|
||||||
|
control, and dual-control provision once those are enabled) require atomic
|
||||||
|
emission via a **local** outbox and a declared cadence or heartbeat. Do not
|
||||||
|
place a synchronous `audit-core` dependency inside the state-change
|
||||||
|
transaction. Attributive classes may keep the current non-blocking trade if
|
||||||
|
that trade stays declared.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- A machine-readable classification exists next to the declaration.
|
||||||
|
- No control in this repository branches on presence or absence of a local
|
||||||
|
evidence record.
|
||||||
|
- Load-bearing emission is queued locally; an `audit-core` outage does not
|
||||||
|
block a revocation.
|
||||||
|
- Documentation uses the sound claim: the archive proves records it holds were
|
||||||
|
not altered or truncated after arrival.
|
||||||
|
|
||||||
|
## Accept the SSH-CA signing engine surface
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T04
|
||||||
|
status: todo
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
ops-warden's `ssh-ca-signing-write` gap names this engine as intended owner.
|
||||||
|
Accept the **engine API**, decline the Staff lane. Publish a contract
|
||||||
|
ops-warden can call after an `access-engine` decision: sign a short-lived
|
||||||
|
certificate for an `adm`/`agt`/`atm` actor under the caller's request, present
|
||||||
|
no additional authority, reconstruct as the caller's action.
|
||||||
|
|
||||||
|
Do not implement a replacement client until ops-warden assents the contract.
|
||||||
|
Do not unpark the standalone `warden-sign` AppRole as break-glass.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- A non-secret contract document in `docs/` states request, decision binding,
|
||||||
|
lifetime, evidence, and non-responsibilities.
|
||||||
|
- ops-warden has a recorded chance to assent or contest.
|
||||||
|
- No OpenBao SSH-CA write is added to this CLI ahead of that assent.
|
||||||
|
- `layer.yaml` owner_status remains `proposed` until the surface ships.
|
||||||
|
|
||||||
|
## Accept the secret-use evidence surface
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T05
|
||||||
|
status: todo
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
kings-guard's secret-abuse posture is fixture-driven because no engine exposes
|
||||||
|
lease, revocation, mount, rotation, and delivery-session metadata. `route` and
|
||||||
|
`audit` are operator summaries over local JSONL and are not that surface.
|
||||||
|
|
||||||
|
Publish a read-only engine contract of non-secret metadata, bounded by §9.6:
|
||||||
|
it cannot prove omission at source. Coordinate destination with `audit-core`.
|
||||||
|
Do not give kings-guard a vault client, and do not return values.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- Contract lists fields, freshness, and the evidence bound.
|
||||||
|
- kings-guard has a recorded chance to assent or contest.
|
||||||
|
- No secret material, token, or accessor is in the surface.
|
||||||
|
- `layer.yaml` owner_status remains `proposed` until the surface ships.
|
||||||
|
|
||||||
|
## No standing engine credential
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: SECRETS-WP-0008-T06
|
||||||
|
status: wait
|
||||||
|
priority: medium
|
||||||
|
```
|
||||||
|
|
||||||
|
Blocked on the platform-owned OpenBao JWT mount/role (railiance-platform) and
|
||||||
|
on `SECRETS-WP-0007-T05` wiring. Companion §7 / statute §3.4: an agent holds
|
||||||
|
no long-lived credential of its own. Authority is per task, time-bounded, and
|
||||||
|
attributable to the principal it acts for.
|
||||||
|
|
||||||
|
Bootstrap token files remain break-glass, heavily evidenced, never an implicit
|
||||||
|
fallback from service identity.
|
||||||
|
|
||||||
|
Acceptance:
|
||||||
|
|
||||||
|
- Steady-state CLI/API auth is the reviewed service identity, not
|
||||||
|
`--bootstrap-token-file`.
|
||||||
|
- Bootstrap is a named break-glass provider with distinct evidence.
|
||||||
|
- No fallback from JWT/service-auth failure into bootstrap or AppRole.
|
||||||
|
- Issued delivery sessions continue to self-revoke as in WP-0007-T05.
|
||||||
|
|
||||||
|
## Exit criteria
|
||||||
|
|
||||||
|
- The published PEP stance is the shipped default and stance application is
|
||||||
|
recorded by name.
|
||||||
|
- Production live side effects require an access-engine decision record, or
|
||||||
|
remain fail-closed with a recorded stance.
|
||||||
|
- Evidence classification and destination match §9.6; completeness is not
|
||||||
|
claimed.
|
||||||
|
- SSH-CA and secret-use surfaces are either contracted with the declaring
|
||||||
|
repositories or explicitly declined in this repository's own voice.
|
||||||
|
- Bootstrap is not the steady-state engine credential.
|
||||||
|
- `layer.yaml` / `pep-stance.yaml` / INTENT frontmatter stay in one voice.
|
||||||
|
- No raw secret values in Git, State Hub, chat, prompts, workplans, evidence,
|
||||||
|
or argv.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue