Implement GH-DEC-2026-003 consume-before-OpenBao PEP gate
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Every live privileged production handler CAS-consumes through
approval-engine before OpenBao. Conflict, unavailability, or a missing
binding fail closed. Live production remains disabled until the durable
decision record is served.

Record kings-guard assent on the secret-use evidence contract.

Assistant: grok
Assistant-Session: 01a05f07-ae72-7781-9fcb-19efd61add00
This commit is contained in:
tegwick 2026-09-02 01:06:50 +02:00
parent 465c0d7049
commit 4b4d556d62
14 changed files with 724 additions and 20 deletions

View file

@ -0,0 +1,49 @@
# Approval consumption (PEP)
Status: engine consumer implemented; live production remains fail-closed
until a durable consume binding is served.
Normative protocol: `gate-house/docs/contracts/approval-consumption.md`
(`GH-DEC-2026-003`). Implementation surface:
`approval-engine/docs/approval-consumption.md`. This document records how
secrets-engine, as the PEP for OpenBao writes, consumes that protocol. It
does not redefine it.
## Sequence
```text
1. PIP GET /v1/approvals/{id}/claim
2. PDP access-engine Check / decide → ALLOW
3. PEP POST /v1/approvals/{id}/consume → CAS
4. PEP OpenBao call → only after consume succeeds
```
Every live privileged production handler passes `_require_lane_approval`,
which calls `require_production_consume` before `OpenBaoClient.resolve`.
Dry-run and `plan` do not consume. Build/test remain fail-open relative to
approval-engine. The three-factor unsafe-demo exception is not a consume
path.
## Fail closed
| Condition | Result |
| --- | --- |
| No served consume binding | refuse; no OpenBao |
| Missing `SECRETS_ENGINE_APPROVAL_URL` or token file | refuse; no OpenBao |
| HTTP 409 / different digest | refuse; no OpenBao |
| Same digest after consume | idempotent success; OpenBao may proceed |
| 401/403/404/503/unreachable | refuse; no OpenBao |
| Side effect fails after consume | approval is spent; no unconsume |
The consume response is mutation evidence (`status=consumed` plus the
presented digest). It is not a permission. Evidence records approval id,
digest, idempotence, and consumed-at only. No token, secret, or accessor.
## What this does not do
- It does not enable live production. Unreachable-engine stance still
fail-closes production until an access-engine decision record is served
(`SECRETS-WP-0007-T04` / `SECRETS-WP-0008-T02`).
- It does not render or cache an authorization decision.
- It does not infer consumption from a decision record or from local
evidence.

View file

@ -50,6 +50,9 @@ contents in this repo.
- Implemented consumer validator: exact action request, decision digest/binding,
validity, State Hub provenance, and caller-selected minimum distinct approval
count.
- Implemented PEP consume-before-OpenBao (`GH-DEC-2026-003`): production
handlers share `require_production_consume` and fail closed on conflict,
unavailability, or a missing consume binding.
- Remaining: State Hub stores/serves the durable object and production handlers
resolve it; all production live actions currently fail closed.

View file

@ -76,3 +76,12 @@ holds: nothing is observed in production until kings-guard reports otherwise.
A coordination message to kings-guard records this contract. Assent or contest
belongs in kings-guard's own voice.
**2026-09-01:** kings-guard assented, in its own voice (State Hub message
`75ebd2cc-a166-4676-94aa-deef2791c0c9`), to this document as a proposed
Engine / Lifecycle read-only non-secret surface. Assent covers: no secret
values; destination audit-core; completeness not claimed; heartbeat rather
than rate monitoring for load-bearing classes; kings-guard reads this engine
surface, never OpenBao. kings-guard will not consume it as an observation
input until the surface ships and publishes its cadence declaration.
`layer.yaml` `owner_status` remains `proposed` until that surface exists.