Skip to content

Sandbox SDK: prebuilt presets, client/session split, async, and resum… #4

Sandbox SDK: prebuilt presets, client/session split, async, and resum…

Sandbox SDK: prebuilt presets, client/session split, async, and resum… #4

Workflow file for this run

name: Build and push preset images
# Two modes of operation:
#
# * Push to main -> build+push :main (mutable dev tag). Library code
# never references :main; it exists for manual testing.
#
# * workflow_dispatch -> build+push a pinned, immutable tag (e.g. :v2)
# matching PRESET_IMAGE_TAG in src/bespokelabs/sandbox/presets.py.
# This is how you cut a new image release: bump the constant in
# Python, then run this workflow with the same tag value.
#
# :sha-<short> is always emitted for audit/rollback.
on:
push:
branches: [main]
paths:
- "images/**"
workflow_dispatch:
inputs:
image:
description: "Specific image to build (e.g. claude-sdk), or 'all'"
required: false
default: "all"
tag:
description: "Pinned tag to publish (e.g. v2). Must match PRESET_IMAGE_TAG."
required: true
default: "v2"
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ghcr.io/bespokelabsai/sandbox
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
images: ${{ steps.set-matrix.outputs.images }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- id: set-matrix
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
INPUT="${{ github.event.inputs.image }}"
if [[ "$INPUT" == "all" || -z "$INPUT" ]]; then
IMAGES=$(ls -d images/*/ | xargs -I{} basename {} | jq -R -s -c 'split("\n") | map(select(. != ""))')
else
IMAGES=$(echo "[\"$INPUT\"]")
fi
else
# On push, only build images whose Dockerfile changed
CHANGED=$(git diff --name-only HEAD~1 HEAD -- images/ | cut -d/ -f2 | sort -u | jq -R -s -c 'split("\n") | map(select(. != ""))')
if [[ "$CHANGED" == "[]" || "$CHANGED" == '[""]' ]]; then
IMAGES="[]"
else
IMAGES="$CHANGED"
fi
fi
echo "images=$IMAGES" >> "$GITHUB_OUTPUT"
build:
needs: detect-changes
if: needs.detect-changes.outputs.images != '[]'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
image: ${{ fromJson(needs.detect-changes.outputs.images) }}
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/setup-buildx-action@v3
- uses: docker/metadata-action@v5
id: meta
with:
images: ${{ env.IMAGE_PREFIX }}/${{ matrix.image }}
# On workflow_dispatch -> the pinned tag input (e.g. :v2).
# On push to main -> :main (dev tag, never referenced by library).
# Always emit :sha-<short> for auditability.
tags: |
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event_name == 'workflow_dispatch' }}
type=raw,value=main,enable=${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
type=sha,prefix=sha-
- uses: docker/build-push-action@v5
with:
context: images/${{ matrix.image }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max