@stixxert/pi-docker-sandbox 0.1.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -2
- package/boundary.md +13 -2
- package/index.ts +268 -44
- package/package.json +23 -5
- package/sandbox/README.md +277 -0
- package/sandbox/e2e.mjs +467 -0
- package/sandbox/index.ts +229 -0
- package/sandbox/operations.ts +496 -0
- package/sandbox/package.json +11 -0
- package/sandbox/transport.ts +377 -0
- package/sandbox/try.sh +157 -0
- package/security.md +54 -2
- package/template/Dockerfile +34 -0
- package/template/README.md +92 -0
- package/template/build.sh +168 -0
- package/template/install.sh +77 -0
- package/test-loader.mjs +53 -0
package/README.md
CHANGED
|
@@ -4,6 +4,15 @@ A [pi](https://pi.dev) extension that gives an AI coding agent a **private
|
|
|
4
4
|
docker sandbox** to deploy into — powered by
|
|
5
5
|
[Docker Sandboxes](https://docs.docker.com/ai/sandboxes/) (`sbx`).
|
|
6
6
|
|
|
7
|
+
**How this sandboxes pi.** There are many ways to sandbox pi: wrap the whole
|
|
8
|
+
agent in a container or dedicated VM, confine it in a locked-down workspace,
|
|
9
|
+
or — as this project does — give pi a sandbox *to deploy into*. This is a
|
|
10
|
+
**pi extension, not a wrapper**: pi itself is never contained. It keeps
|
|
11
|
+
running in its normal host environment with its usual tools, workspace, and
|
|
12
|
+
agent micro-VM; the extension only adds a separate private microVM — with its
|
|
13
|
+
own docker daemon — as the agent's deploy target. What gets sandboxed here is
|
|
14
|
+
the docker work, not the pi process.
|
|
15
|
+
|
|
7
16
|
Each pi session gets its own **sandbox microVM with its own docker daemon**,
|
|
8
17
|
running in parallel to the agent. The agent can pull images, build, run
|
|
9
18
|
containers, and `docker compose up` — while the **host's docker is never
|
|
@@ -23,6 +32,42 @@ daemon are a liability. With this extension:
|
|
|
23
32
|
redirect it.
|
|
24
33
|
- `docker_verify` runs a live isolation audit (PASS/FAIL per check).
|
|
25
34
|
|
|
35
|
+
## Two modes
|
|
36
|
+
|
|
37
|
+
**1. Deploy target (default).** `pi install` this package and the agent gets
|
|
38
|
+
the `docker_*` tools: a private sbx microVM, with its own daemon, to deploy
|
|
39
|
+
into. pi's own tools keep running wherever pi runs.
|
|
40
|
+
|
|
41
|
+
**2. Execution backend.** Load `sandbox/` instead and pi runs *against* the
|
|
42
|
+
sandbox: `bash`, `read`, `write`, `edit`, `grep`, `find`, `ls` and your `!`
|
|
43
|
+
commands all execute inside the sbx microVM, while pi itself stays on the
|
|
44
|
+
host with its own auth, config, sessions and model keys.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cd /path/to/project
|
|
48
|
+
pi -e /path/to/pi-docker-sandbox/sandbox
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This is pi's "route tool execution into an isolated environment" pattern —
|
|
52
|
+
the same shape as pi's [Gondolin
|
|
53
|
+
example](https://github.com/earendil-works/pi-mono), with an sbx microVM as
|
|
54
|
+
the target rather than a local QEMU VM. See [sandbox/README.md](sandbox/README.md).
|
|
55
|
+
|
|
56
|
+
It is also the **lighter alternative to running pi inside a sandbox**: no
|
|
57
|
+
template with pi baked in, no bootstrap seeding state into the sandbox, no
|
|
58
|
+
per-project auth/sessions/credential handling, no sandbox rebuild to pick up
|
|
59
|
+
a new pi version. The tools are *overridden*, not added — so the model's
|
|
60
|
+
tool list is byte-for-byte the built-in one and not one prompt token is
|
|
61
|
+
spent on the sandbox.
|
|
62
|
+
|
|
63
|
+
The sandbox it creates can itself be slim: [template/](template/) builds a
|
|
64
|
+
**648 MB** baseline automatically (vs ~2.2 GB for the pi-bearing template),
|
|
65
|
+
because pi no longer has to live inside it. See
|
|
66
|
+
[template/README.md](template/README.md).
|
|
67
|
+
|
|
68
|
+
Both modes can be active at once; the `docker_*` tools keep working when the
|
|
69
|
+
backend is loaded.
|
|
70
|
+
|
|
26
71
|
## Requirements
|
|
27
72
|
|
|
28
73
|
- [pi](https://pi.dev) (the extension runs in the host pi process)
|
|
@@ -105,7 +150,7 @@ workspace mounted). No manual steps required.
|
|
|
105
150
|
| `docker_init` | Scaffold a Dockerfile (+ compose) with language detection |
|
|
106
151
|
| `docker_compose` | Deploy/manage compose projects (`up -d --build`) |
|
|
107
152
|
| `docker_stop` / `docker_start` / `docker_rm` | Container lifecycle |
|
|
108
|
-
| `docker_curl` | Probe a published port from the host process (GET/POST/PUT) |
|
|
153
|
+
| `docker_curl` | Probe a published port from the host process (GET/POST/PUT; only ports this sandbox published) |
|
|
109
154
|
| `docker_sandbox_rm` | Remove this session's sandbox (microVM + everything inside) |
|
|
110
155
|
| `docker_gc` | Sweep stale `pi-sbx-*` sandboxes left by crashed sessions |
|
|
111
156
|
|
|
@@ -164,7 +209,8 @@ persistent name (e.g. a shared sandbox reused across restarts), pin
|
|
|
164
209
|
mappings; after a host reboot let the session-start GC handle it, or run
|
|
165
210
|
`sbx rm --force $(sbx ls -q | grep pi-sbx)` from a host pane.
|
|
166
211
|
- Agent-side verification: `docker_curl` (host-side fetch, GET/POST/PUT with
|
|
167
|
-
optional body); human-side:
|
|
212
|
+
optional body, confined to ports this sandbox published); human-side:
|
|
213
|
+
`http://localhost:<hostport>/`.
|
|
168
214
|
|
|
169
215
|
See [boundary.md](boundary.md) for the full agent ↔ sbx boundary
|
|
170
216
|
model and usage guide (agent + human). The extension is not dependent on
|
|
@@ -204,6 +250,11 @@ The agent's VM mounts the workspace at `/workspace`; the extension maps
|
|
|
204
250
|
sandbox (the workspace is direct-mounted there). So `docker_build` contexts
|
|
205
251
|
and `docker_run` volume binds "just work".
|
|
206
252
|
|
|
253
|
+
The mapping is **confined to the workspace**: `/workspace/..` traversal,
|
|
254
|
+
absolute host paths, and symlinks that point outside the workspace are all
|
|
255
|
+
rejected, so the agent cannot reach host paths outside the mounted workspace
|
|
256
|
+
via build contexts, volume binds, or `docker_init`.
|
|
257
|
+
|
|
207
258
|
## Example deploy flow
|
|
208
259
|
|
|
209
260
|
```
|
|
@@ -266,6 +317,35 @@ directly by pi (copy it to `~/.pi/agent/extensions/docker-sandbox.ts`, or
|
|
|
266
317
|
pi package manifest (`pi.extensions`) and declares typecheck-only dev deps;
|
|
267
318
|
`tsconfig.json` keeps `tsc --strict` honest against the pi SDK types.
|
|
268
319
|
|
|
320
|
+
## Releases (CI/CD)
|
|
321
|
+
|
|
322
|
+
Releases are fully automated with [semantic-release](https://semantic-release.gitbook.io/)
|
|
323
|
+
via GitHub Actions (`.github/workflows/release.yml`). The **commit messages
|
|
324
|
+
themselves signal the release**: push to `main` and CI analyzes commits since
|
|
325
|
+
the last release tag, then bumps the version, tags, creates a GitHub Release,
|
|
326
|
+
and publishes to npm — only when there is something releasable.
|
|
327
|
+
|
|
328
|
+
| Commit message | Version bump |
|
|
329
|
+
|---|---|
|
|
330
|
+
| `fix: ...` | patch (`1.0.0` → `1.0.1`) |
|
|
331
|
+
| `feat: ...` | minor (`1.0.0` → `1.1.0`) |
|
|
332
|
+
| `BREAKING CHANGE: ...` (in body or footer) | major (`1.0.0` → `2.0.0`) |
|
|
333
|
+
| anything else (`docs:`, `chore:`, `refactor:`, …) | no release |
|
|
334
|
+
|
|
335
|
+
One-time setup: configure **trusted publishing** on npm so the workflow can
|
|
336
|
+
publish via OIDC — no npm token stored anywhere. On npmjs.com → package
|
|
337
|
+
`@stixxert/pi-docker-sandbox` → Settings → **Trusted Publisher**, add:
|
|
338
|
+
|
|
339
|
+
- Organization or user: `stixxert`
|
|
340
|
+
- Repository: `pi-docker-sandbox`
|
|
341
|
+
- Workflow filename: `release.yml`
|
|
342
|
+
- Environment name: *(leave empty)*
|
|
343
|
+
- Allowed actions: `npm publish`
|
|
344
|
+
|
|
345
|
+
`GITHUB_TOKEN` needs no setup. The first push to `main` containing a
|
|
346
|
+
`fix:`/`feat:` commit publishes the initial version. Provenance attestations
|
|
347
|
+
are generated automatically with trusted publishing.
|
|
348
|
+
|
|
269
349
|
## License
|
|
270
350
|
|
|
271
351
|
Apache-2.0 — see [LICENSE](LICENSE).
|
package/boundary.md
CHANGED
|
@@ -14,6 +14,16 @@ for the **agent** and for the **human operator**.
|
|
|
14
14
|
> Gondolin is used throughout this document simply as the concrete reference
|
|
15
15
|
> deployment.
|
|
16
16
|
|
|
17
|
+
> **Two modes.** This document describes the default **deploy target** mode,
|
|
18
|
+
> where the sandbox exists for `docker_*` and the agent keeps using its own
|
|
19
|
+
> tools. The repo also ships an **execution backend** (`sandbox/`) that routes
|
|
20
|
+
> pi's built-in tools into the same sandbox, for which the agent's own VM drops
|
|
21
|
+
> out of the picture and workspace paths are used as-is (the workspace is
|
|
22
|
+
> direct-mounted at its host absolute path inside the sandbox, so no
|
|
23
|
+
> `/workspace` hop is involved). See
|
|
24
|
+
> [sandbox/README.md](sandbox/README.md) and
|
|
25
|
+
> [security.md](security.md#execution-backend-built-in-tools-routed-into-the-sandbox).
|
|
26
|
+
|
|
17
27
|
## Topology
|
|
18
28
|
|
|
19
29
|
```
|
|
@@ -65,7 +75,7 @@ host macOS (trusted operator)
|
|
|
65
75
|
| Host env confidentiality | `DOCKER_*`/`COMPOSE_*` always stripped; secure by default (only a minimal safe set is forwarded); `DOCKER_SANDBOX_ENV_ALLOWLIST` opts in to specific vars, `_PASSTHROUGH` opts out entirely; `docker_verify` audits the active mode |
|
|
66
76
|
| Host files untouched | Only the session workspace is mounted into the sandbox; host `~/.docker`, `~/.ssh` etc. are not visible (audited by `docker_verify`) |
|
|
67
77
|
| Project writes (optional) | `DOCKER_SANDBOX_WORKSPACE_RO=1` → project mounted read-only; all project writes must go through the agent's own tools |
|
|
68
|
-
| Ports | Published on host `127.0.0.1` only (`sbx ports`); the agent probes them with `docker_curl` (host-side fetch); the agent's VM cannot reach host loopback |
|
|
78
|
+
| Ports | Published on host `127.0.0.1` only (`sbx ports`); the agent probes them with `docker_curl` (host-side fetch, confined to ports this sandbox published); the agent's VM cannot reach host loopback |
|
|
69
79
|
|
|
70
80
|
## Ports & networking (verified rules)
|
|
71
81
|
|
|
@@ -98,7 +108,8 @@ host macOS (trusted operator)
|
|
|
98
108
|
pokes the sandbox every ~60s while the pi session is alive).
|
|
99
109
|
6. **Verification paths**:
|
|
100
110
|
- Agent → `docker_curl http://127.0.0.1:<hostport>/` (host-side fetch;
|
|
101
|
-
GET/POST/PUT with optional body
|
|
111
|
+
GET/POST/PUT with optional body; only ports this sandbox published are
|
|
112
|
+
reachable).
|
|
102
113
|
- Sandbox-internal → `docker_exec` against `127.0.0.1:<port>` (same docker
|
|
103
114
|
network).
|
|
104
115
|
- Human → open `http://localhost:<hostport>/` on the host.
|