Verify normalized task approval facts and preserve signed source types
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-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
This commit is contained in:
tegwick 2026-10-16 17:28:03 +02:00
parent 5a2099f400
commit 4dd004a225
18 changed files with 756 additions and 60 deletions

View file

@ -38,7 +38,9 @@ ServiceAccount principal, `flex-auth` audience and live expiry bounding the
operation deadline. This consumes the signed PDP's caller attestation; it does
not independently perform TokenReview or promote the proposed server mapping.
Human/delegation/projected-identity flags cannot substitute for this service seam.
No service_actor_binding request propagation or source-policy activation is added.
The later typed execution builder now propagates the fixed Access public
service_actor_binding before approval issue; it is not caller authentication.
No source-policy activation is added.
`as_owner_handoff()` returns a detached non-secret mapping with:
@ -76,3 +78,36 @@ confirm original durable consumption using Approval's real provider client,
journal it, then recheck its exact Plan, owner sources, grant and deadlines before
any native operation. Neither a dataclass nor a caller-supplied boolean admits
execution. Existing generic CLI CAS behavior is otherwise unchanged.
2026-10-16 retained-registry preapproval source preparation adds
`prepare_task_approval(cfg, entry, execution_contract=contract)`. It calls the
existing signed Check client with the original claim-free typed proposal and
accepts only a signed DENY normalization record. This neither authorizes nor
consumes an operation. No registry algorithm is copied and no registry is emptied.
The detached `as_owner_handoff()` returns `original_request`,
`submitted_request_digest`, authoritative `native_binding`,
`approval_binding_digest`, normalization `decision_id`, `execution_contract`, and
signed `registry_snapshot_digest`. Exact original context (including JSON kinds),
submitted digest, recomputed evaluated digest, explicit approval-free digest,
policy/key admission, service/caller identity, decision time and deadline are
checked. Registry digest is evidence from the admitted signer; this method does
not independently grant registry/config admission. The caller uses the returned
native act and approval-free digest for normal Approval issuance and human entry.
It preserves the original proposal; final authorize_task_execution builds that
same proposal and attaches only the original issued claim. Access normalizes
again and independently joins current source facts. Changed evaluated facts or
native target refuse before CAS. A normalization DENY object/mapping is never
accepted by consume_task_execution.
Normalization decision_time must be valid and nonfuture; there is deliberately
no invented standalone normalization TTL. The DENY receipt is not permission and
cannot discharge final signed ALLOW or source validation. Expired original task/
caller bounds refuse at preparation; a stale normalization's changed evaluated
facts refuse when Access independently checks the original issued claim against
the current retained registry. Unchanged historical normalization can only supply
public issue metadata; it cannot itself produce a CAS/native admission. The actual
source-server drift proof restarts Access with changed authoritative subject
roles after preapproval and observes final refusal with no new ALLOW record, no
CAS and unconsumed Approval state.

View file

@ -65,7 +65,7 @@ before observing the claim or calling Check. Its fields are:
| source_bundle | Absolute owner-resolved files and immutable SHA256 hashes for engine dispatcher, Platform mediator, typed CCR module and policy/auth source |
| backend_origin / cluster_uid | Exact reviewed estate OpenBao origin and railiance01 identity |
| operations | Ordered exact HTTP method, normalized path and canonical JSON/text payload hash for each read/write/readback; no user supplied body |
| operation_deadline | Upper bound no later than approval, PDP or task-token expiry |
| operation_deadline | Upper bound no later than approval, PDP, caller and original/fresh source validity; task-token expiry may be earlier |
| backend_budget | TTL at most 120s, at most twelve uses, no renew/child/wrap/unlimited uses |
| expected_before / expected_after | Owner-authenticated revision/state digests, never secret contents |
@ -158,10 +158,20 @@ validation while Platform owns its OpenBao credential and typed native primitive
Task-token use budget is declared before issuance: two before-state reads, two
writes, two readbacks and one self-revoke (seven uses), plus at most four explicit
metadata capability checks and one reserved cleanup use (twelve total). Failed
backend calls count; never retry to evade limits. Task TTL is
`min(120s, approval_remaining, decision_remaining, operation_remaining)` minus
the declared clock uncertainty/cleanup reserve. Reject if fewer than 30s remain
for planned requests. No renewal or remint extends the operation. CCR38 keeps its
backend calls count; never retry to evade limits. The immutable
`backend_budget.ttl_seconds` declares the requested task-token TTL (30–120s).
The native adapter does not dynamically recompute or shorten that declaration.
Before issuance, conservatively require at least the declared TTL plus the 5s
cleanup reserve within the remaining operation/approval/PDP authority, including
clock uncertainty. The requested and explicit maximum native token TTL equal
the declared budget; returned native TTL must be positive and at most that budget.
The token can expire before the operation deadline; failure or expiry stops work
without remint. The signed operation deadline remains no later than approval,
PDP, authenticated caller and both original/fresh source validity. Access's
trusted source path independently requires the same TTL-plus-5s fit after source
I/O and an operation interval no longer than 120s. Therefore a structural 120s
backend budget cannot fit inside a 120s authority interval with the reserve and
refuses. No renewal or remint extends the operation. CCR38 keeps its
own 300s/eight-use limit; login-self checks and revoke fit its separate budget.
## Failure, replay and recovery