Skip to content

Commit bcde80a

Browse files
authored
Merge branch 'main' into dependabot/go_modules/packages/sandbox-container/native/desktop-wrapper/golang.org/x/image-0.38.0
2 parents e3aaeb4 + c9323fd commit bcde80a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3408
-557
lines changed

.changeset/process-tree-kill.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/crane-copy-retry.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22
# Copy a container image tag with retries on transient failures.
33
#
4-
# Sourced (not executed) by workflow steps - avoid changing shell options.
4+
# Sourced (not executed) by workflow steps avoid changing shell options.
55
#
66
# Usage: source .github/crane-copy-retry.sh
77
# crane_copy_retry "registry/image:src" "registry/image:dst"
@@ -10,7 +10,7 @@ crane_copy_retry() {
1010
local src="$1" dst="$2"
1111
if crane copy "$src" "$dst"; then return 0; fi
1212
for delay in 10 30; do
13-
echo "::warning::crane copy failed for $dst - retrying in ${delay}s"
13+
echo "::warning::crane copy failed for $dst retrying in ${delay}s"
1414
sleep "$delay"
1515
if crane copy "$src" "$dst"; then return 0; fi
1616
done

.github/workflows/release.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,16 @@ jobs:
204204
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
205205
NPM_CONFIG_PROVENANCE: true
206206

207+
- name: Update Docker Hub description
208+
uses: peter-evans/dockerhub-description@v4
209+
continue-on-error: true
210+
with:
211+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
212+
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
213+
repository: cloudflare/sandbox
214+
readme-filepath: ./DOCKER_README.md
215+
short-description: ${{ github.event.repository.description }}
216+
207217
- name: Publish Docker images to Docker Hub
208218
if: steps.changesets.outputs.published == 'true'
209219
run: |

.github/workflows/reusable-build.yml

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -195,38 +195,56 @@ jobs:
195195
env:
196196
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
197197

198-
- name: Retag cached images for this PR
198+
- name: Retag cached images
199+
id: retag-cached
199200
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit == 'true' }}
201+
continue-on-error: true
200202
run: |
201203
source .github/load-docker-images.sh
204+
source .github/crane-copy-retry.sh
202205
REGISTRY="registry.cloudflare.com/${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"
203206
HASH="${{ inputs.docker_hash }}"
204207
TAG="${{ inputs.image_tag }}"
205-
pids=()
208+
failed=0
206209
for image in "${DOCKER_IMAGES[@]}"; do
207-
crane copy "${REGISTRY}/${image}:ci-${HASH}" "${REGISTRY}/${image}:${TAG}" &
208-
pids+=($!)
210+
crane_copy_retry "${REGISTRY}/${image}:ci-${HASH}" "${REGISTRY}/${image}:${TAG}" || failed=1
209211
done
210-
for pid in "${pids[@]}"; do wait "$pid"; done
212+
exit "$failed"
211213
env:
212214
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
213215

214-
# --- Full Docker build (only when registry miss) ---
216+
- name: Resolve Docker path
217+
id: docker-path
218+
if: ${{ !inputs.skip_docker }}
219+
run: |
220+
if [[ "${{ steps.registry-check.outputs.hit }}" != "true" ]]; then
221+
echo "build=true" >> $GITHUB_OUTPUT
222+
echo "::notice::Docker path: full build (cache miss)"
223+
elif [[ "${{ steps.retag-cached.outcome }}" == "failure" ]]; then
224+
echo "build=true" >> $GITHUB_OUTPUT
225+
echo "::warning::Docker path: full build (retag failed, falling back)"
226+
else
227+
echo "build=false" >> $GITHUB_OUTPUT
228+
echo "::notice::Docker path: cache retag"
229+
fi
230+
231+
# --- Full Docker build (cache miss or retag fallback) ---
215232

216233
- name: Set up Docker Buildx
217-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
234+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
218235
uses: docker/setup-buildx-action@v3
219236

220237
- name: Login to GHCR (for build cache)
221-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
238+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
222239
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
223240

224241
- name: Read Bun version
225242
id: bun-version
243+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
226244
run: echo "version=$(cat .bun-version)" >> $GITHUB_OUTPUT
227245

228246
- name: Build Docker images (bake)
229-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
247+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
230248
uses: docker/bake-action@v6
231249
env:
232250
TAG: ${{ inputs.image_tag }}
@@ -240,22 +258,22 @@ jobs:
240258
load: true
241259

242260
- name: Push base image to CF registry
243-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
261+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
244262
run: npx wrangler containers push sandbox:${{ inputs.image_tag }}
245263
env:
246264
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
247265
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
248266

249267
- name: Build standalone image
250-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
268+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
251269
run: |
252270
docker buildx build \
253271
--build-arg BASE_IMAGE=registry.cloudflare.com/${{ secrets.CLOUDFLARE_ACCOUNT_ID }}/sandbox:${{ inputs.image_tag }} \
254272
--load -t sandbox-standalone:${{ inputs.image_tag }} \
255273
-f tests/e2e/test-worker/Dockerfile.standalone tests/e2e/test-worker
256274
257275
- name: Push remaining images to CF registry
258-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' }}
276+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' }}
259277
run: |
260278
source .github/load-docker-images.sh
261279
TAG="${{ inputs.image_tag }}"
@@ -271,24 +289,24 @@ jobs:
271289
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
272290

