Skip to content

fix(sandbox): Daytona DinD denylist overlay, gateway retries and leaked sandboxes - #1123

Open
bingran-you wants to merge 3 commits into
mainfrom
bry/fix-daytona-dind-net-admin-upload
Open

bingran-you wants to merge 3 commits into
mainfrom
bry/fix-daytona-dind-net-admin-upload

Conversation

@bingran-you

@bingran-you bingran-you commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Two Daytona fixes found while running every FrontierPhysics oracle (main 9787d079) on benchflow 0.7.11.

1. Compose tasks with a URL denylist could not start on Daytona

Daytona DinD adds /benchflow/compose/docker-compose-net-admin.yaml to every denylist compose invocation, but it did not upload that bundled overlay into the sandbox. Compose-based denylist tasks failed before their image build with open /benchflow/compose/docker-compose-net-admin.yaml: no such file or directory (present in 0.7.8 through 0.7.11). The overlay is now uploaded with the other bundled compose files. The regression test drives the DinD startup path and checks, at build time, that every referenced compose file has been uploaded. Its second commit stubs the DinD daemon guard (_guard_daemon_from_containers, added to the start path after the test was written); the guard has its own tests in tests/test_sdk_lockdown.py.

2. A gateway error during sandbox creation was not retried and leaked the sandbox

The Daytona SDK creates a sandbox and then waits for it to start inside one create() call. In the sweep, a 502 while refreshing the new sandbox's state raised out of that wait. benchflow got no handle, so the sandbox kept running with nothing able to delete it (found still running after the rollout ended), and the attempt was not retried: 502/503/504 map to DaytonaBadGatewayError / DaytonaServiceUnavailableError in SDK 0.225 and to a status-coded base DaytonaError in 0.184, and neither was transient.

  • 502/503/504 and DaytonaConnectionTimeoutError (0.225's transport timeout) are now transient. The status-code fallback applies only to the base DaytonaError; typed classes go by name.
  • Every sandbox one DaytonaSandbox creates carries a benchflow.create_attempt label. Sandboxes carrying it, other than the one in use, are deleted after a failed or timed-out attempt (shielded and bounded when cancelled), after a retry succeeds (catching a sandbox Daytona committed after its error answer), and in stop(). The lookup and the deletes retry gateway errors. Only that exact label is matched, in the query and again client-side, so other sandboxes on a shared API key are never touched.

Validation at c5e673a3

  • Full suite: 6698 passed, 27 skipped. ruff check and ruff format --check clean.
  • tests/test_daytona_create_cleanup.py (25 tests) passes with the locked Daytona SDK 0.184.0 and with 0.225.0, including a contract test that runs each status through the installed SDK's own error mapping. Nine mutations of the fix (no label, no client-side filter, no post-success, stop, failure or timeout sweep, no lookup retry, no status fallback, no gateway class names) each fail at least one test; against main's code the new tests fail.
  • tests/test_daytona_dind_compose_up.py, test_sandbox_multi_service.py, test_egress_denylist.py, test_network_denylist_config.py, test_sdk_lockdown.py: 234 passed; with daytona_dind.py reverted to main the overlay regression test fails.
  • Native Daytona oracle runs with this branch installed from git (Daytona SDK 0.225.0, no retries or resource/timeout overrides) against FrontierPhysics main 9787d079: ion-trap-3d-vs-2d and twisted-slinky-wave-coupling, which failed on 0.7.11 with the overlay error, both completed with verifier reward 1.0 at 7bd54896. At c5e673a3 the same two tasks and rixs-entanglement-witness (whose first 0.7.11 attempt hit the 502 above) all completed with verifier reward 1.0, and the run left no sandbox behind under its owner label. No gateway error occurred in that run, so the retry and cleanup paths are covered by the unit tests only.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-14T16:52:27.349171Z 96a0a80 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@bingran-you
bingran-you deployed to pypi-internal-preview September 14, 2026 16:51 — with GitHub Actions Active

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

main added _guard_daemon_from_containers to the DinD start path after this test was written; its fake VM exec does not answer the guard, so startup was refused before the uploads were checked. The guard has its own tests in test_sdk_lockdown.py.
@bingran-you
bingran-you force-pushed the bry/fix-daytona-dind-net-admin-upload branch from 96a0a80 to 7bd5489 Compare October 16, 2026 22:31
@bingran-you
bingran-you deployed to pypi-internal-preview October 16, 2026 22:32 — with GitHub Actions Active
…led create left

The Daytona SDK creates a sandbox and then waits for it to start inside one create() call. A 502 while refreshing its state raised out of that wait, so benchflow got no handle: the sandbox kept running with nothing able to delete it, and the attempt was not retried because 502/503/504 were not transient (DaytonaBadGatewayError / DaytonaServiceUnavailableError in newer SDKs, a status-coded base DaytonaError in older ones).

Treat gateway statuses (and DaytonaConnectionTimeoutError) as transient; the status-code fallback applies only to the base class. Every sandbox one DaytonaSandbox creates carries a benchflow.create_attempt label; the sandboxes carrying it, other than the one in use, are deleted after a failed or timed-out attempt (shielded and bounded when cancelled), after a retry succeeds (a sandbox Daytona committed after its error answer), and in stop(). The lookup and deletes retry gateway errors; only that exact label is matched, client-side as well as in the query, so other sandboxes on a shared API key are never touched. Adds CHANGELOG entries for this and the DinD overlay fix.
@bingran-you bingran-you changed the title fix(sandbox): upload denylist compose overlay on Daytona DinD fix(sandbox): Daytona DinD denylist overlay, gateway retries and leaked sandboxes Oct 16, 2026
@bingran-you
bingran-you deployed to pypi-internal-preview October 17, 2026 00:00 — with GitHub Actions Active
@Benjamin-eecs

Copy link
Copy Markdown
Contributor

Evidence for the gateway-retry part, from FrontierPhysics on benchflow 0.7.8: on 2026-10-07 21:30 UTC two GPT-6.1 Sol rollouts (ion-trap-design trial 3, nonlinear-boson-star-sideband-threshold trial 2, 22 s apart) ended with verifier crashed: Failed to get session command: 17 min into test.sh. That is an empty-message DaytonaConnectionTimeoutError from the session-command poll, the class this PR adds to the transient set. Each lost about an hour of agent work, because the cell had to be solved again.

One ask: the two idempotent polls (get_session_command, get_session_command_logs) are still retried 3 times within seconds (_SDK_RETRY). FrontierPhysics-Infra 80a2a0d (bench patch 37) retries those two polls on any transport, timeout, rate-limit or 5xx error (500 included) with about three minutes of backoff in all; a 4xx still fails at once. A longer backoff for those two polls here would let us drop that patch.

On the leak half: a sandbox leaked by a gateway error during create is one of the two leak paths we see. The other, a docker container left by a runner killed with SIGTERM, is #1153.

This branch was successfully deployed

1 active deployment
pypi-internal-preview — c5e673a3 Deployed Oct 17, 2026 by bingran-you via rollout-smoke #1634
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants