feat: implement the PIP claim + validate authorization join
resolve_consume_binding was a `return None` stub, so protocol step 1 of
docs/approval-consumption.md (GET /v1/approvals/{id}/claim) and the
validation join never existed. validate_action_authorization had no caller
in src/ at all - it was reachable only from tests. Production fail-closed
was correct, but for an undocumented second reason, and WP-0007-T04's
"what remains is not local engine work" was wrong.
The join now reproduces the exact CheckRequest via build_action_request,
fetches the durable ActionAuthorization, and validates request binding,
digest, validity, authority, policy pin, and distinct-approver threshold
before offering a consume binding. _require_lane_approval threads the exact
field set for provision/rotate/verify/exec so the digest covers the real
proposed action.
Deliberate choices:
- The approval-engine object id is never inferred from a State Hub decision
UUID; flex-auth stated GET /decisions/{uuid} is not the durable object.
- No default policy pin. flex-auth stated secrets-engine.lifecycle/v1 is
example vocabulary, not a published package.
- A half-configured join raises rather than returning None, so a partial
deployment cannot be mistaken for an unconfigured one.
Behavior is unchanged today: every new input is absent by default, so
production still fails closed and plan/--dry-run still work. 234 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
ebcc36ecab
commit
627810b478
10 changed files with 456 additions and 25 deletions
|
|
@ -109,6 +109,8 @@ def _require_lane_approval(
|
|||
entry,
|
||||
action: str = "",
|
||||
evidence: PrivilegedActionEvidence | None = None,
|
||||
*,
|
||||
fields: tuple[str, ...] = (),
|
||||
):
|
||||
"""Apply published PEP stance, resolve lane approval, then CAS-consume.
|
||||
|
||||
|
|
@ -136,7 +138,9 @@ def _require_lane_approval(
|
|||
require_production_consume(
|
||||
cfg,
|
||||
entry,
|
||||
binding=resolve_consume_binding(cfg, entry, action or "unknown", decision),
|
||||
binding=resolve_consume_binding(
|
||||
cfg, entry, action or "unknown", decision, fields=fields
|
||||
),
|
||||
evidence=evidence,
|
||||
)
|
||||
return decision
|
||||
|
|
@ -311,7 +315,9 @@ def cmd_provision(cfg: Config, args) -> int:
|
|||
raise ProvisioningError(
|
||||
f"lane '{entry.id}' is stage '{entry.stage}', not '{args.stage}'"
|
||||
)
|
||||
decision = _require_lane_approval(cfg, entry, "provision", evidence)
|
||||
decision = _require_lane_approval(
|
||||
cfg, entry, "provision", evidence, fields=(field,) if field else ()
|
||||
)
|
||||
evidence.mark_approved(decision)
|
||||
require_provision_state(cfg.evidence_dir, entry.id)
|
||||
with _open_backend(cfg, args, evidence) as client:
|
||||
|
|
@ -346,7 +352,9 @@ def cmd_rotate(cfg: Config, args) -> int:
|
|||
raise ProvisioningError(
|
||||
f"lane '{entry.id}' is stage '{entry.stage}', not '{args.stage}'"
|
||||
)
|
||||
decision = _require_lane_approval(cfg, entry, "rotate", evidence)
|
||||
decision = _require_lane_approval(
|
||||
cfg, entry, "rotate", evidence, fields=(field,) if field else ()
|
||||
)
|
||||
evidence.mark_approved(decision)
|
||||
with _open_backend(cfg, args, evidence) as client:
|
||||
f = rotate_from_file(client, entry, field, Path(args.from_file))
|
||||
|
|
@ -386,7 +394,9 @@ def cmd_verify(cfg: Config, args) -> int:
|
|||
"negative_requested": negative,
|
||||
},
|
||||
) as evidence:
|
||||
decision = _require_lane_approval(cfg, entry, "verify", evidence)
|
||||
decision = _require_lane_approval(
|
||||
cfg, entry, "verify", evidence, fields=tuple(fields)
|
||||
)
|
||||
evidence.mark_approved(decision)
|
||||
with _open_backend(cfg, args, evidence) as client:
|
||||
if entry.stores_kv_value() and not fields:
|
||||
|
|
@ -540,7 +550,9 @@ def cmd_exec(cfg: Config, args) -> int:
|
|||
},
|
||||
) as evidence:
|
||||
# require approval + readiness before running.
|
||||
decision = _require_lane_approval(cfg, entry, "exec", evidence)
|
||||
decision = _require_lane_approval(
|
||||
cfg, entry, "exec", evidence, fields=(field,) if field else ()
|
||||
)
|
||||
evidence.mark_approved(decision)
|
||||
require_delivery_state(cfg.evidence_dir, entry.id, "exec")
|
||||
if not args.command:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue