feat(sandbox): add Apple Container backend for macOS Virtualization.framework - #936
Conversation
…ramework Adds a new sandbox backend (`--sandbox apple-container`) that runs tasks in Apple Container micro-VMs via the system `container` CLI. Enables macOS users to run BenchFlow evaluations natively without Docker Desktop. Key design decisions: - Background `container run` + `container exec` per command (mirrors Docker) - `-i` flag for stdin passthrough (upload_file) - kalloc zone headroom check as preflight + per-start gate - arm64-only, fail closed on amd64 Dockerfiles - virtiofs bind mounts for zero-copy file transfer on mounted paths - base64-over-exec fallback for unmounted paths - off_box_model=False (VM reaches host via gateway 192.168.64.1) All Phase 0 probes confirmed empirically (2026-07-24): - container exec: basic, cwd, concurrent, stdout/stderr separation - Host networking via gateway IP (curl 200 OK) - useradd/su on virtiofs - Multi-stage Dockerfile builds - 60s background stability - stdin piping with -i flag
virtiofs mount points don't support chmod, but subdirectories inside a mount do. Mounting rollout_dir as /logs (with verifier/, agent/, artifacts/ as regular dirs inside) fixes permission errors when the verifier writes reward.txt. E2E validated: bench eval run --tasks-dir tasks/sales-pivot-analysis --agent oracle --sandbox apple-container → reward=1.0 in 1.1min.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
Auto-fixed by `ruff check --fix` and `ruff format` to match CI's lint and format gates.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
bingran-you
left a comment
There was a problem hiding this comment.
Daily scan thermo-nuclear review (2026-07-25): requesting changes on current head f8ac25cc3754bb823b284936d181d618b7fa04d9.
High-confidence blockers:
-
src/benchflow/sandbox/apple_container.py:223mounts the taskenvironment_dirdirectly over/appas a writable host bind mount. That changes the core Docker/Daytona semantics:/appis no longer the image filesystem produced by the Dockerfile, and agent writes can mutate the repo/task environment on the host across trials. This needs a per-rollout staged workspace or another design that does not overwrite image state and does not let the agent write back into source task files. -
src/benchflow/sandbox/apple_container.py:196buildscontainer runwithout honoringtask_env_config.allow_internet/environment.network_mode=no-network. Other backends enforce this contract (Docker adds the no-network compose overlay; Modal/Daytona block network). As written, no-network tasks silently run with public network in the new backend. -
src/benchflow/sandbox/apple_container.py:509maps/logsand/apppaths back to host paths using string-prefix checks andhost_base / relwithout normalizing/rejecting... A path like/logs/../../...can escape the rollout bind root in the host-copy fast path. The host-side mount optimization needs a strict POSIX-path boundary check before anyshutil.copy*/rmtree. -
src/benchflow/sandbox/apple_container.py:29parses the samplezprintcolumns incorrectly: the test itself labelsparts[4]aselemsandparts[6]asmaxelts, but the implementation returnsparts[6]as current usage. That makes the kalloc preflight/headroom gate unreliable.
Validation gates from local checkout:
uv sync --extra dev --lockedon a pristine PR worktree fails becauseuv.lockneeds updating after addingsandbox-apple-container.- After uv updates the local lock metadata,
uv run --extra dev ty check srcfails atsrc/benchflow/sandbox/apple_container.py:491because_log_file: object | Nonehas no typed.close(). - Focused PR tests passed only after local lock metadata was updated:
tests/test_apple_container_sandbox.py tests/test_sandbox_provider_registry_drift.py-> 33 passed, 1 skipped. - Live GitHub currently reports no checks on this PR.
Label sync: I added enhancement, P1, status:blocked, review:changes-requested, and area:sandbox. This should not be merged until the sandbox contract and CI/type/lock gates are fixed.
AI-generated automation review posted on behalf of Bingran You.
|
Users Simulation automation review (2026-07-25): blocked on current head User-simulation gates:
Thermo/sandbox blockers from review still apply: writable host bind over Labels are already correct: keep AI-generated automation review posted on behalf of Bingran You. |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Users Simulation automation follow-up (2026-07-25): pushed Fixed in this commit:
Validation on the pushed code:
Labels intentionally stay AI-generated automation follow-up posted on behalf of Bingran You. |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Users Simulation automation final-head follow-up (2026-07-25): final pushed head is After the code-fix commit The validation evidence remains:
Labels intentionally remain AI-generated automation follow-up posted on behalf of Bingran You. |
Re-review request: all 4 blockers resolved, independently validatedAll issues from the thermo-nuclear review on Blocker Resolution
Auxiliary fixes:
Independent Validation (2026-07-25, M2 Mac, head
|
bingran-you
left a comment
There was a problem hiding this comment.
Daily scan re-review (2026-07-26) on current head 4c2dd37128e40cf7e8e3946ae3a31a0fde53d9e7.
I rechecked the final head in a fresh detached worktree. The concrete blockers from the earlier f8ac25c review are no longer reproduced in this local slice: the branch no longer bind-mounts /app, no-network tasks fail closed, /logs host-copy paths now use containment checks, zprint parsing reads the elems column, _log_file is typed, and the lock metadata is present.
Fresh local validation from this scan:
uv sync --extra dev --extra sandbox-daytona --locked-> passeduv run --extra dev python -m pytest tests/test_apple_container_sandbox.py tests/test_sandbox_provider_registry_drift.py tests/test_runtime_capabilities.py -q-> 66 passed, 1 skipped- changed-file
ruff check-> passed uv run --extra dev ty check src-> passedgit diff --check origin/main...HEAD-> passed
I am not clearing the merge gate from automation: live GitHub still has no check-run/status rollup for this PR head, the old formal CHANGES_REQUESTED state is still active, and I did not run the real macOS Apple Container lifecycle/E2E test from this machine. Labels should stay status:blocked + review:changes-requested until workflow approval/CI evidence and human re-review land.
AI-generated automation re-review posted on behalf of Bingran You.
|
Users Simulation current-head follow-up for Verdict: still blocked. What passed:
Current blockers:
Labels look correct as-is: keep This comment was generated by an AI agent on behalf of Bingran You. |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Users Simulation current-head follow-up for Pushed Fixed in this commit:
Validation on the pushed code:
Still blocked:
Labels intentionally remain AI-generated automation follow-up posted on behalf of Bingran You. |
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Thermo/end-to-end follow-up for current head All repo-owned blockers are fixed on this head:
Exact-head local acceptance:
The PR description now reflects the actual implementation and supported scope. This comment was generated by an AI agent on behalf of Bingran You. |
bingran-you
left a comment
There was a problem hiding this comment.
Approved on current head d6d9d42897c75e9e7fe870dd0ecf236385e73096.
The requested sandbox, isolation, secret-handling, proxy-placement, lifecycle,
file-transfer, resource-safety, dependency-audit, and parity blockers are
resolved. Real Apple Container and Docker task runs passed with healthy
artifacts, and all current-head GitHub checks are green.
|
@explicitcontextualunderstanding thank you for contributing the Apple Container |
feat(sandbox): add Apple Container backend for macOS Virtualization.framework
What this solves
BenchFlow users on Apple Silicon can run public-network, single-container arm64
tasks locally with Apple's Virtualization.framework backend instead of Docker
Desktop or a cloud sandbox:
bench eval run ... --sandbox apple-containerThe backend requires Apple Container 1.1+ and intentionally fails closed for
unsupported hosts,
no-networktasks, multi-service tasks, unsafe kernel-zoneheadroom, and snapshot workflows.
Implementation
container run --detachcontainer exec --interactive --user/--workdircontainer cpbuild/run --platform linux/arm64receive an unreachable host-loopback endpoint.
container exec --interactive;Apple Container no longer falls through to Daytona internals.
environment.docker_imagewins unlessforce_build=True./logsas the only host bind mount. Task, verifier, oracle, and skillscontent is copied through the native CLI, so the VM cannot mutate source files.
through stdin and deleting them before agent execution.
zprint -H -L data.kalloc.1024schema correctly, failsclosed when it cannot verify usage, and serializes Apple rollouts within each
BenchFlow process.
sandbox-apple-containerpackage extra and the stalePR-only design document.
mcpfrom 1.27.2 to 1.28.1, fixing the current CI dependency advisory.Supported scope
The
data.kalloc.1024leak is system-wide, so concurrent BenchFlow processes arestill discouraged. Docker, Daytona, or Modal remain the supported backends for
no-network, multi-service, snapshot, and high-concurrency runs.Exact-head validation
Current head:
d6d9d42897c75e9e7fe870dd0ecf236385e73096Real Apple Container lifecycle
nested-directory transfer: passed
test_real_apple_container_lifecycle_and_copy: 1 passedReal BenchFlow evaluations
citation-check, Apple Container: reward 1.0, 1/1, zero errorspi-acp+ Azure OpenAIgpt-5.5+xhigh, no-skill, Apple Container:reward 1.0, 1/1, zero errors, 10 tool calls
reward 1.0, 1/1, zero errors, 6 tool calls; validator healthy with
7/7 successful exchanges and 65,144 provider-accounted tokens
reasoning_effort=xhighRepository gates
uv sync --extra dev --extra sandbox-daytona --extra sandbox-modal --lockeduv run ruff check .uv run ruff format --check src testsuv run ty check src/uv lock --checkgit diff --checkpip-audit: No known vulnerabilities foundRemaining merge gates
integration-light, and integration-scope.
CHANGES_REQUESTEDstate; this is the only remaining merge gate.