test: enforce that dry runs never reach the authorization gate
flex-auth's published policy package encodes an explicit limit: apply and apply --dry-run are indistinguishable to a PDP, since both arrive as action `apply`. What separates them is a property of this repo - the PEP does not call the gate for a dry run - and flex-auth recorded that as a limit rather than implying a control they do not have, asking to be told if it stops holding. Verified it holds across all five dry-run handlers (apply, revoke, lifecycle suspend/deactivate/destroy) and locked it with a regression test that fails with the instruction to notify flex-auth. A paired test proves the hook under test is actually load-bearing, so the guard cannot pass vacuously. Also records the FLEX-WP-0021-T01/T02 and GH-DEC-2026-005 outcomes in SECRETS-WP-0007-T04, including the revisit trigger flex-auth flagged: with one calling identity the denial ladder has no action_not_granted branch, so a second identity or a per-lane/stage split is the trigger to add it. allow_ttl 15m needed no change - normalize_wrap_ttl already caps wrap at 15m. The policy pin stays unset; publishing is not deploying. 257 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M65ovP3eiiPHubibvWs9mD Assistant: claude-code Assistant-Model: opus Assistant-Process: 393550@bnt-lap001 Assistant-Session: 4bb359f9-1f12-4410-9e76-079cf23c82e4
This commit is contained in:
parent
7b4b9e386e
commit
083bee7333
2 changed files with 124 additions and 0 deletions
|
|
@ -352,6 +352,63 @@ and the published package from `FLEX-WP-0021-T02`. The pin stays unset.
|
|||
`FLEX-WP-0021-T01`. Separately tracked: production requires a KeyCape RS256 JWT,
|
||||
not the static Bearer token this engine currently sends.
|
||||
|
||||
Closed out 2026-09-06. gate-house amended `GH-DEC-2026-005`; flex-auth published
|
||||
the policy package (`FLEX-WP-0021-T01`/`T02` done, commit `f75db59`).
|
||||
|
||||
- `secrets-engine.catalog-lane.lifecycle` v1 exists with both manifests, a
|
||||
loadable registry snapshot, 26 fixtures and five standalone check requests;
|
||||
`validate -kind policy` reports 22/22 Rego tests and 26/26 fixtures. Our
|
||||
vocabulary is recorded in flex-auth `docs/secrets-engine-action-vocabulary.md`.
|
||||
All four constraints from `docs/gated-actions.md` are encoded rather than
|
||||
assumed: `test_revoke_is_not_an_action` asserts `revoke` denies
|
||||
`unknown_action`, `destroy` is fixtured as the dual-control case before
|
||||
`T04` opens the path, `compromise`/`reactivate` are annotated overlay-only,
|
||||
and the ungated verbs deny `unknown_action`. flex-auth reports four of the
|
||||
twelve would have been inferred wrongly, `revoke` most confidently.
|
||||
- **A published limit now rests on a property of this repo.** `apply` and
|
||||
`apply --dry-run` are indistinguishable to a PDP; both arrive as action
|
||||
`apply`. What separates them is that our PEP does not call the gate for a dry
|
||||
run. flex-auth recorded that as a limit rather than implying a control they do
|
||||
not have, and asked to be told if the assumption stops holding.
|
||||
`tests/test_dry_run_never_gates.py` now enforces it across all five dry-run
|
||||
handlers, with a paired test proving the hook is load-bearing. Changing a
|
||||
dry-run path to gate is now a test failure carrying the instruction to notify
|
||||
flex-auth first.
|
||||
- Dual control on `destroy` checks what the claim *says* (two distinct approver
|
||||
subject ids). flex-auth deliberately does not re-derive temporal validity,
|
||||
signature, or supersession — those are approval-engine's to assert and **ours
|
||||
to verify against the live claim**. `validate_approval_claim` is that check.
|
||||
- `allow_ttl` is 15m in the package, stated rather than left to an engine
|
||||
default. Per `FLEX-DEC-2026-004` that is authority to *issue* the operation,
|
||||
not to keep using what it produced; bounding a delivered secret's own lifetime
|
||||
is ours. Already satisfied: `normalize_wrap_ttl` caps wrap at 15m and lane
|
||||
AppRoles carry 5m/15m token TTLs with a single-use Secret ID.
|
||||
- Structural note carried as a revisit trigger, not a defect: because we named
|
||||
exactly one calling identity, the denial ladder has no `action_not_granted`
|
||||
branch — with one subject holding all twelve actions it could never fire, and
|
||||
a rule that cannot fail reads as per-action control that is not there.
|
||||
Registering a second identity, or splitting the CLI identity by lane or stage,
|
||||
is the trigger; adding the branch then is additive and needs no request-shape
|
||||
change.
|
||||
- gate-house struck the G3 revisit trigger for a composed authorization object,
|
||||
verified against the DecisionEnvelope schema: `lifetime` is required whenever
|
||||
effect is allow, so carrying its own end — the one structural thing the bundle
|
||||
did that the split does not — is already answered. Three triggers remain: a
|
||||
third or fourth PEP-shaped consumer, a single signed forwardable artifact, and
|
||||
§17 request-claim assent.
|
||||
- On the approver threshold we stopped checking, gate-house recorded both that
|
||||
it is correct on layering **and** a genuine reduction in defence in depth,
|
||||
noting a decision recording only the first would be self-serving. The
|
||||
compensating property is reconstructability at the issuer under §9.6 —
|
||||
detection, not prevention — not a second check here.
|
||||
|
||||
**The pin stays unset.** Publishing is not deploying: there is still no
|
||||
`flex-auth-secrets-engine` pin and therefore no address to call. `T04` stands it
|
||||
up in `callerAuth.mode warn`; `T05` hands over the Service DNS and confirms the
|
||||
package/version to configure. Next inbound is the `T03` replay fixture — a real
|
||||
DecisionEnvelope from this package including `provenance.registry_snapshot_digest`
|
||||
— to verify the digest join unchanged.
|
||||
|
||||
Define and enforce the decision contract needed by production commands. A
|
||||
resolved approval must bind at least:
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue