sandbox: add ollama sandbox with openclaw support #108
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| name: Build Sandbox Images | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "sandboxes/**" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - "sandboxes/**" | |
| workflow_dispatch: | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_PREFIX: ${{ github.repository }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Detect which sandbox images have changed | |
| # --------------------------------------------------------------------------- | |
| detect-changes: | |
| name: Detect changed sandboxes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| base-changed: ${{ steps.changes.outputs.base_changed }} | |
| sandboxes: ${{ steps.changes.outputs.sandboxes }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Determine changed sandboxes | |
| id: changes | |
| run: | | |
| set -euo pipefail | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| # Build everything on manual trigger | |
| BASE_CHANGED="true" | |
| SANDBOXES=$(find sandboxes -mindepth 1 -maxdepth 1 -type d -name '*.base' -prune -o -exec test -f {}/Dockerfile \; -print \ | |
| | xargs -I{} basename {} \ | |
| | grep -v '^base$' \ | |
| | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| else | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" | |
| else | |
| BASE_SHA="${{ github.event.before }}" | |
| fi | |
| CHANGED=$(git diff --name-only "$BASE_SHA" "${{ github.sha }}" -- sandboxes/) | |
| # Check if base changed | |
| if echo "$CHANGED" | grep -q '^sandboxes/base/'; then | |
| BASE_CHANGED="true" | |
| # When base changes, rebuild all sandboxes that have a Dockerfile | |
| SANDBOXES=$(find sandboxes -mindepth 1 -maxdepth 1 -type d -exec test -f {}/Dockerfile \; -print \ | |
| | xargs -I{} basename {} \ | |
| | grep -v '^base$' \ | |
| | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| else | |
| BASE_CHANGED="false" | |
| SANDBOXES=$(echo "$CHANGED" \ | |
| | cut -d'/' -f2 \ | |
| | sort -u \ | |
| | while read -r name; do | |
| if [ "$name" != "base" ] && [ -f "sandboxes/${name}/Dockerfile" ]; then echo "$name"; fi | |
| done \ | |
| | jq -R -s -c 'split("\n") | map(select(length > 0))') | |
| fi | |
| fi | |
| echo "base_changed=${BASE_CHANGED}" >> "$GITHUB_OUTPUT" | |
| echo "sandboxes=${SANDBOXES}" >> "$GITHUB_OUTPUT" | |
| echo "Base changed: ${BASE_CHANGED}" | |
| echo "Will build: ${SANDBOXES}" | |
| # --------------------------------------------------------------------------- | |
| # Build the base sandbox image (other sandboxes depend on this) | |
| # --------------------------------------------------------------------------- | |
| build-base: | |
| name: Build base | |
| needs: detect-changes | |
| if: needs.detect-changes.outputs.base-changed == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Lowercase image prefix | |
| id: repo | |
| run: echo "image_prefix=${IMAGE_PREFIX,,}" >> "$GITHUB_OUTPUT" | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate image metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.repo.outputs.image_prefix }}/sandboxes/base | |
| tags: | | |
| type=sha,prefix= | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: sandboxes/base | |
| platforms: linux/amd64,linux/arm64 | |
| push: ${{ github.ref == 'refs/heads/main' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha,scope=base | |
| cache-to: type=gha,mode=max,scope=base | |
| # --------------------------------------------------------------------------- | |
| # Build dependent sandbox images (after base completes) | |
| # --------------------------------------------------------------------------- | |
| build: | |
| name: Build ${{ matrix.sandbox }} | |
| needs: [detect-changes, build-base] | |
| if: | | |
| always() && | |
| needs.detect-changes.result == 'success' && | |
| (needs.build-base.result == 'success' || needs.build-base.result == 'skipped') && | |
| needs.detect-changes.outputs.sandboxes != '[]' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| sandbox: ${{ fromJson(needs.detect-changes.outputs.sandboxes) }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Lowercase image prefix | |
| id: repo | |
| run: echo "image_prefix=${IMAGE_PREFIX,,}" >> "$GITHUB_OUTPUT" | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| # On PRs, use a local registry so the base image built in this job is | |
| # accessible to the subsequent buildx build (docker-container driver | |
| # cannot see images loaded into the host daemon). | |
| - name: Start local registry (PR only) | |
| if: github.ref != 'refs/heads/main' | |
| run: docker run -d -p 5000:5000 --name registry registry:2 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| driver-opts: ${{ github.ref != 'refs/heads/main' && 'network=host' || '' }} | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| # On PRs the base image is not in GHCR. Build it locally, push to the | |
| # local registry, and override BASE_IMAGE to point there. | |
| - name: Build base image locally (PR only) | |
| if: github.ref != 'refs/heads/main' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: sandboxes/base | |
| push: true | |
| tags: localhost:5000/sandboxes/base:latest | |
| cache-from: type=gha,scope=base | |
| - name: Determine parent sandbox | |
| id: parent | |
| run: | | |
| set -euo pipefail | |
| DEFAULT_BASE=$(grep '^ARG BASE_IMAGE=' "sandboxes/${{ matrix.sandbox }}/Dockerfile" | head -1 | cut -d= -f2-) | |
| PARENT=$(echo "$DEFAULT_BASE" | sed -n 's|.*/sandboxes/\([^:]*\).*|\1|p') | |
| if [ -z "$PARENT" ]; then | |
| PARENT="base" | |
| fi | |
| echo "sandbox=$PARENT" >> "$GITHUB_OUTPUT" | |
| echo "Parent for ${{ matrix.sandbox }}: $PARENT" | |
| # When a sandbox depends on another sandbox (not base), build that | |
| # intermediate parent locally so it is available to the buildx build. | |
| - name: Build parent sandbox locally (PR only) | |
| if: github.ref != 'refs/heads/main' && steps.parent.outputs.sandbox != 'base' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: sandboxes/${{ steps.parent.outputs.sandbox }} | |
| push: true | |
| tags: localhost:5000/sandboxes/${{ steps.parent.outputs.sandbox }}:latest | |
| build-args: | | |
| BASE_IMAGE=localhost:5000/sandboxes/base:latest | |
| cache-from: type=gha,scope=${{ steps.parent.outputs.sandbox }} | |
| - name: Set BASE_IMAGE | |
| id: base | |
| run: | | |
| PARENT="${{ steps.parent.outputs.sandbox }}" | |
| if [ "${{ github.ref }}" = "refs/heads/main" ]; then | |
| echo "image=${{ env.REGISTRY }}/${{ steps.repo.outputs.image_prefix }}/sandboxes/${PARENT}:latest" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "image=localhost:5000/sandboxes/${PARENT}:latest" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Generate image metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ steps.repo.outputs.image_prefix }}/sandboxes/${{ matrix.sandbox }} | |
| tags: | | |
| type=sha,prefix= | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: sandboxes/${{ matrix.sandbox }} | |
| platforms: ${{ github.ref == 'refs/heads/main' && 'linux/amd64,linux/arm64' || 'linux/amd64' }} | |
| push: ${{ github.ref == 'refs/heads/main' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| build-args: | | |
| BASE_IMAGE=${{ steps.base.outputs.image }} | |
| cache-from: type=gha,scope=${{ matrix.sandbox }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.sandbox }} | |