carlos / platform Public

Clarify launch adapter descriptor lifetime and pending Home integration

Paul Campbell pushed by paul@keymail.dev 8eb788c946e1fa9b15ff6a71773f7c9ffb4db52f parent caf47fb
1 file changed, +6 −4
  • implementation/maintenance-launch.md +6 −4

CI passed — run details

diff --git a/implementation/maintenance-launch.md b/implementation/maintenance-launch.md
index 19ab3c1f3..d340b9602 100644
--- a/implementation/maintenance-launch.md
+++ b/implementation/maintenance-launch.md
@@ -1,6 +1,6 @@
# Private launch context for maintenance consumers
-Implementation supplement to the approved maintenance-exec.md6a81dac contract. This resolves the Home operator adapter's external invocation-context dependency; it does not enable maintenance or replace any owner, guard, lease, containment, or release gate. Initial4605a54 supplement received independent Fable APPROVE. This revision aligns the verified artifact descriptor and concrete implementation clarifications; delta review and worker implementation remain pending.
+Implementation supplement to the approved maintenance-exec.md6a81dac contract. This specifies the proposed Home operator invocation contract; it does not enable maintenance or replace any owner, guard, lease, containment, or release gate. Initial4605a54 supplement received independent Fable APPROVE. The caf47fb delta received REQUEST_CHANGES. This revision addresses its descriptor-lifetime, status, and verification findings; independent review remains pending. The worker launch path and all Home startup-adapter behavior described below are unimplemented: fd3 parsing, --db/context binding, fd4 handling, and the self-executable check. Home7e has an unmounted opened-DB connector, not this adapter. Before mounting, Home must separately amend and review its approved4770bc6 opened-DB contract to specify this startup ordering; this document does not silently change that contract.
## Boundary
@@ -10,12 +10,14 @@ Only after current-owner approval, immutable request/preflight/environment check
## Descriptor layout and lifetime
-Child fd0 receives the exact validated private JSON stdin. Child fd1 is the bounded private result channel. Child fd2 is /dev/null. Child fd3 is the read end of a newly created private pipe carrying the launch context. Child fd4 is the regular read-only artifact descriptor whose actual bytes the worker has already hashed and verified against the approved release. cmd.ExtraFiles contains exactly those two related descriptors, in that order, with no unrelated descriptors. The strict Linux path executes /proc/self/fd/4 after Go descriptor remapping, with no fresh pathname lookup or fallback; replacing the staged pathname cannot change the executed inode. The child can close fd4 after startup; the worker retains its own verified artifact descriptor for the attempt. Go's descriptor remapping supplies fd3/fd4; the caller cannot set their numbers or substitute filenames. Each pipe/artifact descriptor set permits exactly one spawn attempt; a failed Start never calls a build closure a second time or reuses consumed pipes. The worker owns the write endpoint, writes the complete bounded context, then closes it. Parent descriptors close on every spawn/error/termination path. Child receives no deployment credentials beyond the already approved app environment.
+Child fd0 receives the exact validated private JSON stdin. Child fd1 is the bounded private result channel. Child fd2 is /dev/null. Child fd3 is the read end of a newly created private pipe carrying the launch context. Child fd4 is the regular read-only artifact descriptor whose actual bytes the worker has already hashed and verified against the approved release. cmd.ExtraFiles contains exactly those two related descriptors, in that order, with no unrelated descriptors. The strict Linux path executes /proc/self/fd/4 after Go descriptor remapping, with no fresh pathname lookup or fallback; replacing the staged pathname cannot change the executed inode. The child must verify fd4 is an O_RDONLY regular file, compare its device/inode with an opened /proc/self/exe descriptor, and stream the actual executable SHA256 against context.artifact_digest after validating fd3. It must then close both executable descriptors with checked errors BEFORE Home takes its opened-DB descriptor baseline. Failure refuses before any mutable DB open. The child does not reopen the staged artifact by pathname. The worker retains its own verified artifact descriptor throughout the attempt. Thus fd4 is a startup-only descriptor, never an additional regular file admitted into Home's database baseline. Go's descriptor remapping supplies fd3/fd4; the caller cannot set their numbers or substitute filenames. Each pipe/artifact descriptor set permits exactly one spawn attempt; a failed Start never calls a build closure a second time or reuses consumed pipes. The worker creates and owns os.Pipe pairs for stdin, stdout and fd3; it passes the corresponding *os.File ends to the child and supervises the other ends explicitly. It does not delegate these copies to exec.Cmd-managed goroutines or depend on Wait/WaitDelay to interrupt blocked IO. It writes the complete bounded context, then closes that endpoint. Parent descriptors close on every spawn/error/termination path. Child receives no deployment credentials beyond the already approved app environment.
-Context and stdin writes run with cancellation and termination awareness, alongside bounded stdout capture, so a child that never reads cannot wedge the worker. The worker's deadline/lease supervisor stays independent of blocked pipe writes or output reads. The strict cgroup path has no ordinary Start fallback; process-tree death, including descendants holding pipes, is checked before any result or resume success. App input timeout/refusal never authorizes automatic retry.
+Context and stdin writes run with cancellation and termination awareness, alongside bounded stdout capture, so a child that never reads cannot wedge the worker. The worker's deadline/lease supervisor stays independent of blocked pipe writes or output reads. Maintenance must use the reviewed strict cgroup preparation/start path and must never call cgroup.Manager.Start, whose ordinary path can build twice and fall back to spawn-then-move. The strict path has no ordinary Start fallback; process-tree death, including descendants holding pipes, is checked before any result or resume success. App input timeout/refusal never authorizes automatic retry.
The app adapter reads fd3 at most8KiB plus one overflow-detection byte, requires EOF, rejects truncation, and closes it. It reads stdin at most64KiB plus one overflow-detection byte and requires EOF. No context fallback to argv, environment booleans, files or HTTP exists. A missing/invalid context produces the app's fixed refusal without opening a mutable database. The worker bounds the entire attempt; the adapter must not wait indefinitely for context or stdin and performs these reads under its own bounded startup deadline.
+This launch class is an exec-backed route using a kind=binary release: artifact_digest is the per-file SHA256 of the actual executed binary, not an archive or an unsigned version label. The retained fd pins the inode, not immutable content. Platform artifact writers must preserve those bytes for the full attempt. A same-UID process rewriting the inode is inside the stated trusted-platform boundary; this design does not claim protection against it. The child self-executable hash check detects a changed image before DB access, but cannot make arbitrary later same-UID writes safe.
+
## Version1 context
A closed UTF-8 JSON object, with duplicate and unknown keys, trailing data, noncanonical numeric forms, invalid encodings and oversized fields rejected. Every listed field is required:
@@ -42,6 +44,6 @@ The app never persists the raw launch context or private input digest to public
## Required verification before wiring
1. Worker tests reject user-controlled fd/env/context substitutions; pre-execution failures spawn no child; immutable expected bindings change only through a newly approved request. Byte-exact signed input reaches stdin; private context/input/output never reach argv, public status, stderr, logs or receipts.
-2. Actual subprocess fixtures verify fd3 inheritance, no unrelated inherited descriptors, EOF, blocked-read/write cancellation, exact expiry behavior, output overflow and descendant-held pipes. Fixtures use synthetic keys/DBs and isolated credentials only.
+2. Actual subprocess fixtures verify fd3 inheritance and fd4 as an O_RDONLY regular file with device/inode equal to the worker's retained, already-hashed artifact descriptor. Replacing the staged pathname before execve of /proc/self/fd/4 must still execute that verified inode, with no pathname fallback. Verify child fd4 and self-executable descriptor closure before the Home database baseline, refusal on mode/identity/hash/close failure, and worker retention through completion. Also verify no unrelated inherited descriptors, EOF, blocked-read/write cancellation, exact expiry behavior, output overflow and descendant-held pipes. Fixtures use synthetic keys/DBs and isolated credentials only. The existing /tmp/oficina-maintenance-execfd-proof/result.json is local descriptor/path-replacement evidence only; it proves no worker, cgroup, lease, Home adapter, or deployed execution behavior.
3. Worker tests reject wrong approved request/artifact/environment/record bindings before constructing the context; Home has no independent expected randomized environment-envelope digest or platform record identity and must not pretend to check these against invented duplicate environment flags. Home tests reject missing/extra/duplicate/malformed context fields, wrong exact input digest, selector/context mismatch, actual opened DB identity and expired deadlines, with zero mutations. The adapter also streams a SHA256 of /proc/self/exe and compares context.artifact_digest, checking the actual running image without trusting a pathname. Actual file replacement/symlink races must fail against the opened DB identity. Exact replay under a fresh approved transport returns the same committed Home result.
4. Whole worker plus consumer Fable review and full native/cross-platform CI remain required. Native Linux canary proves actual cgroup/systemd/lease/fence and verified artifact/config behavior. Neither this design nor a locally injected fd3 fixture is deployed proof or authorization for a live operator invocation.