Repository navigation
Codex-generated test harness leaked unbounded Docker/Xcode resources without post-run verification #33707
Description
What version of Codex was running?
The harness was generated during a codex-tui session on the 0.144.0 line. The current installed binary is codex-cli 0.144.5.
Which model was being used?
gpt-5.6-sol, reasoning effort ultra.
What platform was the computer using?
macOS 26.4 (25E246), arm64, with Docker Desktop and Xcode/iOS Simulator.
What issue occurred?
Codex designed and committed an iOS E2E/fault-test harness that created unbounded external resources and then repeatedly ran it without verifying resource cleanup.
The generated harness used:
- a unique Docker Compose project name for every fault scenario/run
docker compose down --remove-orphans, but no removal of project-local images- a new DerivedData path and
.xcresultbundle for each run - no retention policy for DerivedData or result bundles
- simulators that could be booted for a run but were not shut down afterward
- shared/global BuildKit cache with no run ownership or bound
- traps for the immediate shell, but no stale-run reaper for crashes/SIGKILL
- no post-run assertion that Docker/Xcode/simulator resource usage returned to baseline
This was not primarily an interrupt/cancellation failure. The resources accumulated after successful runs because the generated harness itself had incomplete lifecycle semantics.
After many E2E runs:
- the host had about 191 MB free
- Docker Desktop's physical
Docker.rawusage was about 227 GB - Docker Desktop crashed with
no space left on device - Xcode showed many retained test/run entries
- DerivedData, result bundles, project-local images, BuildKit cache, and simulator state had accumulated
After safely pruning only unused Docker data and repairing the harness (without removing Docker volumes), the host recovered more than 200 GB and Docker physical usage dropped to roughly 51 GB.
Reproduction pattern
This is a model/agent behavior reproduction rather than a deterministic CLI command:
- Ask Codex to build a comprehensive iOS E2E matrix with Docker Compose-based transport-fault services and Xcode result bundles.
- Let Codex design the runner and execute it repeatedly across multiple scenarios/devices.
- Inspect the generated lifecycle code.
- Run the suite repeatedly and compare:
- Docker images, containers, builders, and build cache
- DerivedData and
.xcresultdirectories - booted simulators
- free host disk
- Observe that immediate containers are stopped, but run-owned images, cache, Xcode artifacts, and simulator state remain and grow without a bound.
Representative generated patterns were equivalent to:
compose_project="...-${run_id}-${label}-$$"
derived_data=".../${run_id}/${label}"
result_bundle=".../${run_id}/${label}/result.xcresult"
docker compose --project-name "$compose_project" up -d --build
# ...
docker compose --project-name "$compose_project" down --remove-orphansStopping the Compose project did not remove the uniquely named project image, and neither artifact path had retention.
What was expected?
When Codex generates and executes test infrastructure, it should treat every external resource it creates as owned state and verify a bounded lifecycle:
- cleanup on success, failure, and catchable signals
- explicit ownership markers
- stale-run recovery for crashes or SIGKILL
- bounded artifact retention
- cleanup of run-owned images/builders/cache without touching user volumes
- simulator shutdown when the runner booted it
- a post-run resource-delta check before reporting the task complete
The agent should not need to globally prune Docker or delete arbitrary Xcode data. It should generate scoped cleanup for resources it owns.
Why this appears to be an agent-quality issue
The CLI executed the generated scripts as written. It cannot safely infer that an arbitrary Docker image, simulator, or Xcode artifact is disposable. The defect was that Codex generated infrastructure with incomplete ownership and cleanup semantics, repeatedly ran it, and declared the work complete without checking the machine-level resource delta.
This therefore appears to be a model/agent planning and verification gap rather than primarily a shell process-tree bug.
Remediation applied locally
The repaired harness now includes:
- active-run markers and stale-run reaping
- run-owned DerivedData cleanup
- bounded result retention
- simulator shutdown only when the runner booted it
- Compose cleanup with run-owned local image removal
- a run-owned Buildx builder with a pinned BuildKit version and memory limit
- removal of the run-owned builder/state after the run
- explicit protection of Docker volumes
A useful regression/evaluation would ask the model to generate a multi-run Docker/Xcode test harness, run it several times, and assert that all created external resources are either removed or retained under a documented bound.
Activity
runminglu commentedon Jul 16, 2026
Successful mitigation and recovery approach
The prompt that successfully initiated recovery was:
Codex was able to diagnose and repair the problem when explicitly asked to investigate the machine-level resource leak, rather than only fix a failing test. The effective workflow was:
1. Measure before deleting anything
Codex inspected:
Docker.rawusage.xcresultdirectoriesThe important step was correlating run IDs, Compose project names, artifact paths, and simulator state back to the generated harness. This separated runner-owned resources from unrelated user resources.
2. Recover capacity with ownership-scoped cleanup
The recovery removed only unused or clearly runner-owned data:
Docker volumes were explicitly protected. The recovery did not use
docker compose down -vordocker volume rm, because the application's SQLite database and uploads live in a Docker volume.This restored more than 200 GB of host capacity and reduced Docker's physical disk usage from roughly 227 GB to roughly 51 GB.
3. Encode lifecycle ownership into the harness
The repair added:
--rmi localfor run-owned project imagesThe key invariant was: every external resource created by the runner must either be removed at completion or retained under a documented bound.
4. Verify cleanup, including interruption paths
Codex verified the fix with:
The task was considered complete only after a run returned the machine to the expected bounded baseline.
Suggested Codex behavior/evaluation
For tasks that generate Docker, simulator, browser, database, VM, or test artifacts, Codex should automatically include a resource-lifecycle review:
This incident shows that Codex can successfully repair this class of problem once the prompt explicitly frames it as a machine-level resource leak. The improvement would be to make that lifecycle analysis part of the default design and verification behavior when Codex creates the harness in the first place.