railiance-platform/docs/task-execution-native-fixture.md
codex 7be8b6e76d
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Prove trusted task chain and prepare bounded signer custody
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a140c4-354a-7823-8f0d-8f717397f786
2026-10-16 17:29:12 +02:00

274 lines
18 KiB
Markdown

# Executable native metadata/grant/cleanup preparation
RPF-WP-0035-T12, 2026-10-16, second source package after the cleanup journal.
The fixed `NativeFixtureAdapter` actually dispatches to disposable loopback OpenBao.
It requires a live owner-spawned OpenBao dev-process handle with the exact loopback
port and dev/no-store-token arguments, and refuses every non-loopback origin.
Production is deliberately not implemented. This is a guard against accidental
misrouting inside the trusted fixture runtime, not a Python security sandbox.
No estate credentials, grants, approvals or policy packages are read or changed.
The tests start in-memory dev servers with synthetic root/session credentials,
synthetic owner admission, grant/state/source digests and a synthetic postconsume
journal transition. This proves native primitives, not authenticated admission.
The owner Compiler now deterministically includes the operation-specific temporary
policy name and cleanup call commitments in each serialized Plan. Commitments
include identity/task credential slots, exact native revoke/verify or delete/verify
method/path pairs, and the narrow no-issue/no-create skip branches. The full
execution descriptor can be bound into that Plan only by byte equality with an
independently installed owner descriptor, with operation/actor/CCR/catalogue/six
operations correspondence. Compiler revalidation preserves both descriptor and
cleanup content. The descriptor's SHA is preparation provenance; no opaque digest
or local file becomes approval or verified canonical request correspondence.
The adapter needs the exact compiler/Plan/binding and separately installed owner
fixture inputs. All handles stay in owner memory with hidden representations. It
requires the same live consumed journal admission and exact grant-issuing state.
It refuses an existing per-operation grant policy, creates only the two compiler
metadata endpoints plus revoke-self, verifies HCL, mints one parented service token
with only this policy, no default/identity policies, nonrenewable TTL <=120 seconds
and twelve uses, then verifies native token bounds through the owner. Six ordered
metadata calls use independently recompiled source/method/path/body. A task use is
reserved for revoke; native token limits also enforce the ceiling. Business calls
check wall and monotonic deadlines before effect, with a five-second cleanup reserve.
No retry/remint, caller HCL/JSON/path, mount/AppRole/KV/SecretID or shell API exists.
Wave 5 below adds exact sequential snapshot acceptance; native baseline CAS remains absent.
Every business/grant request records durable intent and closed status evidence.
Native cleanup has its own durable per-request intents beneath the original
committed obligation; accessor verification cannot erase an uncertain revoke.
The native adapter compares the exact committed cleanup sequence before request.
Self-revoke success must be followed by owner lookup-accessor's specific invalid
accessor response; generic HTTP400/403, timeout and policy deletion do not prove
revocation. The two explicitly accepted error encodings cover OpenBao's plain and
wrapped single-invalid-accessor forms. Native error text is never logged or hashed.
Cleanup bypasses expired business deadlines under the retained explicit obligation,
never source-driven business repair. Independent cleanup continues after failure;
retirement never overwrites the original unknown/failed business outcome.
Current actual native tests cover policy/body and K8s-role application/readback,
owner-parented TTL/use policy bounds, native sibling/KV/token/mount/SecretID capability
denial, both token accessor-invalid proofs, policy absence, deadline-expired cleanup,
source drift, no preconsume materialization, changed descriptor/cleanup commitments,
nonloopback refusal, actual write followed by simulated lost response, and actual
policy retirement with failed task revocation. The lost response is fault injection
after a successful real native write; it does not pretend to be an actual network
partition. The failed-revoke fixture independently confirms the still-existing
native token, then performs explicit synthetic owner recovery. No blind retry occurs.
## Minimal remaining decisions and integration
1. Define/admit `task-execution-grant` in the owner CCR validator. Bind the exact
cleanup commitments, temporary policy/token bodies and source revisions into its
immutable projection, referenced by the existing descriptor grant SHA. The
descriptor currently has no cleanup field; no engine schema extension is needed
if this owner grant binding is made explicit. The immutable projection/excluded
append-only fields are not implemented in the current owner validator. This is
the concrete owner schema/admission decision, not a need for a new service.
2. Have the existing authoritative engines supply authenticated initiating principal,
exact canonical request + served claim/PDP/package and independent signed CAS
consume verification to the owner mediator before its journal transition.
The native fixture's local transition supplies none of that evidence.
3. Install exact origin/cluster/source/grant/baseline/readback inputs under the
attended owner runtime. The current binder compares independently installed
descriptor bytes, but does not authenticate source-bundle paths, grant digest or
compute immutable CCR projection. The six-operation plan still comes from pinned
actual owner source. Production origin authentication and deadline bounds against
served approval/PDP remain separate.
4. Finish expected-state normalization and conflict handling for native K8s/OIDC
defaults; add per-policy/role approved baseline comparison and exact readback
verification. The fixture checks known fields, not total production equality.
OpenBao metadata PUT has no native atomic CAS; the owner must choose exclusive
admitted target custody or an honest conflict/recovery protocol.
5. Wire the fixed adapter to that mediator with bounded runtime isolation,
owner-private uncertain-issuance recovery, external audit outbox and exact
founder-scoped attended trial. No production caller or protected recovery channel
exists here. The existing production readiness gate remains refused.
No umbrella broker, general executor, new credential catalogue or standing service
admin entitlement is introduced. Approval CAS prevents approval replay; it cannot
make uncertain native effects exactly-once. RPF T12 and Secrets WP13 remain open.
### Exact disposable metadata acceptance (2026-10-16, wave 5)
The owner-installed `FixtureAdmission` now carries canonical JSON before/after
snapshot bytes. Their SHA-256 values must equal the existing descriptor's
`expected_before` and `expected_after`, and both snapshots must name exactly the
two compiled metadata paths. Explicit JSON null means absence. Only the actual
OpenBao empty-errors 404 is accepted as absence; denied/malformed reads fail.
These inputs contain metadata, never KV values or private token handles.
Policy comparison retains name, HCL, version and cas_required. Only the
modification timestamp is excluded, after requiring an aware timestamp and the
closed observed policy field set. Role comparison retains every returned field,
including aliases, token defaults and unexpected additions, using canonical JSON
bytes (therefore false cannot equal zero). The disposable Kubernetes fixture pins
the complete OpenBao 2.5.5 response shape. Another plugin/version/default requires
an independently reviewed owner snapshot; nothing infers new accepted defaults.
Each baseline gates its corresponding write. Policy readback occurs before role
baseline/write/readback. A role conflict can therefore leave the policy applied;
that operation remains unknown. This sequence has no native CAS, aggregate
baseline gate, concurrent-writer exclusion, or simultaneous final-state proof.
After all six calls match the committed snapshots, the same-live adapter records
readback and verified with a value-free evidence digest. The mediator reports
native_apply verified; cleanup-confirmed requires all separate cleanup receipts.
Readback success with unconfirmed cleanup cannot reach cleanup-confirmed.
Reopening SQLite cannot dispatch, reconsume, restore token/accessor handles or
retry cleanup. Native effects can survive process loss. Cleanup handles remain
memory-only: no independently authorized recovery mechanism is implemented here.
This closes disposable sequential apply acceptance only, not TSA03 or native
production recovery/admission.
## Independent cleanup recovery source successor
`task_execution_recovery.py` adds separately installed fixture-only owner custody
and fresh recovery permits. Optional `recovery_custody` on NativeFixtureAdapter
persists the original binding/cleanup commitments, exact operation policy, backend
port and identity accessor before any grant effect; it commits mint intent before
token creation and task accessor immediately after a valid issued response.
Bearer credentials are never persisted. The custody directory is separate from
the public journal, owner-only 0700/0600, bounded at 64KiB, no-follow, with atomic
replacement and fsync. It is real process-independent persistence for synthetic
fixtures. It does not isolate same-UID hostile execution, encrypt at rest, select
production storage or establish a production secret policy. Those are explicit
native custody/deployment gates, not supplied by Python types or file modes.
The independent owner reads its private custody revision and installs a fresh
bounded permit, current owner credential and retained live disposable Popen.
Permit revocation is durably owner-recorded. The recovery runner has no mint,
consume, policy-apply or business method. It dispatches only fixed exact-accessor
revoke/readback and exact `task-exec-<operation>` policy read/delete/readback.
A differently recreated policy is never deleted. Backend admission remains the
same loopback-only owner-spawned dev process; no estate backend can be selected.
Accessor-based recovery is an independently admitted alternate cleanup projection,
not a reinterpretation of the original revoke-self call digest. Production needs
exact owner-reviewed recovery scope; original business grant does not imply it.
Fresh recovery holds the journal process lock but never sets business admission
or consumed-admission fields. Separate recovery attempt/call/result tables retain
original cleanup statuses before reconciliation, write native intent before calls,
and preserve failed/pending outcomes. Proven cleanup alone updates the exact
original cleanup obligation to confirmed. Business state and original pending
call uncertainty remain unchanged. Reusing the original approval, continuing
metadata calls and reusing a recovery permit refuse. Failure needs another
independent owner permit; there is no automatic retry. Expired/revoked permits
or changed private custody revision refuse before calls.
A token-create response lost before accessor custody remains unresolved token
cleanup debt: policy deletion/identity revocation can be independently confirmed,
but cannot imply task-token revocation. Neither expiry guessed from wall clock
nor policy absence fabricates token absence. A production successor must admit
an independent exact ambiguous-issuance reconciliation mechanism or prove bounded
expiry from owner backend evidence. No such new grant is implemented here.
`test_task_execution_recovery.py` forks a real executor and terminates it without
finally cleanup after issue, business effect/lost response and revoke/lost response.
The independent parent, holding the backend and separately installed custody,
recovers specific obligations and verifies actual token/policy absence. Additional
cases cover lost-mint response, revoked credential, permit revocation/expiry,
revision drift, namespace policy-name reuse and private-file/binding refusals.
This is source fixture proof only. Native custody, isolation, exact recovery-role
permissions, retention/encryption, clock admission, audit delivery and human scope
approval remain missing. No generic broker, production reader, grant or CLI is added.
### Recovery R2 exact absence and authenticated capsule refinement
R1 overclaimed policy absence for arbitrary 404 bodies. R2 requires exactly
`{"errors":[]}` for both initial GET and post-DELETE GET. Other 404 bodies,
permission denials, extra data, malformed/duplicate-key/nonfinite JSON and failed
readback cannot confirm policy cleanup. A successful DELETE status alone cannot
confirm absence. Recovery native policy comparison admits precisely one optional
terminal LF, matching the retained OpenBao HCL source/readback convention; spaces,
tabs, CR, extra terminal LF and any other byte change are refused. This is a
narrow declared normalization, not full whitespace or semantic equivalence.
Private fixture capsules now carry HMAC-SHA256 authentication under an exactly
32-byte integrity key supplied independently by the recovery owner. The key is
never stored in the capsule or public journal, and is not a bearer credential.
The fixture owner retains this key independently across executor death; a fresh
owner custody object must supply the same key. Wrong-key or damaged accessor/HCL
bytes refuse before admission. This is integrity protection, not encryption or
same-UID isolation; production key custody, rotation/retention and recovery actor
selection remain explicitly unadmitted.
After authentication the reader enforces exact top-level and nested binding/
cleanup key sets and types, validated Binding/Cleanup formats and the ordered
source-derived cleanup_specs operation digests. Duplicate JSON keys, nonfinite
numbers, malformed phase/revision combinations and type-coercible values refuse.
The reader bounds bytes, rejects indirect/nonprivate files and detects stat/size
changes during its single read. A valid older prepared capsule still cannot
prove a task token absent when durable journal state/calls reached issuance:
that remains unknown cleanup debt. Authentication alone is not anti-rollback.
No business or consume admission is restored and no production scope is granted.
## Absolute budgets, effective credential expiry and exact source bytes
This source successor tightens the disposable native owner adapter; it does not
establish actual v2 whole-stack ALLOW/native acceptance. The retained-registry
Approval correspondence failure is preserved in the coordinator artifact. The
new real provider fixture is retained separately as unfinished follow-up, while
the existing ec215-based fixture evidence remains its original scoped proof.
Every native business/grant method now runs inside the earlier wall/monotonic
operation deadline minus the five-second reserve. After exact owner token lookup,
the adapter requires aware expire_time and retains the earlier actual expiry and
conservative mint-start + declared TTL bound, in wall and monotonic coordinates.
Every subsequent business call uses the minimum of global and credential bounds.
The descriptor and signed global deadline are never extended or rewritten.
Missing/expired credential evidence refuses issuance acceptance. Cleanup continues
under its original separate obligation after either business bound expires.
The fixture owner main-thread execution profile uses absolute SIGALRM budgets,
not socket inactivity timeouts alone. Each native transport and cleanup native
call has a two-second execution deadline, including intent/source checking and
send/header/body/close work. Larger compiler reconstruction remains within the
earlier operation/credential window. A 50ms alarm backstop keeps blocked teardown
interruptible after timeout; it cannot authorize another business effect. Nested
timers retain the shorter outer deadline rather than refreshing it. Unsupported
threads, invalid budgets and conflicting ambient timers refuse. This fixed Unix
fixture profile does not select a production process supervisor or provide a
shared arbitrary-thread execution service. Native rollout still needs exact owner
runtime/admission, trusted clock and independent recovery/custody enforcement.
The actual v2 package/version selects additional mediator checks over the exact
independently installed descriptor source_bundle before authorization and each
freshness gate, including pre-native grant entry. It reads bounded regular,
files without group/world write, non-indirect paths, compares exact source hashes and stat stability,
and applies an absolute read budget. The existing compiler's own pin set does not
implicitly authenticate other source_bundle roles; these explicit checks fill
that gap. No requester-selected path, approval flag or source boolean can enable
this path. Legacy synthetic fixture proof remains separately scoped and is not
used to satisfy v2 acceptance.
Native policy/grant absence now requires exact empty-errors404 and policy HCL
comparison admits only the already reviewed single optional terminal LF, reusing
frozen recovery R2 helpers. Native response JSON rejects duplicate/nonfinite data.
The independent slice tests cover actual header/body drips, stalled close after
timeout, slow compiler and shorter actual credential expiry before any HTTP
effect, nested/conflicting/foreign-thread budgets, private source hash drift,
unsafe modes/indirection/FIFO/oversize refusal, and bounded cleanup after expiry.
Actual native fixed grant/metadata/readback/cleanup remains a separate positive
compatibility check. There is no successful actual normalized provider-chain
claim in this slice; source-managed pre-approval normalization and immediate CAS
precision must pass the follow-up full-stack proof first.
2026-10-16 T12 actual v2 successor source proof: retained registry signed DENY
normalization from the real Secrets prepare_task_approval builder precedes actual
Approval issue/human approval. Actual Access v2 then signs ALLOW; strict Secrets
CAS and independent confirmation GET precede six disposable native calls, exact
readback and confirmed token/policy cleanup. Approval precision source permits
immediate CAS without sleeps/backdating. The 60-second immutable deadline,
30-second backend TTL, 120-second synthetic observation and existing cleanup
reserve remain bound; issued credential expiry narrows business time. Source,
caller, revoke, source-reader, registry drift and expiry refusals cause no native
effects; revoke between ALLOW/CAS retains unknown without business dispatch.
This owner fixture uses separately installed synthetic identity/key/trust and
loopback OpenBao, grants no production authority and keeps T12 progress. Prior
failed temporal/normalization proofs remain retained.