name: Bake images on: schedule: - cron: 0 8 * * 1 workflow_dispatch: inputs: environment: type: choice options: - testing - production default: testing description: "Choose the environment to bake the images for" target: type: string default: "" description: "A comma separated list of targets to build. If empty, all targets will be built." permissions: read-all jobs: # Start by building images for testing. We want to run security checks before pushing those to production. testbuild: name: Build for testing runs-on: ubuntu-latest permissions: contents: read packages: write security-events: write # Required by the cosign step id-token: write outputs: metadata: ${{ steps.build.outputs.metadata }} images: ${{ steps.images.outputs.images }} steps: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Log in to the GitHub Container registry uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # TODO: review this when GitHub has linux/arm64 runners available (Q1 2025?) # https://github.com/github/roadmap/issues/970 - name: Set up QEMU uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3 with: platforms: 'arm64' - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3 - name: Build and push uses: docker/bake-action@37816e747588cb137173af99ab33873600c46ea8 # v6 id: build env: environment: testing registry: ghcr.io/${{ github.repository_owner }} revision: ${{ github.sha }} with: push: true targets: ${{ github.event.inputs.target }} # Get a list of the images that were built and pushed. We only care about a single tag for each image. - name: Generated images id: images run: | echo "images=$(echo '${{ steps.build.outputs.metadata }}' | jq -c '[ .[]."image.name" | sub(",.*";"") ]')" >> "$GITHUB_OUTPUT" # Even if we're testing we sign the images, so we can push them to production later if that's required - name: Install cosign uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3 # See https://github.blog/security/supply-chain-security/safeguard-container-signing-capability-actions/ # and https://github.com/actions/starter-workflows/blob/main/ci/docker-publish.yml for more details on # how to use cosign. - name: Sign images run: | echo '${{ steps.build.outputs.metadata }}' | \ jq '.[] | (."image.name" | sub(",.*";"" )) + "@" + ."containerimage.digest"' | \ xargs cosign sign --yes security: name: Security checks runs-on: ubuntu-latest needs: - testbuild strategy: matrix: image: ${{fromJson(needs.testbuild.outputs.images)}} steps: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Log in to the GitHub Container registry uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Dockle uses: erzz/dockle-action@69369bc745ee29813f730231a821bcd4f71cd290 # v1 with: image: ${{ matrix.image }} exit-code: '1' - name: Snyk uses: snyk/actions/docker@master continue-on-error: true env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: image: "${{ matrix.image }}" args: --severity-threshold=high --file=Dockerfile - name: Upload result to GitHub Code Scanning uses: github/codeql-action/upload-sarif@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # v3 continue-on-error: true with: sarif_file: snyk.sarif # Use the metadata generated in the `testbuild` step to find all the images # that have been built. We copy them one by one to the production registry # using skopeo. Then we sign the production images too. copytoproduction: name: Copy images to production if: | github.ref == 'refs/heads/main' && ( github.event.inputs.environment == 'production' || github.event_name == 'schedule' ) runs-on: ubuntu-latest needs: - testbuild - security permissions: contents: read packages: write security-events: write # Required by the cosign step id-token: write steps: - name: Log in to the GitHub Container registry uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Copy images run: | images=$(echo '${{ needs.testbuild.outputs.metadata }}' | jq -r ' .[] as $items | ( $items."image.name" | split(",")[] + "@" + $items."containerimage.digest" ) ' ) for image in $images do testimageshaonly="${image%:*@*}@${image#*@}" testimagenosha="${image%@*}" prodimage="${testimagenosha/-testing/}" echo "Copying ${testimageshaonly} to ${prodimage}" docker run --quiet quay.io/skopeo/stable:v1.17.0-immutable copy -q -a \ --dest-creds ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }} \ docker://${testimageshaonly} docker://${prodimage} done - name: Install cosign uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3 - name: Sign images run: | images=$(echo '${{ needs.testbuild.outputs.metadata }}' | jq -r '.[] | ( ."image.name" | sub(",.*";"") | sub("-testing:[^@]+";"") ) + "@" + ."containerimage.digest" ' ) echo "Signing ${images}" cosign sign --yes ${images}