273291
- name: Tag images with content hash
274-
if: ${{ !inputs.skip_docker && steps.registry-check.outputs.hit != 'true' && inputs.docker_hash != '' }}
292+
if: ${{ !inputs.skip_docker && steps.docker-path.outputs.build == 'true' && inputs.docker_hash != '' }}
275293
run: |
276294
source .github/load-docker-images.sh
295+
source .github/crane-copy-retry.sh
277296
REGISTRY="registry.cloudflare.com/${{ secrets.CLOUDFLARE_ACCOUNT_ID }}"
278297
HASH="${{ inputs.docker_hash }}"
279298
TAG="${{ inputs.image_tag }}"
280-
pids=()
299+
failed=0
281300
for image in "${DOCKER_IMAGES[@]}"; do
282-
crane copy "${REGISTRY}/${image}:${TAG}" "${REGISTRY}/${image}:ci-${HASH}" &
283-
pids+=($!)
301+
crane_copy_retry "${REGISTRY}/${image}:${TAG}" "${REGISTRY}/${image}:ci-${HASH}" || failed=1
284302
done
285-
for pid in "${pids[@]}"; do wait "$pid"; done
303+
exit "$failed"
286304
env:
287305
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
288306

289307
- name: Report image status
290308
id: image-status
291-
if: always()
309+
if: ${{ !cancelled() }}
292310
run: |
293311
if [[ "${{ inputs.skip_docker }}" == "true" ]]; then
294312
echo "changed=false" >> $GITHUB_OUTPUT

DOCKER_README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Cloudflare Sandbox
2+
3+
Secure, isolated code execution containers for [Cloudflare Workers](https://developers.cloudflare.com/workers/). Run untrusted code safely — execute commands, manage files, run background processes, and expose services from your Workers applications.
4+
5+
## Image Variants
6+
7+
All images are published as tags on `cloudflare/sandbox`:
8+
9+
| Tag | Base | Description |
10+
| -------------------- | ------------ | -------------------------------------------------------------- |
11+
| `<version>` | Ubuntu 22.04 | Default — Node.js 20, Bun, Git, curl, jq, and common utilities |
12+
| `<version>-python` | Ubuntu 22.04 | Default + Python 3.11 with matplotlib, numpy, pandas, ipython |
13+
| `<version>-opencode` | Ubuntu 22.04 | Default + [OpenCode](https://opencode.ai) CLI |
14+
| `<version>-musl` | Alpine 3.21 | Minimal Alpine-based image with Git, curl, and bash |
15+
| `<version>-desktop` | Ubuntu 22.04 | Full Linux desktop (XFCE) with Xvfb, VNC, and noVNC |
16+
17+
## Usage
18+
19+
These images are designed to be used with the [`@cloudflare/sandbox`](https://www.npmjs.com/package/@cloudflare/sandbox) SDK. Reference them in your project's `Dockerfile`:
20+
21+
```dockerfile
22+
FROM cloudflare/sandbox:0.8.3-python
23+
```
24+
25+
Then configure your `wrangler.toml` to use the image:
26+
27+
```toml
28+
[containers]
29+
image = "./Dockerfile"
30+
max_instances = 1
31+
```
32+
33+
See the [Getting Started guide](https://developers.cloudflare.com/sandbox/get-started/) for a complete walkthrough.
34+
35+
## Architecture
36+
37+
Each image runs a lightweight HTTP server (port 3000) that the Sandbox SDK communicates with. The server handles command execution, file operations, process management, and port exposure. Images are built for `linux/amd64`.
38+
39+
## Documentation
40+
41+
- [Full Documentation](https://developers.cloudflare.com/sandbox/)
42+
- [API Reference](https://developers.cloudflare.com/sandbox/api/)
43+
- [Examples](https://github.com/cloudflare/sandbox-sdk/tree/main/examples)
44+
- [GitHub Repository](https://github.com/cloudflare/sandbox-sdk)
45+
46+
## License
47+
48+
[Apache License 2.0](https://github.com/cloudflare/sandbox-sdk/blob/main/LICENSE)

examples/alpine/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/cloudflare/sandbox:0.8.0-musl
1+
FROM docker.io/cloudflare/sandbox:0.8.3-musl
22

33
# Required during local development to access exposed ports
44
EXPOSE 8080

examples/authentication/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/cloudflare/sandbox:0.8.0
1+
FROM docker.io/cloudflare/sandbox:0.8.3
22

33
# Required during local development to access exposed ports
44
EXPOSE 8080

examples/claude-code/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/cloudflare/sandbox:0.8.0
1+
FROM docker.io/cloudflare/sandbox:0.8.3
22
RUN npm install -g @anthropic-ai/claude-code
33
ENV COMMAND_TIMEOUT_MS=300000
44
EXPOSE 3000
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
FROM docker.io/cloudflare/sandbox:0.8.0-python
1+
FROM docker.io/cloudflare/sandbox:0.8.3-python
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/cloudflare/sandbox:0.8.0
1+
FROM docker.io/cloudflare/sandbox:0.8.3
22

33
# Required during local development to access exposed ports
44
EXPOSE 8080

0 commit comments

Comments
 (0)