zebra/.github/workflows/sub-build-docker-image.yml

213 lines
8.8 KiB
YAML

# This workflow automates the building and pushing of Docker images based on user-defined inputs. It includes:
# - Accepting various inputs like image name, Dockerfile path, target, and additional Rust-related parameters.
# - Authenticates with Google Cloud and logs into Google Artifact Registry and DockerHub.
# - Uses Docker Buildx for improved build performance and caching.
# - Builds the Docker image and pushes it to both Google Artifact Registry and potentially DockerHub, depending on release type.
# - Manages caching strategies to optimize build times across different branches.
# - Uses Docker Scout to display vulnerabilities and recommendations for the latest built image.
name: Build docker image
on:
workflow_call:
inputs:
image_name:
required: true
type: string
dockerfile_path:
required: true
type: string
dockerfile_target:
required: true
type: string
short_sha:
required: false
type: string
rust_backtrace:
required: false
type: string
rust_lib_backtrace:
required: false
type: string
# defaults to: vars.RUST_LOG
rust_log:
required: false
type: string
# defaults to: vars.RUST_PROD_FEATURES
features:
required: false
type: string
# defaults to: vars.RUST_TEST_FEATURES (and entrypoint.sh adds vars.RUST_PROD_FEATURES)
test_features:
required: false
type: string
latest_tag:
required: false
type: boolean
default: false
tag_suffix:
required: false
type: string
no_cache:
description: 'Disable the Docker cache for this build'
required: false
type: boolean
default: false
outputs:
image_digest:
description: 'The image digest to be used on a caller workflow'
value: ${{ jobs.build.outputs.image_digest }}
env:
FEATURES: ${{ inputs.features || vars.RUST_PROD_FEATURES }}
TEST_FEATURES: ${{ inputs.test_features || vars.RUST_TEST_FEATURES }}
RUST_LOG: ${{ inputs.rust_log || vars.RUST_LOG }}
CARGO_INCREMENTAL: ${{ vars.CARGO_INCREMENTAL }}
jobs:
build:
name: Build images
timeout-minutes: 210
runs-on: ubuntu-latest
outputs:
image_digest: ${{ steps.docker_build.outputs.digest }}
image_name: ${{ fromJSON(steps.docker_build.outputs.metadata)['image.name'] }}
permissions:
contents: 'read'
id-token: 'write'
pull-requests: write # for `docker-scout` to be able to write the comment
env:
DOCKER_BUILD_SUMMARY: ${{ vars.DOCKER_BUILD_SUMMARY }}
steps:
- uses: actions/checkout@v4.2.1
with:
persist-credentials: false
- uses: r7kamura/rust-problem-matchers@v1.5.0
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@v4
with:
short-length: 7
# Automatic tag management and OCI Image Format Specification for labels
- name: Docker meta
id: meta
uses: docker/metadata-action@v5.5.1
with:
# list of Docker images to use as base name for tags
# We only publish images to DockerHub if a release is not a pre-release
# Ref: https://github.com/orgs/community/discussions/26281#discussioncomment-3251177
images: |
us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra/${{ inputs.image_name }}
zfnd/${{ inputs.image_name }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease }}
# appends inputs.tag_suffix to image tags/names
flavor: |
suffix=${{ inputs.tag_suffix }}
latest=${{ inputs.latest_tag }}
# generate Docker tags based on the following events/attributes
tags: |
# These DockerHub release tags support the following use cases:
# - `latest`: always use the latest Zebra release when you pull or update
# - `v1.x.y` or `1.x.y`: always use the exact version, don't automatically upgrade
#
# `semver` adds a "latest" tag if `inputs.latest_tag` is `true`.
type=semver,pattern={{version}}
type=ref,event=tag
# DockerHub release and CI tags.
# This tag makes sure tests are using exactly the right image, even when multiple PRs run at the same time.
type=sha,event=push
# These CI-only tags support CI on PRs, the main branch, and scheduled full syncs.
# These tags do not appear on DockerHub, because DockerHub images are only published on the release event.
type=ref,event=pr
type=ref,event=branch
type=edge,enable={{is_default_branch}}
type=schedule
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@v2.1.6
with:
workload_identity_provider: '${{ vars.GCP_WIF }}'
service_account: '${{ vars.GCP_ARTIFACTS_SA }}'
token_format: 'access_token'
# Some builds might take over an hour, and Google's default lifetime duration for
# an access token is 1 hour (3600s). We increase this to 3 hours (10800s)
# as some builds take over an hour.
access_token_lifetime: 10800s
- name: Login to Google Artifact Registry
uses: docker/login-action@v3.3.0
with:
registry: us-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}
- name: Login to DockerHub
uses: docker/login-action@v3.3.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Setup Docker Buildx to use Docker Build Cloud
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v3.7.1
with:
version: "lab:latest"
driver: cloud
endpoint: "zfnd/zebra"
# Build and push image to Google Artifact Registry, and possibly DockerHub
- name: Build & push
id: docker_build
uses: docker/build-push-action@v6.9.0
with:
target: ${{ inputs.dockerfile_target }}
context: .
file: ${{ inputs.dockerfile_path }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
SHORT_SHA=${{ env.GITHUB_SHA_SHORT }}
RUST_LOG=${{ env.RUST_LOG }}
FEATURES=${{ env.FEATURES }}
TEST_FEATURES=${{ env.TEST_FEATURES }}
push: true
# It's recommended to build images with max-level provenance attestations
# https://docs.docker.com/build/ci/github-actions/attestations/
provenance: mode=max
sbom: true
# Don't read from the cache if the caller disabled it.
# https://docs.docker.com/engine/reference/commandline/buildx_build/#options
no-cache: ${{ inputs.no_cache }}
# For the latest built image, display:
# - the vulnerabilities (ignoring the base image, and only displaying vulnerabilities with a critical or high security severity)
# - the available recommendations
# - compare it to the latest image indexed in Docker Hub (only displaying changed packages and vulnerabilities that already have a fix)
#
# Record the image to Scout environment based on the event type, for example:
# - `prod` for a release event
# - `stage` for a push event to the main branch
# - `dev` for a pull request event
- name: Docker Scout
id: docker-scout
uses: docker/scout-action@v1.14.0
# We only run Docker Scout on the `runtime` target, as the other targets are not meant to be released
# and are commonly used for testing, and thus are ephemeral.
# TODO: Remove the `contains` check once we have a better way to determine if just new vulnerabilities are present.
# See: https://github.com/docker/scout-action/issues/56
if: ${{ inputs.dockerfile_target == 'runtime' && contains(github.event.pull_request.title, 'Release v') }}
with:
command: cves,recommendations,compare,environment
image: us-docker.pkg.dev/${{ vars.GCP_PROJECT }}/zebra/${{ inputs.image_name }}:${{ steps.meta.outputs.version }}
to: zfnd/zebra:latest
ignore-base: true
ignore-unchanged: true
only-fixed: true
only-severities: critical,high
environment: ${{ (github.event_name == 'release' && !github.event.release.prerelease && 'prod') || (github.event_name == 'push' && github.ref_name == 'main' && 'stage') || (github.event_name == 'pull_request' && 'dev') }}
organization: zfnd
github-token: ${{ secrets.GITHUB_TOKEN }} # to be able to write the comment