diff --git a/SCOPE.md b/SCOPE.md index 91b057f..102211c 100644 --- a/SCOPE.md +++ b/SCOPE.md @@ -40,17 +40,35 @@ point, not an identity provider, and not a general secrets API. - Resolves legacy lane decisions from State Hub by id, with tracked local YAML mirrors retained only for non-production and explicit throwaway demos. This is not an access-engine decision record. -- Fails every production live command closed while there is no durable - access-engine / ActionAuthorization record. That fail-closed row is the - published unreachable-engine stance for `prod` in `pep-stance.yaml`. A local +- Fails every production live command closed while the two-artifact chain + cannot be completed — today because approval-engine does not serve the + approval-claim endpoint. That fail-closed row is the 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 - exact lane/stage/action/target/actor/purpose matching, bounded validity, - State Hub authority, request digest and decision binding, accepted policy - package/version, and an independently required distinct-approver threshold. - Validation is consume-only; this process does not evaluate policy. +- Validates the two-artifact authorization chain, split by owning layer per + `GH-DEC-2026-005`. The approval-engine **approval-claim** supplies the approval + fact: issuer, `valid_now`, consumption state, freshness, `reason_code`, a + required `binding.pdp_path` declaration, and the `pdp_digest` tie to this exact + action. The flex-auth **DecisionEnvelope** supplies the decision: effect, + structured binding correspondence to the proposed action, canonical request + digest, lifetime, and the accepted policy package/version pin. Neither layer + republishes the other's data, and validation is consume-only; this process does + not evaluate policy. +- Compares the decision binding by structured correspondence rather than + byte-equality, per flex-auth's published normalization rule: everything the + engine proposed must survive unchanged, registry enrichment may add only + `type`/`tenant`/`attributes`, and an enriched tenant must be the request + tenant. The request digest is verified against the tuple the binding carries. + The CheckRequest carries the package's `known_tenant`; an absent tenant is a + `wrong_tenant` denial, not an ignored field. +- The `ActionAuthorization` object is **deferred and never ratified** + (`FLEX-DEC-2026-006`); nothing validates it. There is no State Hub authority + constant — State Hub is a read model and holds no runtime approval authority. + The distinct-approver threshold is folded into `valid_now` by the issuer and is + no longer an independent consumer-side check, which is correct on layering and + a real reduction in what this engine verifies alone. - Renders guarded OpenBao plans for exact consumer ACL policies and AppRoles. - Applies policy and AppRole metadata idempotently. Existing mounts render a non-mutating check and are never created by apply. @@ -227,10 +245,18 @@ metadata. `secrets-engine wrap` implements response-wrapped operator handoff. service-auth / `service-jwt` provider. - Provider-side / workload consumer rotation. Overlay lane state is local and non-secret only; it is not an OpenBao-side state machine. -- Resolution of a durable access-engine decision record / State Hub - ActionAuthorization and wiring its validated approval threshold to each - production handler. The consumer validator exists; the serving endpoint does - not, so live production remains fail-closed. +- Protocol step 1 in production: approval-engine does not yet serve the + approval-claim endpoint (`APPROVAL-WP-0002-T03`), so `resolve_consume_binding` + returns no binding and live production remains fail-closed. Step 2 is served + and proven — a real CheckRequest against the deployed `flex-auth-secrets-engine` + pin returns a validated v2 decision over the owner-documented access path + (`docs/pdp-access-path.md`). +- Responder authentication for the decision channel. `flex-auth.decision-record.v1` + carries no signature and pins serve plain HTTP, so a responder knowing the + published package and version could return a well-formed allow. Fail-closed + protects against a PDP that is absent, not one that lies (`FLEX-DEC-2026-010`). + The enforced loopback address shape stands in for this until `FLEX-WP-0024` + ships detached signatures. - Direct access-engine evaluation, JWT signature verification, or identity authentication. KeyCape claims receive only a consumer preflight; OpenBao is responsible for cryptographic JWT validation. @@ -306,7 +332,7 @@ Working companion: `net-kingdom/SECURITY-COMPANION.md`. | 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 from `pep-stance.yaml` | Consume an access-engine decision record before every protected side effect | +| One decision point | Two-artifact consumer validation (approval-claim + DecisionEnvelope); step 2 proven against the deployed pin, step 1 unserved so production live stays fail-closed from `pep-stance.yaml` | Consume an access-engine decision record before every protected side effect | | PEP stance | Runtime loads `pep-stance.yaml`; named stance fields on privileged evidence | Unchanged map; T02 replaces fail-open residue with a decision record | | Evidence bound | `evidence-classification.yaml`; load-bearing local outbox; heartbeat command | Drain to `audit-core` once that sender is admitted | | SSH-CA surface | Contract at `docs/ssh-ca-signing-contract.md`; not shipped | Engine API after ops-warden assent |