git.sandbox
git.sandbox runs a callback in a temporary copy of a repository. It preserves the
live Git index and reconciles formatter changes only when requested. It works in
Git hooks, custom commands, and standalone scripts.
def check(box):
steps.test(
name = "Repository checks",
output = "failures",
fail = {"mode": "wait_all"},
steps = [{"name": "format", "type": "shell", "command": "gofumpt -w ."}],
)
git.sandbox(run = check, scope = "staged", fixes = "unstaged")
Arguments
| Argument | Default | Behavior |
|---|---|---|
run | Required | Callable receiving one sandbox descriptor. |
scope | "staged" | staged, pr, or all. |
base_ref | "origin/main" | Explicit PR comparison base. Missing refs fail; Atmos never fetches them. |
fixes | "none" | none reports changes; unstaged merges them into working files without staging. |
fail_on_changes | True | Fail if tracked sandbox files changed, including when fixes were applied. Use False for a formatting command. |
env | {} | Subprocess environment overrides within the callback. |
path_prepend | [] | Tool directories to prepend to the inherited PATH. Relative paths resolve before entering the sandbox. |
For staged, the checkout contains the caller's index, including the temporary
index used by git commit --only. For pr, the selected files come from the
three-dot diff against base_ref; for all, every indexed file is selected.
Both pr and all inspect current tracked working files, including unstaged edits.
Untracked working files are not copied.
Sandbox descriptor
| Field or method | Purpose |
|---|---|
root | Absolute source repository path. |
path | Absolute temporary checkout path. |
scope | Selected scope. |
base | Resolved PR base commit, or HEAD for staged/all. |
files | Selected repository-relative paths, excluding deletions for staged/pr. |
added | Added paths in the staged index, or PR diff for pr. |
track(paths) | Include additional formatter outputs, such as go.sum, before modifying them. |
copy(paths) | Copy existing regular support files, such as a prebuilt linter, preserving modes and timestamps. Destinations must not exist. These copies are never applied back. |
fs calls, exec.run, exec.which, atmos calls, and nested steps use the sandbox
execution directory. Process settings are scoped to the callback; Atmos does not
change its process-wide directory or environment. Loaded script functions still
resolve load() relative to their source files. Component handles retain their
own component execution context. The env dictionary remains the script's declared
inputs; use env= to override subprocess variables.
Fixes and failures
By default, changes fail the call and leave working files untouched. With
fixes = "unstaged", Atmos merges fixes with existing unstaged edits when possible.
Overlapping or concurrent changes leave the original file untouched and save a
recovery patch with before/after copies. The error names their location.
Checks can fail after making useful fixes: Atmos still reconciles those fixes and
preserves the check failure. Callback defer calls run before reconciliation.
Cancellation prevents reconciliation and removes the temporary checkout. Cleanup
also runs when a check fails. The callback's return value is returned on success.
The sandbox uses private Git metadata and the source repository's object database. It does not register a linked worktree, create branches, stage files, build binaries, or install tools. It supports initial commits and linked worktrees.
Run modifying checks sequentially. Call track before tools create or modify
additional files; only selected and explicitly tracked files are reconciled.
Nested git.sandbox calls are rejected. This is filesystem isolation for cooperating
checks, not a security boundary: scripts and subprocesses can still access absolute
paths outside the temporary checkout.
Related
steps.testfor test progress and failure reporting.fs.write_filewithoverwrite=Truefor atomic transformations.yaml.validatefor syntax-only YAML checks.