Specify private descriptor context for maintenance consumers
1 file changed,
+47
−0
implementation/maintenance-launch.md+47 −0
CI passed — run details
diff --git a/implementation/maintenance-launch.md b/implementation/maintenance-launch.md| new file mode 100644 |
| index 000000000..c13a25763 |
| --- /dev/null |
| +++ b/implementation/maintenance-launch.md |
| @@ -0,0 +1,47 @@ |
| +# 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. Status: proposed, pending independent review and concrete worker implementation. |
| + |
| +## Boundary |
| + |
| +The reviewed worker launches a verified artifact under the existing trusted-platform/shared-UID exec model. A private inherited descriptor identifies a worker invocation to the app adapter. This is not a signature proving an arbitrary local process is CARLOS: a malicious process with the same UID and app keys already crosses that model's boundary. The descriptor must never be exposed through the console request, supplied argv, request environment, app HTTP, or a caller-selected path. An environment boolean is not invocation evidence. |
| + |
| +Only after current-owner approval, immutable request/preflight/environment checks, matching lifecycle claim and guard/projection, continuous healthy lease, checked stop, existing-DB identity and strict containment setup may the worker construct the context. Durable executing state must precede spawning. The context is generated from those checked objects, not copied from request fields. It grants no authority on its own to a worker that has not passed those gates. |
| + |
| +## 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. cmd.ExtraFiles contains exactly that read endpoint, with no unrelated descriptors. Go's descriptor remapping supplies fd3; the caller cannot set its number or substitute a filename. 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. |
| + |
| +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. |
| + |
| +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. |
| + |
| +## 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: |
| + |
| +- version: integer1. |
| +- account, app, host: exact validated route identity using the shared platform validators. |
| +- request_id, attempt_id: canonical base64url encoding of32 random bytes,43 characters each. |
| +- request_digest, record_identity, artifact_digest, environment_envelope_digest: lowercase64-character SHA256. Request digest binds immutable approved nonsecret metadata; record identity uses the guard's canonical identity; artifact digest binds the actual executed artifact; environment digest binds the randomized approved encrypted snapshot. These values are not substituted from live pointers after approval. |
| +- guard_generation: positive integer through signed64-bit maximum, matching executing authority. |
| +- input_sha256: lowercase64-character SHA256 of the exact stdin bytes. This private low-entropy hash is confined to the pipe and must not enter public receipts or logs. |
| +- database_path: exact absolute platform-owned existing path, valid UTF-8, at most1024 bytes, no NUL. database_device and database_inode: canonical unsigned64-bit decimal integers describing the already checked regular, nonsymlink file. Zero identity is unsupported rather than a portable fallback. This class remains native Linux only. |
| +- execution_deadline: exact UTC RFC3339Nano timestamp set by the worker for this attempt, no later than its operation timeout. The worker enforces a separate conservative monotonic lease safe-until deadline and terminates before loss of exclusive ownership. This timestamp is only an additional child refusal bound; it is not proof of current lease health and cannot extend a lease or operation. |
| + |
| +No field says fenced, approved, owner, role, allowed action or maintenance=true. Those would turn the context into an unverified body assertion. The actual worker's construction gates establish transport authority. The app's role/origin/action restrictions come from its exact pinned private launch environment, whose snapshot digest is bound here; no caller-supplied environment overrides are permitted. These app-specific keys and their schema remain owned by Home's approved command design. |
| + |
| +## Home adapter binding |
| + |
| +The fixed Home command accepts only its reviewed launch mode and platform-owned database selector. Before mutation it verifies the exact signed Home input, its operation allowlist and the configured expected role/origin from the pinned environment, then compares the input byte digest with the context. It obtains Home operation_id from that verified signed input and binds it to the context's distinct platform request/attempt IDs in its invocation/result metadata. Platform does not parse or rewrite Home's signed JSON. An explicitly approved retry may use a new transport attempt for the same Home operation; Home's existing transaction/idempotency rules return the committed result without repeating the mutation. |
| + |
| +The adapter opens only the exact expected existing DB and verifies the opened file's actual path/device/inode identity before allowing its command engine to mutate. It refuses missing databases, symlinks, replaced files, wrong role/origin/schema and unsupported identity checks; it never restores, seeds or initializes as a fallback. A private constructor creates the app's opaque invocation context only after those checks. Exported body structs cannot fabricate that context. The worker retains its lifecycle fence and lease while the app runs and independently rechecks DB identity afterward. Checking an input pathname alone is insufficient; the concrete SQLite/open-file sequence must demonstrate that the database actually mutated is the same checked file. |
| + |
| +The app never persists the raw launch context or private input digest to public state or logs. Permanent platform receipts bind ciphertext digests and immutable nonsecret metadata. Existing Home private result/receipt storage keeps its established protection. Empty or malformed stdout, overflow, nonzero exit, timeout, lost lease or containment uncertainty produce no successful operation evidence. |
| + |
| +## 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. |
| +3. Home tests reject missing/extra/duplicate/malformed context fields, wrong request/input/artifact/environment/record/DB identity and expired deadlines, with zero mutations. 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. |