Skip to content

Commit 17a22ac

Browse files
committed
sandboxes: document branch-mode in-container clone and source-repo isolation
Update the branch-mode workflow to reflect the move from on-host worktrees to an in-container clone exposed over git-daemon, and add a new source-repository isolation layer to the security model. Highlights the strong guarantee that an unconstrained agent cannot corrupt the host's .git directory or working tree, since the source mount is read-only and the agent operates on a private clone with its own index, refs, and working tree. Tracks docker/sandboxes#2477.
1 parent 305883d commit 17a22ac

4 files changed

Lines changed: 143 additions & 75 deletions

File tree

content/manuals/ai/sandboxes/security/_index.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ and ICMP are blocked at the network layer.
4343

4444
## Isolation layers
4545

46-
The sandbox security model has four layers. See
46+
The sandbox security model has five layers. See
4747
[Isolation layers](isolation/) for technical details on each.
4848

4949
- **Hypervisor isolation:** separate kernel per sandbox. No shared memory or
@@ -52,6 +52,9 @@ The sandbox security model has four layers. See
5252
[Deny-by-default policy](defaults/). Non-HTTP protocols blocked entirely.
5353
- **Docker Engine isolation:** each sandbox has its own Docker Engine with no
5454
path to the host daemon.
55+
- **Source-repository isolation (branch mode):** the agent works on a private
56+
in-VM clone with your `.git` mounted read-only. Even an unconstrained
57+
agent cannot corrupt your host repository.
5558
- **Credential isolation:** API keys are injected into HTTP headers by the
5659
host-side proxy. Credential values never enter the VM.
5760

content/manuals/ai/sandboxes/security/isolation.md

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
---
22
title: Isolation layers
33
weight: 10
4-
description: How Docker Sandboxes isolate AI agents using hypervisor, network, Docker Engine, and credential boundaries.
5-
keywords: docker sandboxes, isolation, hypervisor, network, credentials
4+
description: How Docker Sandboxes isolate AI agents using hypervisor, network, Docker Engine, source-repository, and credential boundaries.
5+
keywords: docker sandboxes, isolation, hypervisor, network, credentials, git
66
---
77

88
{{< summary-bar feature_name="Docker Sandboxes sbx" >}}
99

1010
AI coding agents need to execute code, install packages, and run tools on
11-
your behalf. Docker Sandboxes run each agent in its own microVM with four
12-
isolation layers: hypervisor, network, Docker Engine, and credential proxy.
11+
your behalf. Docker Sandboxes run each agent in its own microVM with five
12+
isolation layers: hypervisor, network, Docker Engine, source-repository
13+
(in branch mode), and credential proxy.
1314

1415
## Hypervisor isolation
1516

@@ -73,6 +74,64 @@ Host system
7374
└── [VM] Containers created by agent
7475
```
7576

77+
## Source-repository isolation
78+
79+
When you start a sandbox with `--branch` (see the
80+
[branch-mode workflow](../usage.md#branch-mode)), the agent never works
81+
directly against your host repository. Even with full root inside the VM,
82+
it cannot corrupt your local Git state.
83+
84+
The boundary works like this:
85+
86+
- Your repository's Git root is bind-mounted into the sandbox at
87+
`/run/sandbox/source` as **read-only**. The agent — and anything it
88+
spawns — cannot write to your `.git` directory, your working tree, or
89+
any tracked file via that mount.
90+
- The agent's working copy is a private `git clone --reference` populated
91+
on the sandbox's overlay filesystem. The clone has its own index, its
92+
own refs, and its own working tree. Object storage is shared via
93+
`.git/objects/info/alternates`, so the clone is space-efficient and
94+
full history is walkable, but writes to the clone never reach your
95+
host's object database.
96+
- Your host pulls the agent's commits over a `git-daemon` exposed by the
97+
sandbox on `127.0.0.1:<ephemeral-port>`. The CLI registers it as a
98+
`sandbox-<sandbox-name>` remote on your host repo. Fetching from that
99+
remote uses the same trust model as fetching from any third-party
100+
remote: nothing is integrated until you explicitly merge or check out
101+
the fetched refs.
102+
103+
```plaintext
104+
Host repository Sandbox VM
105+
.git/ /run/sandbox/source/ (RO bind mount)
106+
objects/ ◄─────── alternates ───────── clone/.git/objects/
107+
refs/ clone/.git/refs/ (private)
108+
HEAD clone/.git/HEAD (private)
109+
working tree clone/working tree (overlay FS)
110+
remote sandbox-<name> ──── git:// ────► git-daemon :9418
111+
(published 127.0.0.1:<ephemeral>)
112+
```
113+
114+
The practical guarantees:
115+
116+
- **Index and ref corruption are impossible.** Concurrent `git` commands
117+
on the host and inside the sandbox can't race on a shared `.git/index`
118+
or shared refs because there is no shared writable state.
119+
- **No write-back to your working tree.** A compromised or buggy agent
120+
can't drop a `.git/hooks/pre-commit`, modify `.github/workflows/`, or
121+
edit any other tracked file in a way that affects your host until you
122+
fetch and merge from the `sandbox-<name>` remote.
123+
- **No access to your `.git/config`.** Credentials, signing keys, and
124+
global settings declared in your repository configuration stay on the
125+
host. The agent's clone has its own configuration.
126+
- **Cleanup is automatic.** `sbx rm` deletes the clone, the published
127+
port, and the `sandbox-<name>` remote on your host. Nothing leaks
128+
outside the sandbox lifecycle.
129+
130+
In direct mode (no `--branch`), the agent edits your working tree directly
131+
and this isolation does not apply. Use branch mode whenever you want a
132+
strong boundary between the agent's Git activity and your host
133+
repository.
134+
76135
## Credential isolation
77136

78137
Most agents need API keys for their model provider. Rather than passing keys

content/manuals/ai/sandboxes/security/workspace.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,16 @@ includes:
3737
3838
## Branch mode
3939

40-
The `--branch` flag lets the agent work on a separate branch. This is a
41-
workflow convenience, not a security boundary: the agent still mounts the full
42-
repository. See the [usage guide](../usage.md) for details.
40+
The `--branch` flag isolates the agent from your host repository: it works
41+
on a private clone inside the sandbox, with your `.git` directory
42+
bind-mounted **read-only** as a reference. This means the agent cannot
43+
modify any tracked file or any byte under `.git/` on your host, no matter
44+
how unconstrained the agent runs. You see the agent's commits only after
45+
explicitly running `git fetch sandbox-<name>`.
46+
47+
See [Source-repository isolation](isolation.md#source-repository-isolation)
48+
for the full boundary, and the [usage guide](../usage.md#branch-mode) for
49+
the workflow.
4350

4451
## Reviewing changes
4552

@@ -52,10 +59,12 @@ With the default direct mount, changes are in your working tree:
5259
$ git diff
5360
```
5461

