secrets-engine/history/2026-08-29-layer-model-scope-intent-review.md
tegwick 1945e16685
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
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
2026-08-29 11:57:47 +02:00

163 lines
10 KiB
Markdown

# 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`.