From be5c803e8e5a97796194f83582c8fe70f01327d0 Mon Sep 17 00:00:00 2001 From: codex Date: Mon, 27 Jul 2026 02:58:07 +0000 Subject: [PATCH] docs(prd): define authoritative failure boundaries --- .../0082-authoritative-failure-boundaries.md | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 docs/prds/0082-authoritative-failure-boundaries.md diff --git a/docs/prds/0082-authoritative-failure-boundaries.md b/docs/prds/0082-authoritative-failure-boundaries.md new file mode 100644 index 00000000..596441c9 --- /dev/null +++ b/docs/prds/0082-authoritative-failure-boundaries.md @@ -0,0 +1,130 @@ +# PRD 0082: Authoritative failure boundaries + +- **Status:** Draft +- **Author:** codex +- **Created:** 2026-07-27 +- **Issue:** #444 + +## Summary + +Make every security- or lifecycle-sensitive snapshot distinguish authoritative +empty state from unavailable state, and make every destructive or +resource-consuming boundary revalidate the assumptions it acts on. This +finishes the focused quality work begun under #444 without broad rewrites: +cleanup cannot act on stale identities, policy introspection cannot publish a +fabricated empty policy, gateway servers bound untrusted work, and daemon +shutdown does not emit uncaught background-thread failures. + +## Problem + +Several paths are individually fail-closed but compose into unsafe or +misleading behavior: + +1. `cleanup` prepares a plan, waits indefinitely for operator confirmation, + then kills stored PIDs and removes stored paths without checking that those + identities still describe the same orphan. A PID may be reused or a run + directory may become active during the prompt. +2. The supervisor reuses egress's deny-all fallback for + `list-egress-routes`. Deny-all is correct for enforcement, but presenting it + as a successful empty route table can cause a later replace-all proposal to + discard live routes. +3. The supervisor and Git HTTP services accept bounded declared body sizes but + use blocking reads and unbounded request threads. An untrusted bottle can + exhaust the shared gateway with slow or parallel requests. +4. macOS cleanup enumerates containers and networks independently and treats a + failed query as an empty class, so a partial snapshot can still become a + destructive plan. +5. Gateway log-pump threads race stream closure during shutdown and emit + uncaught exceptions even when shutdown otherwise succeeds. + +These are one design problem: state used to authorize deletion, replacement, +or resource allocation must be authoritative at the point of use. + +## Goals / Success Criteria + +- Cleanup never signals a PID or recursively deletes a path solely because it + appeared in a pre-confirmation snapshot. +- Firecracker cleanup proves immediately before action that a PID is still the + same Firecracker process and that a run directory is still orphaned. +- All backend cleanup discovery primitives raise a typed enumeration error on + operational failure. No backend may independently continue from a partial + snapshot. +- Shared cleanup control flow lives in the backend layer; concrete backends + override resource-specific discovery and validation primitives rather than + each implementing a bespoke failure policy. +- `list-egress-routes` returns an MCP error when attribution or policy + resolution is unavailable. A genuine, authoritatively resolved empty policy + remains a successful empty list. +- Supervisor and Git HTTP request bodies have total read deadlines, and each + service bounds concurrent request work. Limits apply to authenticated + callers because bottles themselves are untrusted. +- Gateway child-output pumping treats expected stream closure during shutdown + as completion while preserving diagnostics for unexpected failures. +- Unit tests cover PID/path reuse, partial backend enumeration, transient + policy resolution failure, slow bodies, concurrency saturation, and stream + closure races. + +## Non-goals + +- Further decomposition solely to reduce module line counts. +- Replacing gateway stdlib HTTP services with a web framework. +- Changing egress matching, DLP decisions, proposal semantics, or backend + launch behavior beyond the synchronization required for safe cleanup. +- Making cleanup silently skip uncertain resources. Uncertainty is an + operator-visible failure. + +## Design + +### Shared backend control flow + +Follow the backend architecture rule used by gateway attachment: shared +behavior lives above concrete backends; subclasses provide primitives, not +control flow. + +Cleanup remains previewable, but confirmation authorizes a *new authoritative +evaluation*, not blind execution of the displayed object. The shared flow: + +1. asks each available backend for a preview; +2. displays the union and asks for confirmation; +3. refreshes each non-empty backend plan; +4. validates destructive identities immediately before action; +5. aborts loudly if the refreshed plan or any identity cannot be proven safe. + +Backend-specific primitives define how to identify a resource. Firecracker +uses process start identity plus canonical config/run paths; container +backends use authoritative CLI queries and stable resource names/labels. + +### Enforcement state versus introspection state + +Egress enforcement retains its deny-all fallback because uncertainty must not +grant network access. Supervisor introspection uses a strict resolver path: +unattributed callers and resolver failures become typed MCP errors, while a +successfully resolved policy containing zero routes returns `routes: []`. + +### Gateway resource boundaries + +Both stdlib servers set a per-connection body deadline before reading and use a +bounded request executor or semaphore. Saturated capacity fails quickly with a +service-unavailable response. Existing size caps remain independent: +supervisor proposals retain the 1 MiB cap and Git pack requests retain their +larger protocol-appropriate cap. + +### Shutdown diagnostics + +The gateway output pump catches only stream-closure exceptions expected after +the supervisor closes child pipes. Other I/O failures remain visible and are +reported through the supervisor's normal diagnostic channel. + +## Implementation chunks + +1. Existing fail-closed security and backend enumeration fixes. +2. FastAPI orchestrator transport and bounded control-plane bodies. +3. Egress request-policy and outbound-DLP pipeline extraction. +4. Supervisor MCP dispatch extraction. +5. Shared cleanup refresh/revalidation plus authoritative macOS discovery. +6. Strict supervisor introspection and bounded supervisor/Git HTTP work. +7. Gateway shutdown log-pump closure handling. + +## Open questions + +None.