Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/build-nocache.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
packages: write
env:
DOCKER_REPOSITORY: ghcr.io/dfe-digital/check-performance-data
WORKER_DOCKER_REPOSITORY: ghcr.io/dfe-digital/check-performance-data-worker
outputs:
docker-image-tag: ${{ steps.build-image.outputs.tag }}
runs-on: ubuntu-latest
Expand Down Expand Up @@ -42,6 +43,28 @@ jobs:
name: web
github-token: ${{ secrets.GITHUB_TOKEN }}

# The worker image installs curl, so it gets OS package fixes that the web image does not.
# Rebuild it here too, or its cached package layer stays old until its base digest changes.
- name: Build without cache and push worker docker image
id: build-worker-image
uses: DFE-Digital/github-actions/build-docker-image@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
context: ./src
dockerfile-path: ./src/DfE.CheckPerformanceData.RulesEngineWorker/Dockerfile
target: final
docker-repository: ${{ env.WORKER_DOCKER_REPOSITORY }}
max-cache: true
reuse-cache: false
snyk-token: ${{ secrets.SNYK_TOKEN }}

- name: SBOM for the worker image
uses: ./.github/actions/image-sbom
with:
image: ${{ steps.build-worker-image.outputs.image }}
name: worker
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Notify teams channel on job failure
uses: DFE-Digital/github-actions/send-to-teams-channel@master
if: ${{ failure() }}
Expand Down
28 changes: 25 additions & 3 deletions docs/dependabot.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,31 @@ Dependabot's pull requests change the digest, and the tag if there is a newer on
republishes `10.0` with each .NET patch and Ubuntu security update.

Pinning the .NET images means the runtime patch an image ships changes only when a Dependabot
pull request is merged, not at every build. `apt-get upgrade` in the Web and worker Dockerfiles
still applies Ubuntu security updates at every build, and the weekly **Build No Cache** run still
rebuilds the web image to pick them up.
pull request is merged, not at every build. Ubuntu security updates come from `apt-get upgrade`
in the Web and worker Dockerfiles (see [OS packages](#os-packages)).

### OS packages

The `base` stage of the Web and worker Dockerfiles runs `apt-get upgrade`. The worker also
installs `curl`. This layer gets the Ubuntu security fixes that the base image does not have yet.

CI reuses this layer from its build cache, so it does not run at each build. It runs again when:

- a Dependabot pull request changes the base image digest;
- the weekly **Build No Cache** run rebuilds the web and worker images on `main`;
- the `OS_PACKAGES_DATE` build argument in the Dockerfile changes.

When the Snyk scan in the **Build** job finds a high severity issue in an Ubuntu package, do these
steps:

1. Read the "Fixed in" version in the Snyk output. Snyk shows the image name after the issue
("Target file").
2. Make sure that Ubuntu has the fix. Run
`docker run --rm --user root <base image> sh -c "apt-get update -qq; apt-cache policy <package>"`.
3. If Ubuntu has the fix, set `OS_PACKAGES_DATE` to today's date in both Dockerfiles. Merge
the change to `main`, then merge `main` into the open pull requests.
4. If Ubuntu does not have the fix ("Fixed in" is empty), the upgrade cannot help. Wait for a
new base image, or ask the team about a Snyk ignore with an end date.

### The pin check

Expand Down
9 changes: 5 additions & 4 deletions docs/sbom.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ The action that does this is `.github/actions/image-sbom`, called after each ima
## Finding the SBOM for a deployed environment

Go by the image **digest** the running pods report, not by the sha tag: the weekly
`Build No Cache` run rebuilds the web image and moves the sha tag to the new image without
redeploying anything, so a running environment can be on an earlier digest than its tag.
`Build No Cache` run rebuilds the web and worker images and moves each sha tag to the new image
without redeploying anything, so a running environment can be on an earlier digest than its tag.

1. Read the digest from the pods (the namespace and deployment names are
`schoolstandards-development` / `schoolstandards-test` / `schoolstandards-production` and
Expand Down Expand Up @@ -89,7 +89,8 @@ Or scan the whole SBOM for known vulnerabilities with [grype](https://github.com
grype sbom:./sbom-web-<sha>.cdx.json
```

The weekly `Build No Cache` run rebuilds the web image with current Ubuntu packages, pushes it
under the same sha tag and attaches a new SBOM to the new image; the earlier image keeps its own.
The weekly `Build No Cache` run rebuilds the web and worker images with current Ubuntu packages,
pushes each under the same sha tag and attaches a new SBOM to the new image; the earlier image
keeps its own.
Running pods stay on the digest they started with until the next deployment, which is why the
steps above start from the pod's digest rather than the tag.
4 changes: 4 additions & 0 deletions src/DfE.CheckPerformanceData.RulesEngineWorker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ FROM mcr.microsoft.com/dotnet/aspnet:10.0@sha256:de0ee358cdd672f7017a003bed21e9a
# `apt-get upgrade` applies Ubuntu security updates the base image has not yet
# been rebuilt with (see the Web Dockerfile for the CVE-2026-84782 example).
# curl is used by the container orchestrator's exec probe to query the HTTP health surface.
# CI reuses this layer from its build cache, so the upgrade does not run at each build. To get
# the current Ubuntu packages now, set OS_PACKAGES_DATE to today's date: a new value makes Docker
# run the layer again (docs/dependabot.md#os-packages).
ARG OS_PACKAGES_DATE=2026-10-29
RUN apt-get update \
&& apt-get upgrade -y --no-install-recommends \
&& apt-get install -y --no-install-recommends curl \
Expand Down
4 changes: 4 additions & 0 deletions src/DfE.CheckPerformanceData.Web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ FROM mcr.microsoft.com/dotnet/aspnet:10.0@sha256:de0ee358cdd672f7017a003bed21e9a
# with published fixes outstanding (e.g. libssl3t64 3.0.13-0ubuntu3.15 against
# CVE-2026-84782), and the Snyk gate in CI then fails every build. Upgrading at
# build time keeps the shipped image at the current noble-security level.
# CI reuses this layer from its build cache, so the upgrade does not run at each build. To get
# the current Ubuntu packages now, set OS_PACKAGES_DATE to today's date: a new value makes Docker
# run the layer again (docs/dependabot.md#os-packages).
ARG OS_PACKAGES_DATE=2026-10-29
RUN apt-get update \
&& apt-get upgrade -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
Expand Down
Loading