Skip to content

Commit 1c7f948

Browse files
committed
feat: add digest-pinned OCI image management
Amp-Thread-ID: https://ampcode.com/threads/T-019c7d62-3f6b-7188-94cc-63e3d4f1cb10
1 parent f66b908 commit 1c7f948

File tree

24 files changed

+1906
-95
lines changed

24 files changed

+1906
-95
lines changed

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ It is built for this lifecycle:
1212
## What It Does
1313

1414
- Compiles repository policy from `cleanroom.yaml`
15+
- Requires digest-pinned sandbox base images via `sandbox.image.ref`
1516
- Enforces deny-by-default egress (`host:port` allow rules)
1617
- Runs commands in a Firecracker microVM via guest agent
1718
- Returns exit code + stdout/stderr over API
@@ -101,6 +102,15 @@ curl --silent --show-error \
101102
cleanroom exec -- pi run "implement the requested refactor"
102103
```
103104

105+
Image lifecycle commands:
106+
107+
```bash
108+
cleanroom image pull ghcr.io/buildkite/cleanroom-base/alpine@sha256:...
109+
cleanroom image ls
110+
cleanroom image rm sha256:...
111+
cleanroom image import ghcr.io/buildkite/cleanroom-base/alpine@sha256:... ./rootfs.tar.gz
112+
```
113+
104114
## API Contract (Current)
105115

106116
### `POST /v1/cleanrooms/launch`
@@ -141,6 +151,8 @@ Response fields:
141151
- `stderr`
142152
- `run_dir`
143153
- `plan_path`
154+
- `image_ref`
155+
- `image_digest`
144156

145157
### `POST /v1/cleanrooms/terminate`
146158

@@ -166,6 +178,8 @@ Minimal example:
166178
```yaml
167179
version: 1
168180
sandbox:
181+
image:
182+
ref: ghcr.io/buildkite/cleanroom-base/alpine@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
169183
network:
170184
default: deny
171185
allow:
@@ -187,13 +201,14 @@ backends:
187201
firecracker:
188202
binary_path: firecracker
189203
kernel_image: /opt/cleanroom/vmlinux
190-
rootfs: /opt/cleanroom/rootfs.ext4
191204
vcpus: 2
192205
memory_mib: 1024
193206
guest_cid: 3
194207
launch_seconds: 30
195208
```
196209

210+
The Firecracker adapter resolves `sandbox.image.ref` through the local image manager and caches materialised ext4 files under XDG cache paths.
211+
197212
## Isolation Model
198213

199214
- Workload runs in a Firecracker microVM
@@ -235,7 +250,8 @@ cleanroom status --run-id <run-id>
235250
- Linux host
236251
- `/dev/kvm` available and writable
237252
- Firecracker binary installed
238-
- Kernel image + rootfs image configured
253+
- Kernel image configured
254+
- `mkfs.ext4` installed (used to materialise OCI layers into ext4 cache artifacts)
239255
- `sudo -n` access for `ip`, `iptables`, and `sysctl` (network setup/cleanup)
240256

241257
## References

cleanroom.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
version: 1
22
sandbox:
3+
image:
4+
ref: ghcr.io/buildkite/cleanroom-base/alpine@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
35
network:
46
default: deny
57
allow:

examples/basic/README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The CLI should be available in `GOBIN` (or `GOPATH/bin`).
1414

1515
## Files
1616

17-
- `cleanroom.yaml`: deny-by-default network policy with one allowed host.
17+
- `cleanroom.yaml`: digest-pinned sandbox image ref plus a deny-by-default network policy with one allowed host.
1818
- `marker.sh`: command that writes a local marker file.
1919
- `cleanup.sh`: removes marker files created during testing.
2020

@@ -54,12 +54,23 @@ Expected: marker file exists and contains a timestamp.
5454

5555
## Optional: launched backend path
5656

57-
Launched execution requires runtime config (`~/.config/cleanroom/config.yaml`) with Firecracker `kernel_image` and `rootfs`, plus a rootfs prepared with `cleanroom-guest-agent` boot hook.
57+
Launched execution requires runtime config (`~/.config/cleanroom/config.yaml`) with Firecracker `kernel_image`, plus a digest-pinned `sandbox.image.ref` in policy.
58+
59+
Prewarm image cache (optional):
60+
61+
```bash
62+
cleanroom image pull ghcr.io/buildkite/cleanroom-base/alpine@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
63+
```
64+
65+
Or import a local tarball into the cache:
5866

5967
```bash
60-
sudo ../../scripts/create-rootfs-image.sh
61-
../../scripts/prepare-firecracker-image.sh
68+
cleanroom image import ghcr.io/buildkite/cleanroom-base/alpine@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ./rootfs.tar.gz
69+
```
6270

71+
Then run:
72+
73+
```bash
6374
cleanroom exec -- ./marker.sh
6475
ls -la .marker-created
6576
```

examples/basic/cleanroom.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
version: 1
22
sandbox:
3+
image:
4+
ref: ghcr.io/buildkite/cleanroom-base/alpine@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
35
network:
46
default: deny
57
allow:

go.mod

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ require (
88
github.com/charmbracelet/log v0.4.2
99
github.com/creack/pty v1.1.24
1010
github.com/firecracker-microvm/firecracker-go-sdk v1.0.0
11+
github.com/google/go-containerregistry v0.20.2
1112
github.com/mdlayher/vsock v1.2.1
1213
golang.org/x/net v0.38.0
1314
golang.org/x/sys v0.32.0
1415
golang.org/x/term v0.31.0
1516
google.golang.org/protobuf v1.36.10
1617
gopkg.in/yaml.v3 v3.0.1
18+
modernc.org/sqlite v1.33.1
1719
tailscale.com v1.80.3
1820
)
1921

@@ -43,9 +45,14 @@ require (
4345
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
4446
github.com/charmbracelet/x/term v0.2.1 // indirect
4547
github.com/coder/websocket v1.8.12 // indirect
48+
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
4649
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
4750
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
4851
github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect
52+
github.com/docker/cli v27.4.1+incompatible // indirect
53+
github.com/docker/distribution v2.8.3+incompatible // indirect
54+
github.com/docker/docker-credential-helpers v0.8.2 // indirect
55+
github.com/dustin/go-humanize v1.0.1 // indirect
4956
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
5057
github.com/gaissmai/bart v0.11.1 // indirect
5158
github.com/go-json-experiment/json v0.0.0-20250103232110-6a9a0fde9288 // indirect
@@ -59,6 +66,7 @@ require (
5966
github.com/google/uuid v1.6.0 // indirect
6067
github.com/gorilla/csrf v1.7.3-0.20250123201450-9dd6af1f6d30 // indirect
6168
github.com/gorilla/securecookie v1.1.2 // indirect
69+
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
6270
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
6371
github.com/illarion/gonotify/v2 v2.0.3 // indirect
6472
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect
@@ -74,10 +82,16 @@ require (
7482
github.com/mdlayher/sdnotify v1.0.0 // indirect
7583
github.com/mdlayher/socket v0.5.0 // indirect
7684
github.com/miekg/dns v1.1.58 // indirect
85+
github.com/mitchellh/go-homedir v1.1.0 // indirect
7786
github.com/mitchellh/go-ps v1.0.0 // indirect
7887
github.com/muesli/termenv v0.16.0 // indirect
88+
github.com/ncruces/go-strftime v0.1.9 // indirect
89+
github.com/opencontainers/go-digest v1.0.0 // indirect
90+
github.com/opencontainers/image-spec v1.1.0 // indirect
7991
github.com/pierrec/lz4/v4 v4.1.21 // indirect
92+
github.com/pkg/errors v0.9.1 // indirect
8093
github.com/prometheus-community/pro-bing v0.4.0 // indirect
94+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
8195
github.com/rivo/uniseg v0.4.7 // indirect
8296
github.com/safchain/ethtool v0.3.0 // indirect
8397
github.com/sirupsen/logrus v1.9.3 // indirect
@@ -91,6 +105,7 @@ require (
91105
github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect
92106
github.com/tailscale/wireguard-go v0.0.0-20250107165329-0b8b35511f19 // indirect
93107
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
108+
github.com/vbatts/tar-split v0.11.6 // indirect
94109
github.com/vishvananda/netns v0.0.4 // indirect
95110
github.com/x448/float16 v0.8.4 // indirect
96111
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
@@ -106,4 +121,10 @@ require (
106121
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
107122
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
108123
gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 // indirect
124+
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
125+
modernc.org/libc v1.55.3 // indirect
126+
modernc.org/mathutil v1.6.0 // indirect
127+
modernc.org/memory v1.8.0 // indirect
128+
modernc.org/strutil v1.2.0 // indirect
129+
modernc.org/token v1.1.0 // indirect
109130
)

0 commit comments

Comments
 (0)