fix: bind approval consumption to actual Flex Auth submissions
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-09 08:55:46 +02:00
parent 89bc31460f
commit ee4e901611
23 changed files with 612 additions and 1023 deletions

View file

@ -1,52 +1,22 @@
# flex-auth T03 replay fixtures
# Flex Auth replay contract fixtures
Copied verbatim from `flex-auth/examples/secrets-engine/replay/` (commit
`9e10d1c`, `FLEX-WP-0021-T03`). Real `DecisionEnvelope`s emitted by the
published `secrets-engine.catalog-lane.lifecycle` v1 package via
`go run ./cmd/flex-auth check`, from `flex-auth/local` in `standalone` mode.
Copied byte-for-byte on 2026-09-09 from flex-auth revision
`88b354377c8e26b162f1234e673072f1c06dcd89`, examples/secrets-engine/ and its
replay/ directory. Contract: FLEX-DEC-2026-012. These are standalone evaluator
outputs, not deployment evidence.
Vendored so the digest contract test is hermetic. Regenerate upstream and
re-copy if the contract version changes.
Each output is paired with its independently supplied check_request input.
Tests compute submitted_request_digest from that input; they do not reconstruct
it from the enriched response. Existing request_digest, approval_binding_digest,
policy-package and registry-snapshot pins are unchanged. Policy remains v2.
Approval correspondence compares claim.binding.pdp_digest with the evaluator's
approval_binding_digest. Neither is computed from the unenriched request.
Re-copied 2026-09-06 (twice, both upstream regenerations):
Tests inject the actual decision time instead of modifying captured lifetimes.
The older flex-auth-live fixture remains untouched and must fail the new
contract because it has no submitted_request_digest.
1. commit `9f3e7e3` completed the approval-claim on `context.approval`. Because
`context` is hashed material, completing the claim moved the request digest.
2. commit `dd3ce4c` (`FLEX-DEC-2026-007`) published
`binding.approval_binding_digest` and set the embedded claim's
`binding.pdp_digest` to it with `binding.pdp_path` true. The request digest
moved once more with the claim's contents; the approval-binding digest did
**not**, which is the property the fixture now demonstrates rather than
asserts.
3. commit `d98323b` published **v2**, which adds the `input.tenant` rule v1
never had, and a third fixture: `decision_wrong_tenant_deny.json`. The
request digests did **not** move — every allow fixture already carried
`tenant: tenant:platform` — but `provenance.policy_version` is now `v2` and
`policy_package_digest` moved to `sha256:bd11c5fe…`.
`decision_rotate.json` carries no `approval_binding_digest` — the field is
omitted on claim-free decisions rather than duplicated onto them, and a test
pins that omission.
`decision_wrong_tenant_deny.json` is an `effect: deny` envelope and carries no
`lifetime`, which is legal: the schema requires `lifetime` only for an allow.
It is the wrong-tenant denial evidence `GLAS-WP-0015` asked for. Do not
lifetime-refresh it in tests.
**v1 must not be pinned.** It had no tenant rule and failed open; flex-auth
superseded rather than amended it so the change is visible in the version
string. See `docs/tenant-alignment.md`.
**Pinned here** (stable across runs, per the upstream README):
`binding.request_digest`, `binding.approval_binding_digest`,
`provenance.policy_package_digest`, `provenance.registry_snapshot_digest`, and
the presence/absence of `provenance.input_claim_digests.context`.
`approval_binding_digest` is not only pinned but **rederived** by
`test_pdp_digest_equals_the_published_approval_binding_digest`: our canonical
implementation must reproduce it from the fixture's own request. A pin asserts
the constant; rederiving it proves we hash the same material flex-auth does.
**Never pin:** `id`, `provenance.decision_time`, `lifetime.not_before`,
`lifetime.expires_at` — all move with the clock.
`tools/exercise_approval_identity.py` additionally compiles the owner evaluator
and runs real KeyCape/Approval Engine/Flex Auth joins with synthetic credentials,
including registry override and destructive-action dual control. Its receipt
pins source, binary and producer inputs; it makes no live admission claim.