From 2d9e7bad39d5dcedacdc33c7ed3dd727fe977839 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Fri, 3 Jul 2026 17:04:11 +0200 Subject: [PATCH] ci: build and publish docker-agent sandbox templates Adds templates/Dockerfile and two CI jobs that build and push docker/sandbox-templates:docker-agent{,-docker} images on main (edge) and v* tags (versioned + floating). Assisted-By: claude-sonnet-4-5 --- .github/workflows/ci.yml | 91 ++++++++++++++++++++++++++++++++++++++++ Dockerfile | 27 ++++++++++++ Taskfile.yml | 5 +++ 3 files changed, 123 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0bd21c52..51527556e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,6 +123,22 @@ jobs: cache-from: type=gha,scope=buildx-${{ matrix.platform }} cache-to: type=gha,mode=min,scope=buildx-${{ matrix.platform }} + # The sandbox template shares the builder-linux stage, so it reuses the + # binary compiled by the step above. + - name: Build template + uses: docker/build-push-action@ee4ca427a2f43b6a16632044ca514c076267da23 # v6.19.0 + with: + context: . + target: template + platforms: ${{ matrix.platform }} + push: false + sbom: false + provenance: false + build-args: | + GIT_TAG=pr + GIT_COMMIT=dev + cache-from: type=gha,scope=buildx-${{ matrix.platform }} + build-and-push-image: if: github.event_name != 'pull_request' && !github.event.repository.fork needs: [lint, build-and-test, license-check] @@ -192,6 +208,39 @@ jobs: if-no-files-found: error retention-days: 1 + # The sandbox template is a stage of the same Dockerfile with identical + # build args, so it reuses the builder-linux layer from the image build + # above and embeds the exact same binary. + - name: Build and push template by digest + id: build-template + uses: docker/build-push-action@ee4ca427a2f43b6a16632044ca514c076267da23 # v6.19.0 + with: + context: . + target: template + platforms: ${{ matrix.platform }} + sbom: true + provenance: mode=max + outputs: type=image,name=docker/docker-agent-sbx-templates,push-by-digest=true,name-canonical=true,push=true + build-args: | + GIT_TAG=${{ github.ref_name }} + GIT_COMMIT=${{ github.sha }} + cache-from: type=gha,scope=buildx-${{ matrix.platform }} + + - name: Export template digest + env: + DIGEST: ${{ steps.build-template.outputs.digest }} + run: | + mkdir -p "${RUNNER_TEMP}/template-digests" + touch "${RUNNER_TEMP}/template-digests/${DIGEST#sha256:}" + + - name: Upload template digest + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: template-digests-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/template-digests/* + if-no-files-found: error + retention-days: 1 + merge-and-push-image: if: github.event_name != 'pull_request' && !github.event.repository.fork needs: [build-and-push-image] @@ -236,3 +285,45 @@ jobs: - name: Inspect image run: | docker buildx imagetools inspect docker/docker-agent:${{ steps.meta.outputs.version }} + + merge-and-push-template: + if: github.event_name != 'pull_request' && !github.event.repository.fork + needs: [build-and-push-image] + runs-on: ubuntu-latest + steps: + - name: Download template digests + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + with: + path: ${{ runner.temp }}/template-digests + pattern: template-digests-* + merge-multiple: true + + - name: Hub login + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + with: + username: ${{ vars.DOCKERPUBLICBOT_USERNAME }} + password: ${{ secrets.DOCKERPUBLICBOT_WRITE_PAT }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + + # Assemble the multi-arch manifest list from the per-arch digests pushed + # by build-and-push-image. On main only the edge tag moves; on a v* tag + # both the version tag and the floating latest tag that sandboxes pulls + # by default. + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/template-digests + run: | + if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then + tags=(-t "docker/docker-agent-sbx-templates:${GITHUB_REF_NAME#v}" -t "docker/docker-agent-sbx-templates:latest") + else + tags=(-t "docker/docker-agent-sbx-templates:edge") + fi + args=() + for digest in *; do args+=("docker/docker-agent-sbx-templates@sha256:${digest}"); done + docker buildx imagetools create "${tags[@]}" "${args[@]}" + + - name: Inspect template + run: | + if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then tag="${GITHUB_REF_NAME#v}"; else tag="edge"; fi + docker buildx imagetools inspect "docker/docker-agent-sbx-templates:${tag}" diff --git a/Dockerfile b/Dockerfile index a2bbade6c..6724e15ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -68,6 +68,33 @@ COPY --from=builder-cross /binaries/docker-agent-$TARGETOS-$TARGETARCH* docker-a FROM scratch AS cross COPY --from=builder-cross /binaries . +# Sandbox template for docker/sandboxes, pushed as +# docker/docker-agent-sbx-templates: layers the binary built above onto the +# sandboxes shell-docker base (tools stack, tini entrypoint, and +# com.docker.sandboxes.* labels — including start-docker, which sbx keys DinD +# setup on), so the template ships the exact same binary as the docker-agent +# image. +FROM docker/sandbox-templates:shell-docker AS template +ARG TARGETOS TARGETARCH +# The sandboxes tools base ships no editor; agents and users expect vi. +USER root +RUN <