55-
If you used `--branch`, the agent's changes are on a separate branch:
62+
If you used `--branch`, the agent's changes are on the `sandbox-<name>`
63+
remote until you fetch and merge them:
5664

5765
```console
58-
$ git diff main..my-feature
66+
$ git fetch sandbox-my-sandbox
67+
$ git diff main..sandbox-my-sandbox/my-feature
5968
```
6069

6170
Pay particular attention to:

content/manuals/ai/sandboxes/usage.md

Lines changed: 62 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,29 @@ time, they may step on each other's changes. See
7777

7878
### Branch mode
7979

80-
Pass `--branch <name>` to give the agent its own
81-
[Git worktree](https://git-scm.com/docs/git-worktree) and branch. This
82-
prevents conflicts when multiple agents, or you and an agent, write to the
83-
same files at the same time. You can set `--branch` on `create`, `run`, or
84-
both.
85-
86-
The CLI creates worktrees under `.sbx/` in your repository root. The
87-
worktree is a separate working directory, so the agent doesn't touch your main
88-
working tree. This means:
89-
90-
- The worktree branches off your latest commit when you create it.
91-
Uncommitted changes in your working tree are not included (`sbx` warns you
92-
if it detects any).
93-
- Files you add or change in your main working tree won't be visible to the
94-
agent, and vice versa. The two directories are independent.
80+
Pass `--branch <name>` to give the agent its own branch and an isolated clone
81+
of your repository inside the sandbox. This prevents conflicts when multiple
82+
agents, or you and an agent, write to the same files at the same time. You
83+
can set `--branch` on `create` or, equivalently, on `run` at create time.
84+
85+
When `--branch` is active:
86+
87+
- The agent works on a private clone living entirely inside the sandbox.
88+
Your repository's `.git` directory is bind-mounted **read-only** as a
89+
reference for the clone's object database, so the agent reuses your local
90+
history without consuming extra disk space.
91+
- The CLI creates the new branch on your host repository and checks it out
92+
if your working tree is clean. If it's dirty, the branch ref is still
93+
created but the checkout is skipped with a warning, so your uncommitted
94+
changes are preserved.
95+
- The sandbox runs a `git-daemon` over a `127.0.0.1`-bound ephemeral port
96+
that exports the in-container clone. The CLI registers it as a Git remote
97+
named `sandbox-<sandbox-name>` on your host repository, so you can pull
98+
the agent's commits with `git fetch`.
99+
- The agent's clone has its own index, refs, and working tree. Concurrent
100+
Git operations on the host and inside the sandbox can't corrupt each
101+
other. See [Source-repository isolation](security/isolation.md#source-repository-isolation)
102+
for the security implications.
95103

96104
#### Starting a branch
97105

@@ -105,46 +113,44 @@ Use `--branch auto` to let the CLI generate a branch name for you:
105113
$ sbx run claude --branch auto
106114
```
107115

108-
You can also create the sandbox first and add a branch at run time:
109-
110-
```console
111-
$ sbx create --name my-sandbox claude .
112-
$ sbx run --branch my-feature my-sandbox
113-
```
114-
115-
Or set the branch at create time and reuse it on subsequent runs:
116+
You can also create the sandbox first and attach later:
116117

117118
```console
118119
$ sbx create --name my-sandbox --branch my-feature claude .
119-
$ sbx run my-sandbox # resumes in the my-feature worktree
120-
$ sbx run --branch my-feature my-sandbox # same — reuses the existing worktree
120+
$ sbx run my-sandbox # resumes in the my-feature clone
121121
```
122122

123-
#### Multiple branches per sandbox
124-
125-
You can run multiple worktrees in the same sandbox by passing different branch
126-
names:
127-
128-
```console
129-
$ sbx run --branch feature-a my-sandbox
130-
$ sbx run --branch feature-b my-sandbox
131-
```
123+
> [!NOTE]
124+
> A sandbox is bound to the branch chosen at create time. To work on a
125+
> different branch, create a new sandbox with `sbx create --branch
126+
> other-feature ...`. Running `sbx run --branch ...` on an existing sandbox
127+
> with a different branch is rejected.
132128
133129
#### Reviewing and pushing changes
134130

135-
To review the agent's work, find the worktree with `git worktree list`, then
136-
push or open a PR from there:
131+
The CLI wires the agent's in-container clone as a `sandbox-<sandbox-name>`
132+
Git remote on your host repository. Review the agent's work with the same
133+
commands you'd use for any other remote — no `cd` into a worktree, no extra
134+
tooling:
137135

138136
```console
139-
$ git worktree list # find the worktree path
140-
$ cd .sbx/<sandbox-name>-worktrees/my-feature
141-
$ git log # see what the agent did
137+
$ git fetch sandbox-my-sandbox # pull the agent's commits
138+
$ git log sandbox-my-sandbox/my-feature # see what the agent did
139+
$ git diff main..sandbox-my-sandbox/my-feature # full diff
140+
$ git checkout my-feature && git merge --ff-only \
141+
sandbox-my-sandbox/my-feature # fast-forward your local branch
142142
$ git push -u origin my-feature
143143
$ gh pr create
144144
```
145145

146-
Some agents don't commit automatically and leave changes uncommitted in the
147-
worktree. If that happens, commit from the worktree directory before pushing.
146+
Some agents don't commit automatically. If `git log sandbox-<name>/<branch>`
147+
shows nothing new, open a shell in the sandbox and commit from there before
148+
fetching:
149+
150+
```console
151+
$ sbx exec -it my-sandbox bash
152+
$ git -C $(pwd) commit -am "save work"
153+
```
148154

149155
See [Workspace trust](security/workspace.md) for security considerations when
150156
reviewing agent changes.
@@ -187,31 +193,22 @@ For common signing failures, see
187193

188194
#### Cleanup
189195

190-
`sbx rm` removes the sandbox and all of its worktrees and branches.
191-
192-
#### Ignoring the `.sbx/` directory
193-
194-
Branch mode stores worktrees under `.sbx/` in your repository root. To keep
195-
this directory out of `git status`, add it to your project's `.gitignore`:
196+
`sbx rm` deletes the sandbox, its in-container clone, the published Git
197+
port, and the `sandbox-<sandbox-name>` remote on your host repository. The
198+
local branch the agent worked on stays on your host so you don't lose any
199+
commits you've already fetched.
196200

197-
```console
198-
$ echo '.sbx/' >> .gitignore
199-
```
200-
201-
Or, to ignore it across all repositories, add `.sbx/` to your global gitignore:
202-
203-
```console
204-
$ echo '.sbx/' >> "$(git config --global core.excludesFile)"
205-
```
201+
#### Restrictions
206202

207-
> [!TIP]
208-
> If `git config --global core.excludesFile` is empty, set one first:
209-
> `git config --global core.excludesFile ~/.gitignore`.
203+
A few configurations are incompatible with branch mode and are rejected at
204+
create time:
210205

211-
You can also create Git worktrees yourself and run an agent directly in one,
212-
but the sandbox won't have access to the `.git` directory in the parent
213-
repository. This means the agent can't commit, push, or use Git. `--branch`
214-
solves this by setting up the worktree so that Git works inside the sandbox.
206+
- `--branch` together with `--workspace-volume`: the source-repository
207+
isolation relies on bind-mounting your Git root, which is incompatible
208+
with a volume-backed workspace.
209+
- `--branch` from inside a host Git worktree: the bind mount can't resolve
210+
the worktree's `.git` pointer file. Run `sbx create --branch ...` from
211+
the main repository instead.
215212

216213
## Reconnecting and naming
217214

@@ -250,8 +247,8 @@ $ sbx run claude-my-project
250247

251248
You can mount extra directories into a sandbox alongside the main workspace.
252249
The first path is the primary workspace — the agent starts here, and the
253-
sandbox's Git worktree is created from this directory if you use `--branch`.
254-
Extra workspaces are always mounted directly.
250+
sandbox's branch-mode clone is created from this directory if you use
251+
`--branch`. Extra workspaces are always mounted directly.
255252

256253
All workspaces appear inside the sandbox at their absolute host paths. Append
257254
`:ro` to mount an extra workspace read-only — useful for reference material or

0 commit comments

Comments
 (0)