2026-10-11 15:03:24 +02:00
|
|
|
# Approval Engine metadata execution consumer contract — source proposal
|
|
|
|
|
|
|
|
|
|
Author: approval-engine source reviewer (Codex), staged only. Work record:
|
|
|
|
|
APPROVAL-WP-ADHOC-2026-10-11-T01, bounded completed source preparation. Existing
|
|
|
|
|
APPROVAL-WP-0002-T05 remains unchanged wait/residual adoption. This is an
|
|
|
|
|
author-qualified technical proposal, not a formal delegated owner review,
|
|
|
|
|
owner acknowledgement, founder approval, identity admission or runtime receipt.
|
|
|
|
|
Source checkout: c8ae88057d5f2ff3743a37c158d7f692d90cce23, including pre-existing
|
|
|
|
|
uncommitted owner files listed in source-state.json; none modified.
|
|
|
|
|
|
|
|
|
|
Reviewed proposals: SECRETS-EXEC-20261011-v1 and platform-task-execution/v1.
|
|
|
|
|
Their exact source-file hashes are in source-state.json. Initial execute-ccr
|
|
|
|
|
metadata pilot only; no generic grants, daemon, standing service permissions,
|
|
|
|
|
raw bearer handoff or full Secrets adoption.
|
|
|
|
|
|
|
|
|
|
## Existing route and trust boundary
|
|
|
|
|
|
|
|
|
|
- GET /v1/approvals/{id}/claim requires approval:read and exact store tenant.
|
|
|
|
|
It supplies fresh approval facts and native five-field act binding, approval-free
|
|
|
|
|
PDP digest, PDP/human declarations. consumed=true lacks consumed request/decision
|
|
|
|
|
correspondence and cannot confirm execution admission.
|
|
|
|
|
- POST /v1/approvals/{id}/consume requires approval:consume, exact tenant and
|
|
|
|
|
service/agent principal. Body is request_digest plus decision_id. It returns
|
|
|
|
|
approval_id, status=consumed, request_digest, original decision_id when stored,
|
|
|
|
|
consumed_at and explicit idempotent boolean. Direct response to an authenticated
|
|
|
|
|
independent mediator is authoritative mutation evidence on its trusted transport.
|
|
|
|
|
- GET /v1/approvals/{id} requires approval:read. Approval.as_dict returns id,
|
|
|
|
|
persisted status, exact binding, validity, and consumption containing original
|
|
|
|
|
request_digest/decision_id/consumed_at. This existing read is the independent
|
|
|
|
|
consume-confirmation surface. It includes approver entries, so capture in memory
|
|
|
|
|
and discard them; never serialize the raw object into a receipt or tool output.
|
|
|
|
|
|
|
|
|
|
There is no signed portable consume receipt or dedicated public confirmation
|
|
|
|
|
endpoint. A caller boolean, ConsumedApproval dataclass, JSON receipt or local file
|
|
|
|
|
is not trusted proof. The mediator fetches the authoritative object itself through
|
|
|
|
|
its owner-pinned authenticated endpoint, with no caller-selected origin/opener.
|
|
|
|
|
Bearer authentication identifies the client to the server; the Platform owner must
|
|
|
|
|
also establish the server/transport identity. Generic HTTP support in the helper
|
|
|
|
|
is not evidence of an admitted production transport.
|
|
|
|
|
|
|
|
|
|
Identity/read reachability is explicitly unproved. The admitted Secrets client
|
|
|
|
|
does not grant a new Platform mediator approval:read/consume custody. KeyCape owns
|
|
|
|
|
any exact client/audience/scope/tenant registration and Platform owns transport and
|
|
|
|
|
credential custody; do not widen an identity profile or reuse Secrets credentials
|
|
|
|
|
merely to make a read work. In-cluster callers require the existing reviewed
|
|
|
|
|
NetworkPolicy namespace admission too. No credential was obtained in this review.
|
|
|
|
|
|
|
|
|
|
## Exact binding responsibilities
|
|
|
|
|
|
|
|
|
|
Source mechanisms: api.py ApiApplication.identity and consume route; auth.py
|
|
|
|
|
RS256/JWKS claim verification; store.py Engine.consume/Approval.as_dict/claim;
|
|
|
|
|
binding.py canonical_binding; execution_confirmation.py staged strict client.
|
|
|
|
|
|
|
|
|
|
Native binding digest covers action/actor/principal/purpose/target, preserving
|
|
|
|
|
arbitrary nested target. Extra top-level execution context is not part of this
|
|
|
|
|
native digest. It must be covered by the PDP's approval-free digest issued as
|
|
|
|
|
pdp_digest and the full enriched decision binding.request_digest submitted to
|
|
|
|
|
consume. Access owner reports ApprovalBindingDigest removes only top-level
|
|
|
|
|
context.approval: execution_contract remains covered. Compute through Access's
|
|
|
|
|
actual canonical CheckRequest implementation; never assume Python sorted-key JSON
|
|
|
|
|
is the Go request digest. Full enriched request includes the served claim.
|
|
|
|
|
|
|
|
|
|
Engine.consume validates digest syntax, not equivalence to pdp_digest or act, and
|
|
|
|
|
does not validate a DecisionEnvelope, decision_id existence or consuming sub
|
|
|
|
|
against binding.actor. This is the PIP boundary, not a second policy decision
|
|
|
|
|
point. A service holding consume scope can spend an approved object with an
|
|
|
|
|
unrelated well-formed digest; that response cannot substitute for the mediator's
|
|
|
|
|
prior independent exact claim/PDP/body/action/target/actor/principal validation.
|
|
|
|
|
|
|
|
|
|
Access's present v2 apply rules do not evaluate execution_contract. A distinct
|
|
|
|
|
execute-ccr action, published exact package/version/digest and verified initiating
|
|
|
|
|
principal/representation mapping are prerequisites, not inferred semantics.
|
|
|
|
|
Create enforces binding.actor==verified requester sub; the design must resolve
|
|
|
|
|
actual initiating principal vs execution service with Identity/Access owners,
|
|
|
|
|
without guessing actor strings or treating environment subject text as evidence.
|
|
|
|
|
All owner-compiled CCR/grant/catalog/source revisions, methods/paths/body hashes,
|
|
|
|
|
operation UUID and deadlines must remain in the approved underlying context.
|
|
|
|
|
Approval IDs and served claim additions must follow Access's explicit exclusion.
|
|
|
|
|
|
|
|
|
|
## Idempotency and lifecycle
|
|
|
|
|
|
|
|
|
|
BEGIN IMMEDIATE serializes consume; status compare-and-swap and local use outbox
|
|
|
|
|
are one transaction. The first consume requires approved status, current validity
|
|
|
|
|
window and declared human-control evidence. Different consumed digest conflicts.
|
|
|
|
|
Same digest returns idempotent=true and the original decision_id even if a retry
|
|
|
|
|
submits another decision_id, even after original expiry. No second use event is
|
|
|
|
|
created. That success is historical consumption, never renewed execution power.
|
|
|
|
|
The staged client requires exact original decision correspondence and rejects
|
|
|
|
|
string/integer booleans, missing times and decision-shaped responses.
|
|
|
|
|
|
|
|
|
|
Revoked/superseded/expired objects reject a first consume. Consumed is terminal:
|
|
|
|
|
revoke and supersede cannot cancel it, and expiry does not erase historical
|
|
|
|
|
consumption. A spent claim has valid_now=false (after deadline its reason/state
|
|
|
|
|
is expired while consumed remains true). Rechecking valid_now after consume
|
|
|
|
|
cannot validate continuation. The original validated approval/PDP/operation
|
|
|
|
|
deadlines bound every business write; failure stops further writes. In-flight
|
|
|
|
|
cancellation requires a separately owned execution stop/cleanup mechanism, not
|
|
|
|
|
post-consume approval revocation. Cleanup has its explicit original obligation.
|
|
|
|
|
|
|
|
|
|
## Independent mediator sequence
|
|
|
|
|
|
|
|
|
|
1. Independently reconstruct owner-approved operation bodies and binding; check
|
|
|
|
|
identity/source/revisions/deadline and exact published PDP package. No native
|
|
|
|
|
secret read/login, token mint or mutation during preparation.
|
|
|
|
|
2. Atomically reserve a one-shot execution journal admission for the immutable
|
|
|
|
|
approval/request/operation tuple; only creator proceeds. This journal is
|
|
|
|
|
Platform execution state, distinct from approval-engine outbox/consumption.
|
|
|
|
|
3. Fetch and validate a fresh human-controlled PDP-path claim, call Access Check,
|
|
|
|
|
require exact underlying/full digest, original act and policy pin, then one
|
|
|
|
|
CAS consume. Prefer consume at this mediator boundary to early CLI consumption.
|
|
|
|
|
4. Validate direct consume evidence with consume_exact; if separate Secrets code
|
|
|
|
|
returns a receipt, independently GET confirm_consumption with expected native
|
|
|
|
|
act and approval-free PDP digest. Match original exact decision/full digest/time.
|
|
|
|
|
Do not issue another mutating consume merely to discover whether one happened.
|
|
|
|
|
5. Persist confirmed evidence in the existing live journal before protected
|
|
|
|
|
calls. A successful idempotent response or GET without that same live one-shot
|
|
|
|
|
admission never permits execution. A CAS/read timeout marks unknown; owner
|
|
|
|
|
reconciliation may read confirmation but does not automatically resume work.
|
|
|
|
|
6. Check original deadlines before every native call, record about-to-call then
|
|
|
|
|
outcome, and maintain separately confirmed cleanup. Duplicate completed input
|
|
|
|
|
returns existing receipt only. Any incomplete/unknown operation requires owner
|
|
|
|
|
reconciliation and fresh exact recovery approval for another protected action.
|
|
|
|
|
|
|
|
|
|
The staged client implements only exact direct evidence and independent read
|
|
|
|
|
confirmation. It does not implement the journal, authorization policy, server
|
|
|
|
|
identity admission or execution. Existing Secrets consume_approval accepts wrong
|
|
|
|
|
approval_id, does not require original decision match and coerces idempotent;
|
|
|
|
|
Secrets owns its strict handoff refinement. Do not silently extend the generic
|
|
|
|
|
ProtectedActionHarness into an at-most-once execution service.
|
|
|
|
|
|
|
|
|
|
## Gates and validation
|
|
|
|
|
|
|
|
|
|
Existing owners/tasks retained: APPROVAL-WP-0002-T05 served T-06 consumer proof;
|
|
|
|
|
APPROVAL-WP-0002-T01 issuer/profile plus schema-v6 release evidence;
|
|
|
|
|
SECRETS-WP-0013 implementation and SECRETS-WP-0008-T06 full adoption;
|
|
|
|
|
RPF-WP-0035-T02 native lane adoption; exact Access/Identity action/representation
|
|
|
|
|
admission under those owners' records. No dependency is marked closed.
|
|
|
|
|
|
|
|
|
|
24 focused tests pass, including authenticated WSGI GET with no mutation/outbox
|
|
|
|
|
change, wrong act/target/actor/principal/purpose/digest/decision refusal, strict
|
|
|
|
|
booleans/time, denied read, filtered evidence and idempotency after expiry with
|
|
|
|
|
terminal revoke/supersede refusal. Staged full suite: 219 passed, one existing
|
|
|
|
|
JWT short-test-key warning. No production HTTP/DB/OpenBao call or native action.
|
2026-10-11 16:45:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
## Transport repair proposal after local redirect counterexample
|
|
|
|
|
|
|
|
|
|
The original source review above does not attest the inherited transport's
|
|
|
|
|
authoritative reachability. A later synthetic two-origin counterexample proved
|
|
|
|
|
that urllib's previous default followed a redirect, forwarded Authorization and
|
|
|
|
|
accepted its JSON. This is retained as a failed transport outcome, not rewritten
|
|
|
|
|
into a success. Bounded source repair is a new demand under
|
|
|
|
|
APPROVAL-WP-ADHOC-2026-10-11-T02, without residual promotion or native admission.
|
|
|
|
|
|
|
|
|
|
The staged default ApprovalHTTPClient transport uses the fixed provider-owned
|
|
|
|
|
http_transport.py child via the current Python executable with -I. Request data,
|
|
|
|
|
including bearer material, travels only through private process pipes, never
|
|
|
|
|
argv, logs or diagnostic output. The child receives an empty environment; environment proxy settings are ignored, every
|
|
|
|
|
redirect refuses without issuing another request, status must be exactly 200,
|
|
|
|
|
Content-Type must be a single application/json with UTF-8 (or no charset),
|
|
|
|
|
compressed/oversized/inconsistent responses refuse, and duplicate-key/non-finite/
|
|
|
|
|
malformed/non-object JSON refuses. Backend/error bodies are not read or exposed.
|
|
|
|
|
Public errors contain closed provider messages and numeric status only.
|
|
|
|
|
|
|
|
|
|
The parent's subprocess timeout covers DNS/connect/TLS/header/body/error-close
|
|
|
|
|
and process cleanup for the fixed child, which has no retry or subprocess
|
|
|
|
|
descendants. It avoids SIGALRM and multiprocessing-spawn main-guard requirements
|
|
|
|
|
so default SDK calls remain usable in worker threads and ordinary scripts.
|
|
|
|
|
The token is read from a bounded local regular file using nonblocking/no-follow
|
|
|
|
|
descriptor traversal: no symlink component, final hardlink, other-readable or
|
|
|
|
|
group-writable mode, non-current/non-root owner, FIFO/directory or oversized
|
|
|
|
|
credential is accepted. Restrictive current/root-owned group-readable files
|
|
|
|
|
(such as 0440) are permitted; unknown projected/symlink credential layouts must
|
|
|
|
|
be corrected by the custody owner, never silently followed or substituted.
|
|
|
|
|
Only ASCII non-whitespace bearer content is admitted; credential errors do not
|
|
|
|
|
republish paths or values. The file is reopened every request, retaining rotation.
|
|
|
|
|
|
|
|
|
|
The explicit opener injection is retained solely as a trusted owner test-adapter
|
|
|
|
|
seam; it does not inherit isolated/default transport admission or total deadline
|
|
|
|
|
guarantees. Supplying urllib.urlopen as an injected opener recreates its own
|
|
|
|
|
redirect/proxy behavior and must not be admitted as production execution
|
|
|
|
|
confirmation. Native mediator implementation must use this fixed default or a
|
|
|
|
|
separately reviewed equivalent; caller-selected transport code is unacceptable.
|
|
|
|
|
The default code still supports HTTP for reviewed private estate routes; source
|
|
|
|
|
validation does not prove TLS, the actual server origin, deployed custody/read
|
|
|
|
|
scope or ingress admission. No native identity/profile is widened.
|
|
|
|
|
|
|
|
|
|
After a timeout/refusal, consume remains potentially unknown and cannot be
|
|
|
|
|
retried to infer absence. Fresh exact claim/PDP validation, returned original
|
|
|
|
|
consumption correspondence and separate one-shot journal remain required.
|
|
|
|
|
This is a transport repair only, never an execution authority or replay service.
|