Skip to content

Commit 57db352

Browse files
committed
feat(build): attach a provenance attestation beside the SBOM
An image built with SBOM=1 says what is in it and nothing about how it was built: BUILDX_ARGS set --provenance=false for every build, from when any attestation broke the single-platform stitch. SBOM=1 now also passes --attest type=provenance,mode=min, which BuildKit writes into the same attestation manifest as the SBOM, so the index shape the stitch and the gate read since #4997 is unchanged and a signature over the index covers it. mode=min records the build times, the platform, the frontend and the BuildKit version and leaves out build arguments and secrets, which is what lets it ride every release image. A build without SBOM=1 keeps --provenance=false: the default docker driver cannot attach it, and a PR image turned into an index would buy nothing. Refs #3278 Assisted-by: LLM Signed-off-by: Marian Koreniuk <[email protected]>
1 parent d32092a commit 57db352

3 files changed

Lines changed: 24 additions & 11 deletions

File tree

‎docs/release.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ The script runs the same `cosign verify-blob` before it returns, so a signature
355355

356356
### SBOM of the container images
357357

358-
The container images a release pins by digest each carry an SPDX SBOM of the packages in them, which BuildKit attaches at build time as an attestation (`SBOM=1` in `tags.yaml`, scanner and flags in [`hack/common-envs.mk`](../hack/common-envs.mk)). The attestation is an entry of the image's index, so the digest the release pins names both, and promotion copies it with the image. Read it with `docker buildx imagetools inspect <image>@<digest> --format '{{ json .SBOM }}'`, which prints one document per platform. The attestations are not signed. A release cut before `SBOM=1` was set has none, and neither has the Talos installer image, which the imager builds and `skopeo` pushes, nor the third-party images `packages/` vendors by digest.
358+
The container images a release pins by digest each carry an SPDX SBOM of the packages in them, which BuildKit attaches at build time as an attestation (`SBOM=1` in `tags.yaml`, scanner and flags in [`hack/common-envs.mk`](../hack/common-envs.mk)). The attestation is an entry of the image's index, so the digest the release pins names both, and promotion copies it with the image. Read it with `docker buildx imagetools inspect <image>@<digest> --format '{{ json .SBOM }}'`, which prints one document per platform. The same attestation manifest carries a SLSA provenance statement of the build, in BuildKit's `mode=min` (build times, platform, frontend and BuildKit version, no build arguments and no secrets), which `docker buildx imagetools inspect <image>@<digest> --format '{{ json .Provenance }}'` prints. The attestations are not signed. A release cut before `SBOM=1` was set has none, and neither has the Talos installer image, which the imager builds and `skopeo` pushes, nor the third-party images `packages/` vendors by digest.
359359

360360
## Nightly builds
361361

‎hack/common-envs.mk‎

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,29 @@ PLATFORM ?= $(if $(filter 1,$(LOAD)),,$(DEFAULT_PLATFORMS))
6666
BUILDX_EXTRA_ARGS ?=
6767
COZYSTACK_VERSION = $(patsubst v%,%,$(shell git describe --tags --match 'v*'))
6868

69-
# SBOM=1 attaches an SPDX SBOM to every image as a BuildKit attestation. The
70-
# pushed ref then names an index of the image and its attestation manifest, not
71-
# the image itself, which hack/stitch-multiarch.sh and hack/verify-multiarch.sh
72-
# both handle. Attestations need the docker-container buildx driver. The scanner
73-
# is pinned by digest like every other build input, where --sbom=true would pull
69+
# SBOM=1 attaches an SPDX SBOM and a SLSA provenance statement to every image
70+
# as BuildKit attestations, in one attestation manifest per platform. The
71+
# pushed ref then names an index of the image and that manifest, not the image
72+
# itself, which hack/stitch-multiarch.sh and hack/verify-multiarch.sh both
73+
# handle. Attestations need the docker-container buildx driver. The scanner is
74+
# pinned by digest like every other build input, where --sbom=true would pull
7475
# a floating tag. Renovate bumps the version and the digest together, through
7576
# the manager in .github/renovate.json that reads the SBOM_SCANNER line below.
77+
#
78+
# The provenance is mode=min: build times, the build platform, the frontend
79+
# and BuildKit version, nothing of the build arguments or secrets, so it can
80+
# ride every release image. Without SBOM=1 provenance stays off: the default
81+
# docker driver cannot attach it, and it would turn every PR image into an
82+
# index for nothing that reads it.
7683
SBOM ?= 0
7784
SBOM_SCANNER ?= docker.io/docker/buildkit-syft-scanner:1.12.0@sha256:ae4f3b554449e7e25548e7d8ccc029d17357348e30c6e3df01b92bc93654d6a9
78-
# A variable, because the commas would split the arguments of $(if) below.
85+
# Variables, because the commas would split the arguments of $(if) below.
7986
SBOM_ATTEST := --attest type=sbom,generator=$(SBOM_SCANNER)
87+
PROVENANCE_ATTEST := --attest type=provenance,mode=min
8088

