Skip to content

Docker

Docker #983

name: Docker
# Build, publish and cosign-sign the image through the org bake reusable.
# The workflow has zero step-level action `uses:` — checkout, buildx, registry
# login, docker/metadata-action, the build and the keyless cosign signing all
# run inside netresearch/.github build-container-bake.yml. The build itself is
# defined in docker-bake.hcl (bake-only container builds, org policy).
#
# Signing note: the previous inline step signed
# `ghcr.io/netresearch/validator-w3c@<build-push digest>`. The reusable instead
# runs `cosign sign --yes <tag>` over the tags enumerated from
# `docker buildx bake --print`, so the digest is resolved by cosign at signing
# time rather than taken from the build output. In practice that is the same
# manifest — the sign step runs in the same job, seconds after the push — but
# it is a resolution, not a binding. The reusable does expose a `bake-metadata`
# output carrying each target's `containerimage.digest`, so a digest-pinned
# sign step is possible — but only as a change inside netresearch/.github, not
# at this call site. No such change is open there as of this PR.
on:
workflow_dispatch:
schedule:
- cron: '38 4 * * *'
push:
branches: [ master ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ master ]
permissions: {}
jobs:
build:
uses: netresearch/.github/.github/workflows/build-container-bake.yml@main
permissions:
contents: read
packages: write
# Trivy SARIF upload (scan: true) — and required regardless, since a
# caller may not grant less than the called job declares.
security-events: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
with:
bake-file: docker-bake.hcl
# Build from the LOCAL checkout: docker/metadata-action writes its tag and
# label bake files to $RUNNER_TEMP, which the default git remote context
# cannot see.
bake-source: "."
targets: app
registry: ghcr.io
metadata-images: ghcr.io/netresearch/validator-w3c
# docker/metadata-action's four built-in defaults, previously implicit
# (the old `Extract Docker metadata` step passed no `tags:`). Spelled out
# so the published tag set is auditable at the call site.
metadata-tags: |
type=schedule
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
# Don't push on PR.
push: ${{ github.event_name != 'pull_request' }}
# GHA layer cache (`cache-from`/`cache-to=type=gha`, emitted by the
# reusable only when this input is true). Enabled for branch pushes and
# pull requests only. Release-tag (`refs/tags/v*.*.*`) pushes, `schedule`
# and `workflow_dispatch` build uncached — as every trigger did before
# this migration, where the `docker/build-push-action` step passed
# neither `cache-from` nor `cache-to`.
cache: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && !startsWith(github.ref, 'refs/tags/') }}
# Cosign keyless (OIDC), as before; the reusable runs it only when
# pushing, i.e. never on pull_request. The `!repository.private` guard
# of the previous inline step is preserved here at the call site: the
# keyless flow records signatures on the public Rekor transparency log,
# so it stays off if this repo ever becomes private.
sign: ${{ !github.event.repository.private }}
# This is the repository's ONLY Trivy image scan. ci.yml calls
# docker-image-ci.yml, whose `build` job calls build-container.yml with
# `push: false`; that reusable gates both its Trivy step and its SARIF
# upload on `inputs.scan && inputs.push`, so its image scan is skipped
# on every ci.yml trigger. ci.yml's remaining security checks are
# hadolint, gitleaks and (on PRs) dependency-review — no image scan.
# Scanning here therefore covers every *published* image: push to
# master, `v*.*.*` tags, schedule and workflow_dispatch. Trivy is
# report-only (SARIF to code scanning, no --exit-code) and the reusable
# skips it unless something was pushed or loaded — so it does not run on
# pull_request here either (push=false, `load` left at its false default).
scan: true