Repository navigation
#614 Generate a CycloneDX SBOM for each web and worker image - #651
Merged
Merged
Conversation
…age and attaches it in GHCR syft (anchore/sbom-action) reads the image the shared build-docker-image action loaded into the runner's daemon; the SBOM is kept as a workflow artifact and attached to the image with ORAS, using the referrers tag schema because GHCR has no referrers API. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both builds in Build and Deploy and the weekly no-cache rebuild of the web image, which pushes a fresh image under the same sha tag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… against it Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Review app for PR 651 was deleted |
E2E tests passed374 passed, 0 failed, 4 skipped in 17 min 36 s Commit |
… step summary Identical sources build an identical image, so a docs-only pull request, a job re-run and the merge build all resolve to a digest that already carries an SBOM; attaching again would rewrite the referrers index on GHCR. ORAS pinned to 1.3.5, the version the behaviour was checked with. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rom the sha tag The weekly no-cache rebuild moves the tag without redeploying, and the SBOM file is named after the commit that first built the image. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
setup-oras@v2 installs only the versions in its bundled release list, which stops at 1.3.4, so the 1.3.5 pin failed the build. 1.3.1 is the action's default and was also checked against GHCR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A re-run of the same merge commit rebuilt the web image's publish layer and produced a new digest, which took its own SBOM. Each digest still has exactly one; the comment and the docs no longer promise that identical sources always give an identical image. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
davidgouge
approved these changes
Oct 20, 2026
This branch was successfully deployed
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #614 (part of #607, OWASP A03).
What
Every web and worker image CI pushes now has a CycloneDX SBOM, in two places:
sbom-web-<sha>.cdx.json/sbom-worker-<sha>.cdx.json(90 days)referrers API, so ORAS uses the referrers tag schema: a
sha256-<image digest>tag in thepackage points at the index that lists the SBOM.
oras discover <image>:<sha>finds it.One composite action,
.github/actions/image-sbom(anchore/sbom-action→ syft → CycloneDXJSON;
oras attach), called after both builds inbuild-and-deploy.ymland after the weeklyno-cache rebuild of the web image in
build-nocache.yml, which pushes a fresh image under thesame sha tag.
docs/sbom.mdsays how to fetch the SBOM for a deployed sha and check anadvisory against it.
An SBOM is attached once per image digest. When the layer cache is hit, commits with the same
./srcbuild the same image (this PR's first images were the onesmainc1b2ace deployed), so adocs-only PR, a job re-run and the merge build find the SBOM already there and skip the attach;
otherwise the image gets a new digest and its own SBOM. The step summary names the digest and says
which happened. The SBOM file is named after the commit whose build first attached it. Docs find a
deployed environment's SBOM from the digest its pods report, because the weekly no-cache rebuild
moves the sha tag without redeploying.
No Dockerfile, code or package change. No permission change (
packages: writewas already there).Proof
97 Ubuntu packages; worker — 4,037 components, 141 NuGet, 112 Ubuntu packages.
Both name the application (1.0.0), Npgsql 10.0.3 and libssl3t64 3.0.13-0ubuntu3.16.
both SBOM steps green in 13 s (web) / 10 s (worker); artifacts
sbom-web-2defa314b06682b755476a297d8711068b4756f2.cdx.jsonand thesbom-worker-…equivalent.CI used syft 1.42.3 (CycloneDX 1.6; 89 NuGet / 97 deb web, 141 / 112 worker).
oras discover ghcr.io/dfe-digital/check-performance-data:2defa31…→ one referrer,application/vnd.cyclonedx+json,sha256:74545271556f…(worker:sha256:aa31a763aa3b…);oras pullof each gives a file byte-identical to its artifact. Thesha256-<digest>referrers index tag exists in GHCR (HTTP 200) and lists the SBOM.
https://github.com/DFE-Digital/check-performance-data/actions/runs/39421197224: web image rebuilt under
the same sha tag (new digest
sha256:236c350ae01c…), new SBOMsha256:fea67fc92513…attached anddiscoverable.
(run 39421067233).
https://github.com/DFE-Digital/check-performance-data/actions/runs/39427772270 (
43b27cb8):worker skipped for real on GHCR —
ghcr.io/dfe-digital/check-performance-data-worker:43b27cb8… (sha256:60094523b1b7…) already has an SBOM attached; not attaching another.Web had a new digest (
sha256:16f00d1c65c1…) and attachedsbom-web-43b27cb8….cdx.json.same merge commit: worker skipped again with the same line; web rebuilt its publish layer
(cache not reused), got another new digest (
sha256:310adfef110d…) and attached to that.So the web digest is stable only when the layer cache is hit;
e4ee960esays so.(
e4ee960e, merged ontomain5d3ee95): worker skipped a third time (same line, digest60094523b1b7…); web, built from 611 remove unsafe inline and unsafe eval from the csp script src #650's changed sources, attached to its new digestsha256:31638f3764a3…. Deployment To Review and smoke tests green.oras discover --artifact-type application/vnd.cyclonedx+jsonfrom outside CI: exactly onereferrer on every image this PR touched — web
5e4c914f,236c350a,16f00d1c,310adfef,31638f37; worker60094523.e4ee960e: 374 passed, 0 failed, 4 skipped (run https://github.com/DFE-Digital/check-performance-data/actions/runs/39431417722; up from 362 because 611 remove unsafe inline and unsafe eval from the csp script src #650 onmainadded E2E tests). The suite started by the attempt-2 deploy (run 39429841578) failed one test,SearchByTokens_NamesTheReadablePaths_InTheCountLineAndTheScopeComment, while the review app was redeployed under it fore4ee960e; that test passed in thee4ee960esuite.Follow-ups (not this PR)
Build No Cacherebuilds only the web image weekly; the worker is never refreshed.dependency-snapshot: true) so Dependabotalerts cover the Ubuntu packages too.
anchore/sbom-actionandoras-project/setup-oras;both run on moving tags and receive the job token, which has
packages: write.dependency-snapshot: trueneedscontents: writeon the build job — a permissions changefor that follow-up to state. Nothing reads these SBOMs yet; the dependency graph would be
the first consumer.
setup-oras@v2installs only the versions in its bundled list, which stops at 1.3.4.Review
Opus review of 20 Oct (two should-fix findings, one nit) applied in 296fb6c and 67589e6.
43b27cb pins ORAS to 1.3.1, because
setup-oras@v2cannot install 1.3.5 yet (that pin made run39427207465 fail at
Set up ORAS). e4ee960 stops promising that identical sources always give anidentical image.
🤖 Generated with Claude Code