Skip to content

Commit 3ffce2a

Browse files
ndeloofdvdksn
authored andcommitted
sandboxes: document --clone, in-container clone and source-repository isolation
Replaces the `--branch[=NAME]` documentation with `--clone` (boolean) on both `sbx create` and `sbx run`, matching the CLI rename in docker/sandboxes#3055. Clone mode is now strictly about running the agent on a private in-container `git clone --reference` of the host repository; no host-side branch is created on the user's behalf — the user instructs the agent to `git checkout -b ...` inside the sandbox if a dedicated working branch is needed. Key documentation changes: - usage.md: "Branch mode" section is renamed to "Clone mode" and rewritten end-to-end. Drops the `.sbx/<name>-worktrees/...` directory mention (no longer created), the host-side branch creation/checkout step, the `--branch=auto` flow, and the legacy "Multiple branches per sandbox" section. Adds: * an explicit note that clone mode is fixed at create time; * the forge-remote propagation behaviour (origin/upstream propagated from host into the in-container clone, local-path remotes skipped); * a Cleanup warning about lost in-container commits when running `sbx rm` (mirrors the runtime warning). - security/isolation.md: adds the "Source-repository isolation" section introduced in docker#25007. Same content, but uses `--clone` and "clone mode" terminology throughout, plus a clarifying note that `sbx rm` warns before dropping unfetched/unpushed commits. - security/workspace.md: the existing "Branch mode" stub (claiming the old `--branch` was a "workflow convenience, not a security boundary") is replaced with a "Clone mode" section that explicitly calls out the isolation guarantee — clone mode IS a security boundary, the host's `.git` cannot be touched. - security/_index.md: source-repository isolation is added to the five-layer model (was four). Wording aligned with isolation.md. Migration: callers that scripted `sbx create --branch=feature/x` now pass `--clone` and tell the agent to create the branch. This PR is an alternative to docker#25007, written against the post-rename CLI. Signed-off-by: Nicolas De loof <nicolas.deloof@gmail.com>
1 parent d95336d commit 3ffce2a

4 files changed

Lines changed: 177 additions & 91 deletions

File tree

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

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

4242
## Isolation layers
4343

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

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

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

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
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
AI coding agents need to execute code, install packages, and run tools on
9-
your behalf. Docker Sandboxes run each agent in its own microVM with four
10-
isolation layers: hypervisor, network, Docker Engine, and credential proxy.
9+
your behalf. Docker Sandboxes run each agent in its own microVM with five
10+
isolation layers: hypervisor, network, Docker Engine, source-repository
11+
(in clone mode), and credential proxy.
1112

1213
## Hypervisor isolation
1314

@@ -71,6 +72,65 @@ Host system
7172
└── [VM] Containers created by agent
7273
```
7374

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

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

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

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,18 @@ includes:
3333
> building, or opening the project in an IDE. Review these files after any agent
3434
> session before performing those actions.
3535
36-
## Branch mode
36+
## Clone mode
3737

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

4249
## Reviewing changes
4350

@@ -50,10 +57,12 @@ With the default direct mount, changes are in your working tree:
5057
$ git diff
5158
```
5259

53-
If you used `--branch`, the agent's changes are on a separate branch:
60+
If you used `--clone`, the agent's changes are on the `sandbox-<name>`
61+
remote until you fetch and merge them:
5462

5563
```console
56-
$ git diff main..my-feature
64+
$ git fetch sandbox-my-sandbox
65+
$ git diff main..sandbox-my-sandbox/<branch-the-agent-used>
5766
```
5867

5968
Pay particular attention to:

content/manuals/ai/sandboxes/usage.md

Lines changed: 94 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -77,117 +77,131 @@ When your workspace is a Git repository, the agent edits your working tree
7777
directly by default. Changes appear in your working tree immediately, the same
7878
as working in a normal terminal.
7979

