Bake images #26
This file contains 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
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." | |
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@v4 | |
- name: Log in to the GitHub Container registry | |
uses: docker/login-action@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@v3 | |
with: | |
platforms: 'arm64' | |
# TODO: remove once https://github.com/docker/setup-qemu-action/issues/198 is fixed | |
image: 'tonistiigi/binfmt:qemu-v7.0.0' | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Build and push | |
uses: docker/bake-action@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@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@v4 | |
- name: Log in to the GitHub Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Dockle | |
uses: erzz/dockle-action@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@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@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@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} |