diff --git a/docs/gated-actions.md b/docs/gated-actions.md deleted file mode 100644 index 07471f0..0000000 --- a/docs/gated-actions.md +++ /dev/null @@ -1,48 +0,0 @@ -# Gated actions over `secret-catalog-lane` - -Authoritative list of the `action` values secrets-engine passes to the shared -authorization gate (`_require_lane_approval` → `resolve_consume_binding` → -`require_production_consume`). Supplied to flex-auth for -`secrets-engine.catalog-lane.lifecycle` (FLEX-WP-0021-T01 / FLEX-DEC-2026-005). - -This is the enforced set read out of `cli.py`, not the -`secrets-engine.lifecycle`/`v1` example vocabulary. `resource.type` is -`secret-catalog-lane` and `resource.system` is `secrets-engine`; the catalog id -is `request.resource.id`. - -| action | Reached by | Side effect | -| --- | --- | --- | -| `apply` | `apply` | writes consumer ACL policy + AppRole metadata | -| `provision` | `provision` | writes one declared KV field | -| `rotate` | `rotate` | replaces one declared KV field | -| `verify` | `verify` | AppRole login + bounded read/capability probe | -| `handoff` | `handoff` | mints role-id/secret-id to mode-0600 files | -| `wrap` | `wrap` | response-wrapped operator handoff | -| `exec` | `exec` | fetches one field into a child process | -| `deactivate` | `revoke` **and** `lifecycle deactivate` | removes managed AppRole/policy; preserves KV | -| `suspend` | `lifecycle suspend` | removes managed AppRole; preserves policy | -| `destroy` | `lifecycle destroy` | irreversible KV metadata deletion | -| `compromise` | `lifecycle compromise` | marks lane compromised; blocks delivery | -| `reactivate` | `lifecycle reactivate` | clears overlay state | - -## Things a package author would otherwise get wrong - -- **`revoke` is not an action.** The CLI verb `revoke` gates as `deactivate`. - There is no `revoke` action value. Do not add one. -- **`destroy` is defined but currently unreachable live.** The handler raises - before the gate; only `--dry-run` renders. Keep it in the package as the - dual-control-capable case, but no live `destroy` Check will arrive until the - exact-action approval contract lands (`SECRETS-WP-0007-T04`). -- **`compromise` and `reactivate` mutate local overlay state only.** They touch - no OpenBao object. They are gated because they change delivery posture, not - because they write to the backend. -- **`plan`, `apply --dry-run`, `route`, `audit`, `catalog`, `decision inspect` - and `evidence` never reach the gate** and must not appear in the package. -- Build and test stages remain fail-open relative to approval-engine; only - `stage: prod` reaches consume. - -## Request attributes carried today - -`resource.attributes` carries `stage`, and sorted `fields`, `policy_targets`, -and `auth_targets`. `fields` is populated for `provision`, `rotate`, `verify`, -and `exec`; the others send an empty list rather than a guess. diff --git a/workplans/SECRETS-WP-0007-production-lifecycle-hardening.md b/workplans/SECRETS-WP-0007-production-lifecycle-hardening.md index b1ded12..a5ffe96 100644 --- a/workplans/SECRETS-WP-0007-production-lifecycle-hardening.md +++ b/workplans/SECRETS-WP-0007-production-lifecycle-hardening.md @@ -273,44 +273,6 @@ deployment: approval-engine must serve the claim endpoint and access-engine must serve Check. Probed 2026-09-06 — neither is reachable, and State Hub exposes only `/decisions/`. -Inbound 2026-09-06 (approval-engine `APPROVAL-IN-0002`, flex-auth -`FLEX-DEC-2026-005`). The join committed in `627810b` validates the wrong -artifact and must not be extended until gate-house rules. - -- `ActionAuthorization` is a PROPOSED, unratified object from flex-auth's own - contract. It appears zero times in gate-house and state-hub. `GH-DEC-2026-003` - already names step 1 as `GET /v1/approvals/{id}/claim -> valid_now`, an - approval-claim field that `ActionAuthorization` does not carry. The claim body - is an approval-claim envelope, not an `ActionAuthorization`. -- Confirmed defect, ours, independent of the ruling: `authorization.py` pins - `AUTHORITY = "state-hub"` and enforces it unconditionally, contradicting - flex-auth's statement that State Hub decision records are not the runtime - approval authority and our own read-model doctrine. Not patched yet: under - option A the authority check belongs on the claim issuer, so it moves with the - split rather than being guessed twice. -- If gate-house confirms option A, `validate_action_authorization` splits across - the two artifacts already fetched: the claim carries approval fact (binding - digest, validity window, consumption state, freshness, issuer); the step-2 - DecisionEnvelope carries exact CheckRequest match and the package/version pin. - No check is lost. Do not start until the ruling. -- Auth gap, tracked separately so it does not ride the envelope decision: we - send a static mode-0600 token as Bearer. Production verifies a KeyCape RS256 - JWT against JWKS and refuses opaque tokens. Requested registration clientId - `secrets-engine-approval`, scopes `approval:read` + `approval:consume`, - client_credentials, confidential. `aud` MUST be the resource server - `approval-engine`, never the clientId. `service_auth.py` already implements - this exchange for `secrets-engine-openbao`, so this is a second registration. -- approval-engine `APPROVAL-WP-0002-T03` will publish the base URL; it is not - deployed anywhere today and proceeds on its own evidence. The envelope - question gates our first live consume, not their rollout. -- flex-auth endorsed the no-default-pin decision explicitly. The reserved - coordinate `secrets-engine.catalog-lane.lifecycle` / `v1` is a RESERVATION, - not a publication; our pin stays unset. `docs/gated-actions.md` delivers the - authoritative twelve-action list `FLEX-WP-0021-T01` was blocked on. No - estate-wide PDP exists by design: flex-auth runs per-consumer cluster-local - pins, and `flex-auth-secrets-engine` has not been created yet, so the - 2026-09-06 probe finding was the design working rather than an outage. - Define and enforce the decision contract needed by production commands. A resolved approval must bind at least: