Repository navigation
Make a local sandbox's commands read no input, end with the command, and keep a bounded tail of valid text - #135
Merged
Conversation
…and keep a bounded tail of valid text A local command inherited this process's stdin, so one that read input hung until its timeout. A job it left in the background held its output open, so a command that had exited timed out. Its output was kept whole, and a byte that wasn't UTF-8 failed a command that had passed. Commands now read from /dev/null. The call ends with the command: Process.wait() also waits for the pipes to close, so the exit is checked for directly, and the pipes are closed a second later, as a remote exec session ending would. Each stream keeps its last 16 MiB, in chunks so memory stays bounded, and decodes with replacement characters. A cancelled command's pipes are closed too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t, and leave the command out of the warning Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Every step that runs a command on a local sandbox goes through
LocalSandbox.exec_with_output:verify_sandboxchecks, setup scripts, builds and copies. That call misbehaved in four ways.Before / after, measured on
mainand on this branch:cat >/dev/null(reads input) while this process's stdin is an open pipe, as in a worker/dev/nullsleep 6 & true(leaves a job in the background)printf '\xff'UnicodeDecodeErrorthough it exited 0�How
All in
local_sandbox.py. Remote providers andexec(), whichcollect_artifactsstreams from, are unchanged.exec()passesstdin=DEVNULL. Nothing in core writes to a sandbox command's stdin.Process.wait()also waits for the command's pipes to close, so the exit is checked for directly whilewait()runs (_exit_code). Output is still read for 1 s after the command ends, and then our ends of its pipes are closed. That is what a remote exec session ending does, and why host installs start their agent withnohup … > log 2>&1 &. A background job still writing to the command's output is cut off with it._Tail). That is above the largest output core reads whole through this call,run_code's 50 MiB result, and a test pins it there. It holds chunks because cutting the front off one growingbytearraykeeps the memory it grew to: 590 MB to hold a 16 MB tail in a micro-benchmark. The warning leaves the command out, since commands can carry secrets.errors="replace"._stopnow waits for the exit the same way and closes the pipes. A cancelled command whose job escaped the kill no longer holds file descriptors, or a 5 s wait.The pipes are closed through
process._transport, since asyncio has no public way to close a subprocess's pipes.Verified
A chaos script ran on macOS and on Linux (
python:3.12-slim), with the process's stdin a held-open pipe. Every check passed on both:wait, each under a timeoutsleep … & true, andsleep … & exit 3yes &writing to the command's outputcat >/dev/nullyesunder a 3 s timeoutprintf 'ok \xff\xfe end'ok �� endrun_coderesult near its limit)read_vm_fileof 50 MiBverify_sandboxstep with the background-job, non-UTF-8, stdin and hang checksUnit tests pass, including new ones for stdin, a background job holding the output, a job cut off with it, decoding, and the tail. The local Docker integration tests (
test_run_docker_container_local.py,test_agent_on_local_sandbox.py) pass on macOS.🤖 Generated with Claude Code

Confidence Score: 5/5
The PR appears safe to merge; both earlier findings are addressed.Summary
Local sandbox commands no longer read the worker’s stdin, and output calls can finish when the command exits even if a background job keeps a pipe open. Each returned stream keeps its last 64 MiB, with invalid UTF-8 bytes replaced when decoded.
Reviews (2) · Last reviewed commit: "Keep 64 MiB of a local command's output,..." · Reviewed by Greptile