Label and time-bound the sandbox helper containers — a hung clone or a crash mid-checkout orphans networked containers prune cannot reclaim
Severity: medium | Confidence: 0.72 | Effort: M
Where:
plugins/ca-sandbox/tools/create.ts:158-210, 220-266, 376-391
plugins/ca-sandbox/tools/destroy.ts:100-123
Evidence: The throwaway clone container (buildCloneArgs, create.ts:194-210) and the docker-cp helper (ca-sbx-cp-<id>, create.ts:227-247) carry no ca.sandbox label — by design they are "not a sandbox object" — and spawnAsync/spawnSync impose no timeout. A clone that hangs (dead remote, giant repo) leaves a networked, unlabeled container running indefinitely; a host-process crash between docker create and the finally-block docker rm -f (create.ts:263) leaks the helper. prune() sweeps only ca.sandbox=1 objects (destroy.ts:107-122), so neither orphan is reclaimable by the documented AC-11 sweep. The createSandbox failure teardown also removes the volume before the leftover-container sweep (create.ts:378-388), so volume rm -f fails while a labeled container still holds it and is never retried.
Impact: The lifecycle guarantee ("a failed create never leaks"; "prune reclaims every object") has two escape hatches: unbounded/unlabeled helper containers (the clone one with network egress up) and an unretried in-use volume. Orphans accumulate invisibly across failed creates.
Recommendation: Label the clone and cp-helper containers with ca.sandbox=1 + the id (they are ephemeral either way, and the label makes prune authoritative); add a wall-clock timeout to the clone and cp steps; in the createSandbox catch, remove containers first, then the volume (matching destroySandbox's order).
Acceptance criteria:
- Killing the host process mid-clone leaves an object that
prune() reclaims (docker-gated test)
- createSandbox failure with a started container removes both the container and the volume in one pass
Label and time-bound the sandbox helper containers — a hung clone or a crash mid-checkout orphans networked containers prune cannot reclaim
Severity: medium | Confidence: 0.72 | Effort: M
Where:
plugins/ca-sandbox/tools/create.ts:158-210, 220-266, 376-391
plugins/ca-sandbox/tools/destroy.ts:100-123
Evidence: The throwaway clone container (buildCloneArgs, create.ts:194-210) and the docker-cp helper (
ca-sbx-cp-<id>, create.ts:227-247) carry no ca.sandbox label — by design they are "not a sandbox object" — and spawnAsync/spawnSync impose no timeout. A clone that hangs (dead remote, giant repo) leaves a networked, unlabeled container running indefinitely; a host-process crash betweendocker createand the finally-blockdocker rm -f(create.ts:263) leaks the helper. prune() sweeps onlyca.sandbox=1objects (destroy.ts:107-122), so neither orphan is reclaimable by the documented AC-11 sweep. The createSandbox failure teardown also removes the volume before the leftover-container sweep (create.ts:378-388), sovolume rm -ffails while a labeled container still holds it and is never retried.Impact: The lifecycle guarantee ("a failed create never leaks"; "prune reclaims every object") has two escape hatches: unbounded/unlabeled helper containers (the clone one with network egress up) and an unretried in-use volume. Orphans accumulate invisibly across failed creates.
Recommendation: Label the clone and cp-helper containers with ca.sandbox=1 + the id (they are ephemeral either way, and the label makes prune authoritative); add a wall-clock timeout to the clone and cp steps; in the createSandbox catch, remove containers first, then the volume (matching destroySandbox's order).
Acceptance criteria:
prune()reclaims (docker-gated test)