80-
If you run multiple agents on the same repository at once, use [branch
81-
mode](#branch-mode) to give each agent its own branch and working directory.
80+
If you want the agent to work in isolation from your host repository — for
81+
example to run multiple agents in parallel, or to prevent any chance of an
82+
agent rewriting your local Git state — use [clone mode](#clone-mode). The
83+
agent runs against a private Git clone inside the sandbox; your host repository
84+
sees the agent's commits only after you explicitly fetch them.
8285

8386
### Direct mode (default)
8487

8588
The agent edits your working tree directly. Stage, commit, and push as you
8689
normally would. If you run multiple agents on the same repository at the same
8790
time, they may step on each other's changes. See
88-
[branch mode](#branch-mode) for an alternative.
89-
90-
### Branch mode
91-
92-
Pass `--branch <name>` to give the agent its own
93-
[Git worktree](https://git-scm.com/docs/git-worktree) and branch. This
94-
prevents conflicts when multiple agents, or you and an agent, write to the
95-
same files at the same time. You can set `--branch` on `create`, `run`, or
96-
both.
97-
98-
The CLI creates worktrees under `.sbx/` in your repository root. The
99-
worktree is a separate working directory, so the agent doesn't touch your main
100-
working tree. This means:
101-
102-
- The worktree branches off your latest commit when you create it.
103-
Uncommitted changes in your working tree are not included (`sbx` warns you
104-
if it detects any).
105-
- Files you add or change in your main working tree won't be visible to the
106-
agent, and vice versa. The two directories are independent.
107-
108-
#### Starting a branch
91+
[clone mode](#clone-mode) for an alternative.
92+
93+
### Clone mode
94+
95+
Pass `--clone` to run the agent on a private Git clone living entirely
96+
inside the sandbox, instead of bind-mounting your working tree. Your host
97+
repository is mounted read-only as the clone's reference, so the agent — even
98+
with full root inside the VM — cannot modify any byte of your `.git`
99+
directory or working tree. You can set `--clone` on `create` or, equivalently,
100+
on `run` at create time.
101+
102+
When `--clone` is active:
103+
104+
- The agent works on a private clone populated by
105+
`git clone --reference` from your repository, on the sandbox's overlay
106+
filesystem. The clone has its own index, refs, and working tree.
107+
Object storage is shared via `.git/objects/info/alternates`, so the
108+
clone is space-efficient and full history is walkable, but writes to
109+
the clone never reach your host's object database.
110+
- Your repository's Git root is bind-mounted at `/run/sandbox/source` as a
111+
read-only mount. The agent's `git clone --reference` reads from this
112+
mount; nothing on the host is writable from inside the sandbox.
113+
- The clone follows whatever HEAD your host repository is on at create time.
114+
No branch is created automatically — if you want the agent to work on a
115+
dedicated branch, instruct the agent to `git checkout -b my-feature`
116+
inside the sandbox before it starts editing.
117+
- The sandbox runs a `git-daemon` over a `127.0.0.1`-bound ephemeral port
118+
that exports the in-container clone. The CLI registers it as a Git remote
119+
named `sandbox-<sandbox-name>` on your host repository, so you can pull
120+
the agent's commits with `git fetch`.
121+
- Forge remotes you have on the host (`origin`, `upstream`, …) are
122+
propagated into the in-container clone with their existing URLs, so the
123+
agent can `git push origin …` to your GitHub fork as you would on the
124+
host. Local-path remotes (`file://`, paths) are skipped because they
125+
aren't reachable from inside the sandbox.
126+
127+
See [Source-repository isolation](security/isolation.md#source-repository-isolation)
128+
for the security boundary.
129+
130+
#### Starting a sandbox in clone mode
109131

110132
```console
111-
$ sbx run claude --branch my-feature # agent works on the my-feature branch
133+
$ sbx run --clone claude # private clone of the current repository
112134
```
113135

114-
Use `--branch auto` to let the CLI generate a branch name for you:
136+
You can also create the sandbox first and attach later:
115137

116138
```console
117-
$ sbx run claude --branch auto
139+
$ sbx create --clone --name my-sandbox claude .
140+
$ sbx run my-sandbox # resumes in the in-container clone
118141
```
119142

120-
You can also create the sandbox first and add a branch at run time:
143+
> [!NOTE]
144+
> Clone mode is fixed at create time. Recreate the sandbox with
145+
> `sbx create --clone ...` to switch an existing sandbox into clone mode.
121146
122-
```console
123-
$ sbx create --name my-sandbox claude .
124-
$ sbx run --branch my-feature my-sandbox
125-
```
126-
127-
Or set the branch at create time and reuse it on subsequent runs:
128-
129-
```console
130-
$ sbx create --name my-sandbox --branch my-feature claude .
131-
$ sbx run my-sandbox # resumes in the my-feature worktree
132-
$ sbx run --branch my-feature my-sandbox # same — reuses the existing worktree
133-
```
134-
135-
#### Multiple branches per sandbox
147+
#### Reviewing and pushing changes
136148

137-
You can run multiple worktrees in the same sandbox by passing different branch
138-
names:
149+
The CLI wires the agent's in-container clone as a `sandbox-<sandbox-name>`
150+
Git remote on your host repository. Review the agent's work with the same
151+
commands you'd use for any other remote — no extra tooling, no `cd` into
152+
a separate directory:
139153

140154
```console
141-
$ sbx run --branch feature-a my-sandbox
142-
$ sbx run --branch feature-b my-sandbox
155+
$ git fetch sandbox-my-sandbox # pull the agent's commits
156+
$ git log sandbox-my-sandbox/<branch-the-agent-used> # see what the agent did
157+
$ git diff main..sandbox-my-sandbox/<branch-the-agent-used>
158+
$ git checkout -b my-feature sandbox-my-sandbox/<branch-the-agent-used>
159+
$ git push -u origin my-feature
160+
$ gh pr create
143161
```
144162

145-
#### Reviewing and pushing changes
163+
If the agent committed on a dedicated branch (because you asked it to
164+
`git checkout -b ...`), that branch name appears on the `sandbox-<name>`
165+
remote. If it stayed on the HEAD it inherited at create time, its commits
166+
extend that branch instead — you'll see them by fetching and diffing.
146167

147-
To review the agent's work, find the worktree with `git worktree list`, then
148-
push or open a PR from there:
168+
Some agents don't commit automatically. If `git log sandbox-<name>/...`
169+
shows nothing new, open a shell in the sandbox and commit from there
170+
before fetching. `sbx exec` drops you into the in-container clone:
149171

150172
```console
151-
$ git worktree list # find the worktree path
152-
$ cd .sbx/<sandbox-name>-worktrees/my-feature
153-
$ git log # see what the agent did
154-
$ git push -u origin my-feature
155-
$ gh pr create
173+
$ sbx exec -it my-sandbox bash
174+
$ git commit -am "save work"
156175
```
157176

158-
Some agents don't commit automatically and leave changes uncommitted in the
159-
worktree. If that happens, commit from the worktree directory before pushing.
160-
161177
See [Workspace trust](security/workspace.md) for security considerations when
162178
reviewing agent changes.
163179

164180
#### Cleanup
165181

166-
`sbx rm` removes the sandbox and all of its worktrees and branches.
167-
168-
#### Ignoring the `.sbx/` directory
182+
`sbx rm` deletes the sandbox, its in-container clone, the published Git
183+
port, and the `sandbox-<sandbox-name>` remote on your host repository.
169184

170-
Branch mode stores worktrees under `.sbx/` in your repository root. To keep
171-
this directory out of `git status`, add it to your project's `.gitignore`:
185+
> [!WARNING]
186+
> Any commits the agent made inside the sandbox that you have not yet
187+
> fetched (via `git fetch sandbox-<name>`) or pushed to an upstream
188+
> remote will be lost — the in-container clone lives on the sandbox's
189+
> overlay filesystem and is dropped with it. `sbx rm` prints a warning
190+
> for clone-mode sandboxes; review it before confirming the removal.
172191
173-
```console
174-
$ echo '.sbx/' >> .gitignore
175-
```
176-
177-
Or, to ignore it across all repositories, add `.sbx/` to your global gitignore:
178-
179-
```console
180-
$ echo '.sbx/' >> "$(git config --global core.excludesFile)"
181-
```
192+
#### Restrictions
182193

183-
> [!TIP]
184-
> If `git config --global core.excludesFile` is empty, set one first:
185-
> `git config --global core.excludesFile ~/.gitignore`.
194+
A few configurations are incompatible with clone mode and are rejected at
195+
create time:
186196

187-
You can also create Git worktrees yourself and run an agent directly in one,
188-
but the sandbox won't have access to the `.git` directory in the parent
189-
repository. This means the agent can't commit, push, or use Git. `--branch`
190-
solves this by setting up the worktree so that Git works inside the sandbox.
197+
- `--clone` together with `--workspace-volume`: the source-repository
198+
isolation relies on bind-mounting your Git root, which is incompatible
199+
with a volume-backed workspace.
200+
- `--clone` from inside a host Git worktree: the bind mount can't resolve
201+
the worktree's `.git` pointer file. Run `sbx create --clone ...` from
202+
the main repository instead.
203+
- `--clone` on a non-Git workspace: clone mode requires a Git repository.
204+
Run `sbx create` without `--clone` for non-Git workspaces.
191205

192206
### Signed commits
193207

@@ -251,7 +265,7 @@ $ sbx create claude .
251265
```
252266

253267
Unlike `run`, `create` requires an explicit workspace path. It uses direct
254-
mode by default, or pass `--branch` for [branch mode](#branch-mode). Attach
268+
mode by default, or pass `--clone` for [clone mode](#clone-mode). Attach
255269
later with `sbx run`:
256270

257271
```console
@@ -262,8 +276,8 @@ $ sbx run claude-my-project
262276

263277
You can mount extra directories into a sandbox alongside the main workspace.
264278
The first path is the primary workspace — the agent starts here, and the
265-
sandbox's Git worktree is created from this directory if you use `--branch`.
266-
Extra workspaces are always mounted directly.
279+
sandbox's in-container Git clone is populated from this directory if you
280+
use `--clone`. Extra workspaces are always mounted directly.
267281

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

0 commit comments

Comments
 (0)