feat(sandbox): add offload, matrix and self commands with safety guards - #84
Open
pratikbin wants to merge 3 commits into
Open
feat(sandbox): add offload, matrix and self commands with safety guards#84pratikbin wants to merge 3 commits into
pratikbin wants to merge 3 commits into
Conversation
Introduce `sandbox offload` and `sandbox matrix` subcommands for one‑shot offload and parallel fork workflows. Add `sandbox self` for in‑sandbox signaling. Implement guards, retry logic, and improved error handling for lifecycle, connection setup, and disk operations.
fork --count was checked after resolving the source ref, so an invalid count still paid for an API lookup before failing. Move the check to the top of runFork. Unknown command names (root or nested) printed a suggestion but exited 0: urfave's CommandNotFoundFunc has no return value, so ShowCommandHelp always returns nil after calling it. Root's own custom Action also never reached that path at all, since urfave only falls back to CommandNotFoundFunc through its default help Action. Detect the unresolved name directly in each command's own Action instead, and return a real error so app.Run (and main.go's exit code) see the failure. Claude-Session: https://claude.ai/code/session_019J9PwFePTzAhpPs1TY9ZGq
Go's stdlib flag parsing stops at the first positional argument, so a command like `fork <sandbox> --count 2` left `--count` unparsed and defaulted to 1. Added `forkCountFlag` that falls back to scanning raw os.Args, restoring the intended count.
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.
Summary
Three new capabilities for driving a fleet of sandboxes from the CLI:
sandbox offload <dir> -- <cmd>— stage a directory, run one command, fetch results, destroy the sandbox..gitignore-aware staging,--egress-preset,--fetch,--keep-on-fail.sandbox matrix <dir>— build one golden sandbox, run--prepareonce, fork it N times, run one job per clone in parallel, report per-job exit codes.--fromreuses an existing paused sandbox instead of building one.sandbox self pause|delete— a workload ends its own sandbox from the inside, over the loopback-only guest agent (127.0.0.1:1029). No credential needed or present.sandbox fork --count N— direct N-way cloning of one snapshot.Fixes found and verified along the way
Each of these was confirmed against a live account, not just unit-tested:
pause/resumefailing with "Content-Length is required" —lifecyclePOSTsent a body-less POST; control's forwarder strips the client'sContent-Lengthheader, and a nil body makes Go emit none at all.forkalways had a body and never hit this. Now sends{}.forkissued right afterpausehit "sandbox is running, expected paused or error" because pause is async. Now waits forpausedfirst.s-1vcpu-1gb/auto_pause=900golden box produced as-4vcpu-4gb/auto_pause=Noneclone.matrixnow re-applies the auto-pause backstop to every clone.coverage -> /etc+ entrycoverage/passwdescapes it). Replaced withos.Root, which resolves through an open directory descriptor and cannot be defeated by a symlink.CreateSandbox/ForkSandboxsucceeding thenwaitForStatusfailing left an untracked, running sandbox. Both paths now destroy the sandbox and name its id in the error.offloadexited 0 after a failed teardown — a CI job reading only the exit code would call this a clean run while a sandbox kept billing. Teardown failure now fails the command.forksilently paused a running source —createos sandbox fork my-live-serverwould pause whatever it was serving with no prompt. Now refused; onlymatrix's own golden box (which it created) is paused automatically.push/pullnow refuse this, and fail closed (refuse, not allow) if the disk list itself cannot be read.-o jsonafter a subcommand silently failing ("flag provided but not defined") —OnUsageErroris not inherited from the app in urfave/cli v2, so it has to be set on every command node. Fixed, and the error now shows the corrected command line. Unknown (sub)commands now suggest the nearest real one via edit distance.Test plan
gofmt -lclean,golangci-lint run ./...0 issues,go test ./...passesoffloadend to end (staged 4 files / 5.0 kB, excluded a 200 kBnode_modulesvia.gitignore, 2.1s total)matrix— 3 forked clones, correct per-job exit codes (0, 0, 3),--prepareoutput identical (same nanosecond timestamp + PID) across all three clones, auto-pause backstop confirmed on every clonesandbox self pausefrom inside a real sandbox withls ~/.createos→ no such file (zero credential on disk), sandbox verifiedpausedafterwardsandbox forkon a running sandbox refuses and leaves itrunning