81-
BUILDX_ARGS := --provenance=false --push=$(PUSH) --load=$(LOAD) \
89+
BUILDX_ARGS := --push=$(PUSH) --load=$(LOAD) \
8290
--label org.opencontainers.image.source=https://github.com/cozystack/cozystack \
83-
$(if $(filter 1,$(SBOM)),$(SBOM_ATTEST)) \
91+
$(if $(filter 1,$(SBOM)),$(SBOM_ATTEST) $(PROVENANCE_ATTEST),--provenance=false) \
8492
$(if $(strip $(BUILDER)),--builder=$(BUILDER)) \
8593
$(if $(strip $(PLATFORM)),--platform=$(PLATFORM)) \
8694
$(BUILDX_EXTRA_ARGS)

‎hack/common-envs_test.bats‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,20 @@ load test_helper
144144
echo "$out" | grep -q -- '--push=0 --load=1'
145145
}
146146

147-
@test "SBOM=1 attaches an SPDX attestation from a scanner pinned by digest, and the default builds none" {
147+
@test "SBOM=1 attaches an SPDX attestation from a scanner pinned by digest and a mode=min provenance, and the default builds none" {
148148
# An image built with an attestation is an index, not a plain manifest, which
149149
# the stitch and the gate have to read, so it stays off unless a build asks.
150-
# --sbom=true would pull the scanner by a floating tag.
150+
# --sbom=true would pull the scanner by a floating tag. Provenance rides the
151+
# same attestation manifest; mode=max would write build arguments into it.
151152
out=$(make -n -C packages/system/cozystack-controller image IMAGE_TAG=pr-1-abc COZYSTACK_VERSION=0 BUILDER=b)
152153
if echo "$out" | grep -q -- '--attest\|--sbom'; then echo "FAIL: an attestation without SBOM=1"; false; fi
154+
echo "$out" | grep -q -- '--provenance=false' || { echo "FAIL: provenance not switched off without SBOM=1"; false; }
153155
out=$(make -n -C packages/system/cozystack-controller image IMAGE_TAG=pr-1-abc COZYSTACK_VERSION=0 BUILDER=b SBOM=1)
154156
echo "$out" | grep -qE -- '--attest type=sbom,generator=[^ ]+@sha256:[0-9a-f]{64} ' || { echo "FAIL: no digest-pinned scanner"; false; }
155157
if echo "$out" | grep -q -- '--sbom'; then echo "FAIL: --sbom=true pulls a floating scanner tag"; false; fi
158+
echo "$out" | grep -q -- '--attest type=provenance,mode=min' || { echo "FAIL: no mode=min provenance beside the SBOM"; false; }
159+
if echo "$out" | grep -q -- '--provenance=false'; then echo "FAIL: --provenance=false cancels the provenance attestation"; false; fi
160+
if echo "$out" | grep -qE -- 'provenance,mode=max|--provenance=true'; then echo "FAIL: full provenance would carry build arguments"; false; fi
156161
# The environment reaches buildx as well, which is how the release workflow sets it.
157162
out=$(SBOM=1 make -n -C packages/system/cozystack-controller image IMAGE_TAG=pr-1-abc COZYSTACK_VERSION=0 BUILDER=b)
158163
echo "$out" | grep -q -- '--attest type=sbom,'

0 commit comments

Comments
 (0)