name: build permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: workflow_dispatch: push: branches: - 'master' - 'v[0-9]*' tags: - 'v*' pull_request: paths-ignore: - 'README.md' - 'docs/**' env: SETUP_BUILDX_VERSION: "edge" SETUP_BUILDKIT_IMAGE: "moby/buildkit:latest" SCOUT_VERSION: "1.11.0" REPO_SLUG: "docker/buildx-bin" DESTDIR: "./bin" TEST_CACHE_SCOPE: "test" TESTFLAGS: "-v --parallel=6 --timeout=30m" GOTESTSUM_FORMAT: "standard-verbose" GO_VERSION: "1.26" GOTESTSUM_VERSION: "v1.13.0" # same as one in Dockerfile jobs: test-integration: runs-on: ubuntu-24.04 env: TESTFLAGS_DOCKER: "-v --parallel=1 --timeout=30m" TEST_IMAGE_BUILD: "0" TEST_IMAGE_ID: "buildx-tests" TEST_COVERAGE: "1" strategy: fail-fast: false matrix: buildkit: - master - latest - buildx-stable-1 - v0.29.0 - v0.28.1 - v0.27.1 worker: - docker-container - remote pkg: - ./tests mode: - "" - experimental include: - worker: remote+multinode pkg: ./tests - worker: remote+multinode pkg: ./tests mode: experimental - worker: docker pkg: ./tests - worker: docker pkg: ./tests mode: experimental - worker: docker+containerd # same as docker, but with containerd snapshotter pkg: ./tests - worker: docker+containerd # same as docker, but with containerd snapshotter pkg: ./tests mode: experimental - worker: "docker@28.5" pkg: ./tests - worker: "docker+containerd@28.5" # same as docker, but with containerd snapshotter pkg: ./tests - worker: "docker@28.5" pkg: ./tests mode: experimental - worker: "docker+containerd@28.5" # same as docker, but with containerd snapshotter pkg: ./tests mode: experimental - worker: "docker@27.5" pkg: ./tests - worker: "docker+containerd@27.5" # same as docker, but with containerd snapshotter pkg: ./tests - worker: "docker@27.5" pkg: ./tests mode: experimental - worker: "docker+containerd@27.5" # same as docker, but with containerd snapshotter pkg: ./tests mode: experimental steps: - name: Prepare run: | echo "TESTREPORTS_NAME=${{ github.job }}-$(echo "${{ matrix.pkg }}-${{ matrix.buildkit }}-${{ matrix.worker }}-${{ matrix.mode }}" | tr -dc '[:alnum:]-\n\r' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV if [ -n "${{ matrix.buildkit }}" ]; then echo "TEST_BUILDKIT_TAG=${{ matrix.buildkit }}" >> $GITHUB_ENV fi testFlags="--run=//worker=$(echo "${{ matrix.worker }}" | sed 's/\+/\\+/g')$" case "${{ matrix.worker }}" in docker | docker+containerd | docker@* | docker+containerd@* | remote+multinode) echo "TESTFLAGS=${{ env.TESTFLAGS_DOCKER }} $testFlags" >> $GITHUB_ENV ;; *) echo "TESTFLAGS=${{ env.TESTFLAGS }} $testFlags" >> $GITHUB_ENV ;; esac if [[ "${{ matrix.worker }}" == "docker"* || "${{ matrix.worker }}" == "remote+multinode" ]]; then echo "TEST_DOCKERD=1" >> $GITHUB_ENV fi if [ "${{ matrix.mode }}" = "experimental" ]; then echo "TEST_BUILDX_EXPERIMENTAL=1" >> $GITHUB_ENV fi - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - name: Set up QEMU uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - name: Build test image uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0 with: source: . targets: integration-test set: | *.output=type=docker,name=${{ env.TEST_IMAGE_ID }} - name: Test run: | ./hack/test env: TEST_REPORT_SUFFIX: "-${{ env.TESTREPORTS_NAME }}" TESTPKGS: "${{ matrix.pkg }}" - name: Upload coverage to Codecov if: always() uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: directory: ./bin/testreports flags: integration token: ${{ secrets.CODECOV_TOKEN }} disable_file_fixes: true # needed for Go language https://docs.codecov.com/docs/fixing-reports - name: Upload test results to Codecov if: always() uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: report_type: test_results directory: ./bin/testreports flags: integration token: ${{ secrets.CODECOV_TOKEN }} disable_file_fixes: true # needed for Go language https://docs.codecov.com/docs/fixing-reports - name: Generate annotations if: always() uses: crazy-max/.github/.github/actions/gotest-annotations@46267a6e61cd56aac2fc79943df180152f4c89d6 # v1.10.1 with: directory: ./bin/testreports - name: Upload test reports if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-reports-${{ env.TESTREPORTS_NAME }} path: ./bin/testreports test-unit: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: - ubuntu-24.04 - macos-15 - windows-2025 env: SKIP_INTEGRATION_TESTS: 1 steps: - name: Setup Git config run: | git config --global core.autocrlf false git config --global core.eol lf - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Set up Go uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: go-version: "${{ env.GO_VERSION }}" - name: Prepare run: | testreportsName=${{ github.job }}--${{ matrix.os }} testreportsBaseDir=./bin/testreports testreportsDir=$testreportsBaseDir/$testreportsName echo "TESTREPORTS_NAME=$testreportsName" >> $GITHUB_ENV echo "TESTREPORTS_BASEDIR=$testreportsBaseDir" >> $GITHUB_ENV echo "TESTREPORTS_DIR=$testreportsDir" >> $GITHUB_ENV mkdir -p $testreportsDir shell: bash - name: Install gotestsum run: | go install gotest.tools/gotestsum@${{ env.GOTESTSUM_VERSION }} - name: Test env: TMPDIR: ${{ runner.temp }} run: | gotestsum \ --jsonfile="${{ env.TESTREPORTS_DIR }}/go-test-report.json" \ --junitfile="${{ env.TESTREPORTS_DIR }}/junit-report.xml" \ --packages="./..." \ -- \ "-mod=vendor" \ "-coverprofile" "${{ env.TESTREPORTS_DIR }}/coverage.txt" \ "-covermode" "atomic" ${{ env.TESTFLAGS }} shell: bash - name: Upload coverage to Codecov if: always() uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: directory: ${{ env.TESTREPORTS_DIR }} env_vars: RUNNER_OS flags: unit token: ${{ secrets.CODECOV_TOKEN }} disable_file_fixes: true # needed for Go language https://docs.codecov.com/docs/fixing-reports - name: Upload test results to Codecov if: always() uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: report_type: test_results directory: ${{ env.TESTREPORTS_DIR }} env_vars: RUNNER_OS flags: unit token: ${{ secrets.CODECOV_TOKEN }} disable_file_fixes: true # needed for Go language https://docs.codecov.com/docs/fixing-reports - name: Generate annotations if: always() uses: crazy-max/.github/.github/actions/gotest-annotations@46267a6e61cd56aac2fc79943df180152f4c89d6 # v1.10.1 with: directory: ${{ env.TESTREPORTS_DIR }} - name: Upload test reports if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-reports-${{ env.TESTREPORTS_NAME }} path: ${{ env.TESTREPORTS_BASEDIR }} govulncheck: runs-on: ubuntu-24.04 permissions: # same as global permission contents: read # required to write sarif report security-events: write steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 with: version: ${{ env.SETUP_BUILDX_VERSION }} driver-opts: image=${{ env.SETUP_BUILDKIT_IMAGE }} buildkitd-flags: --debug - name: Run uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0 with: targets: govulncheck env: GOVULNCHECK_FORMAT: sarif - name: Upload SARIF report if: ${{ github.ref == 'refs/heads/master' && github.repository == 'docker/buildx' }} uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: sarif_file: ${{ env.DESTDIR }}/govulncheck.out binaries: uses: docker/github-builder/.github/workflows/bake.yml@5f637c833aa76bc99372a1dc9a6f8bcd8056fb85 # v1.12.0 permissions: contents: read # same as global permission id-token: write # for signing attestation(s) with GitHub OIDC Token with: runner: amd64 artifact-name: buildx artifact-upload: true cache: true cache-scope: bin-image target: release output: local sbom: true sign: ${{ github.event_name != 'pull_request' }} binaries-finalize: runs-on: ubuntu-24.04 needs: - binaries steps: - name: Download artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: /tmp/buildx-output name: ${{ needs.binaries.outputs.artifact-name }} - name: Rename provenance and sbom run: | for pdir in /tmp/buildx-output/*/; do ( cd "$pdir" binname=$(find . -name 'buildx-*') filename=$(basename "${binname%.exe}") mv "provenance.json" "${filename}.provenance.json" mv "sbom-binaries.spdx.json" "${filename}.sbom.json" find . -name 'sbom*.json' -exec rm {} \; if [[ "$binname" == *darwin* ]]; then rm -f "provenance.sigstore.json" elif [ -f "provenance.sigstore.json" ]; then mv "provenance.sigstore.json" "${filename}.sigstore.json" fi ) done mkdir -p "${{ env.DESTDIR }}" mv /tmp/buildx-output/**/* "${{ env.DESTDIR }}/" - name: Create checksums working-directory: ${{ env.DESTDIR }} run: | sha256sum -b buildx-* > ./checksums.txt sed -i '/darwin/d' ./checksums.txt sha256sum -c --strict checksums.txt - name: List artifacts working-directory: ${{ env.DESTDIR }} run: | tree -nh . - name: Check artifacts working-directory: ${{ env.DESTDIR }} run: | find . -type f -exec file -e ascii -- {} + - name: Upload release binaries uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: release path: ${{ env.DESTDIR }}/* if-no-files-found: error bin-image-prepare: runs-on: ubuntu-24.04 outputs: repo-slug: ${{ env.REPO_SLUG }} steps: # FIXME: can't use env object in reusable workflow inputs: https://github.com/orgs/community/discussions/26671 - run: echo "Exposing env vars for reusable workflow" bin-image: if: ${{ github.repository == 'docker/buildx' }} uses: docker/github-builder/.github/workflows/bake.yml@5f637c833aa76bc99372a1dc9a6f8bcd8056fb85 # v1.12.0 needs: - bin-image-prepare - test-integration - test-unit permissions: contents: read # same as global permission id-token: write # for signing attestation(s) with GitHub OIDC Token with: runner: amd64 target: image-cross cache: true cache-scope: bin-image output: image push: ${{ github.event_name != 'pull_request' }} sbom: true set-meta-labels: true meta-images: | ${{ needs.bin-image-prepare.outputs.repo-slug }} meta-tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} meta-bake-target: meta-helper secrets: registry-auths: | - registry: docker.io username: ${{ vars.DOCKERPUBLICBOT_USERNAME }} password: ${{ secrets.DOCKERPUBLICBOT_WRITE_PAT }} scout: runs-on: ubuntu-24.04 if: ${{ github.ref == 'refs/heads/master' && github.repository == 'docker/buildx' }} permissions: # same as global permission contents: read # required to write sarif report security-events: write needs: - bin-image steps: - name: Login to DockerHub uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: username: ${{ vars.DOCKERPUBLICBOT_USERNAME }} password: ${{ secrets.DOCKERPUBLICBOT_WRITE_PAT }} - name: Scout id: scout uses: crazy-max/.github/.github/actions/docker-scout@46267a6e61cd56aac2fc79943df180152f4c89d6 # v1.10.1 with: version: ${{ env.SCOUT_VERSION }} format: sarif image: registry://${{ env.REPO_SLUG }}:master - name: Upload SARIF report uses: github/codeql-action/upload-sarif@54f647b7e1bb85c95cddabcd46b0c578ec92bc1a # v4.36.3 with: sarif_file: ${{ steps.scout.outputs.result-file }} release: runs-on: ubuntu-24.04 permissions: # required to create GitHub release contents: write needs: - test-integration - test-unit - binaries-finalize steps: - name: Download release binaries uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: ${{ env.DESTDIR }} name: release - name: GitHub Release if: startsWith(github.ref, 'refs/tags/v') uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: draft: true files: ${{ env.DESTDIR }}/*