mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-05 16:37:46 +00:00
ci: daily cache-bust the Alpine apk upgrade layer (#491)
The runtime stage's `apk upgrade --no-cache` layer was being reused from the buildx gha/registry cache indefinitely, so newly-patched Alpine packages (e.g. openssl CVE fixes) could sit behind a stale layer until an unrelated Dockerfile change invalidated it by coincidence. This surfaced as Trivy hard-failing on CVE-2026-28390 (libcrypto3/libssl3 DoS in CMS) on the github-app-token-migration PR, even though upstream Alpine had already published 3.5.6-r0 with the fix. Add an APK_CACHE_BUST build-arg that CI sets to the current UTC date (YYYY-MM-DD). Each calendar day the arg value changes, which changes the RUN layer's hash, which forces buildx to re-execute `apk upgrade` and pick up whatever Alpine has published that day. All three build invocations (PR docker-validate, release pre-publish scan, release multi-arch push) pass the same value, so the scan and the published artifact always share a layer and Trivy never scans stale bits. Default value `unset` lets local developers `docker build` without the arg; production CI always supplies the date.
This commit is contained in:
@@ -131,6 +131,14 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
# Computed once per job run. Feeds Dockerfile's APK_CACHE_BUST arg so
|
||||
# the `apk upgrade` layer rebuilds at least once per calendar day, even
|
||||
# when every other input to the layer is cached. See Dockerfile:115-122
|
||||
# for the rationale.
|
||||
- name: Compute daily apk cache bust value
|
||||
id: apk-bust
|
||||
run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build Docker image (validation only)
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
@@ -140,6 +148,8 @@ jobs:
|
||||
tags: sencho:pr-test
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}
|
||||
|
||||
- name: Scan image for vulnerabilities (Trivy)
|
||||
# Hard-fails the PR on any HIGH or CRITICAL finding that is not listed
|
||||
|
||||
@@ -38,6 +38,15 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
# Computed once per job run. Feeds Dockerfile's APK_CACHE_BUST arg so
|
||||
# the `apk upgrade` layer rebuilds at least once per calendar day, even
|
||||
# when every other input to the layer is cached. See Dockerfile:115-122
|
||||
# for the rationale. Both the pre-publish scan build and the multi-arch
|
||||
# push build below consume this so Trivy scans a fresh layer.
|
||||
- name: Compute daily apk cache bust value
|
||||
id: apk-bust
|
||||
run: echo "date=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
@@ -88,6 +97,8 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
tags: localhost/sencho:release-scan
|
||||
cache-from: type=registry,ref=saelix/sencho:buildcache
|
||||
build-args: |
|
||||
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}
|
||||
|
||||
- name: Re-scan release image for vulnerabilities (Trivy)
|
||||
# Gates the release on the same HIGH/CRITICAL policy as the PR scan.
|
||||
@@ -139,6 +150,8 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=saelix/sencho:buildcache
|
||||
cache-to: type=registry,ref=saelix/sencho:buildcache,mode=max
|
||||
build-args: |
|
||||
APK_CACHE_BUST=${{ steps.apk-bust.outputs.date }}
|
||||
# SBOM + provenance attestations are embedded as OCI referrers on the
|
||||
# published image. Inspect with: docker buildx imagetools inspect <img>
|
||||
sbom: true
|
||||
|
||||
+11
-1
@@ -112,9 +112,19 @@ FROM node:22-alpine
|
||||
ARG DOCKER_VERSION=29.3.1
|
||||
ARG COMPOSE_VERSION=v5.1.1
|
||||
|
||||
# Daily cache-bust for the apk upgrade layer. CI passes the current date
|
||||
# (YYYY-MM-DD) as a build-arg, so this RUN layer's hash changes at most
|
||||
# once per calendar day. Without this, buildx reuses the cached layer
|
||||
# indefinitely and a new Alpine package fix (e.g. an openssl CVE patched
|
||||
# upstream in alpine 3.23) sits behind the stale cache until an unrelated
|
||||
# change invalidates this line by coincidence. Default value lets local
|
||||
# developers build without the arg; production CI always sets it.
|
||||
ARG APK_CACHE_BUST=unset
|
||||
|
||||
# Upgrade all Alpine system packages, install runtime deps, then fetch Docker
|
||||
# CLI + Compose plugin from official static binaries.
|
||||
RUN apk upgrade --no-cache && \
|
||||
RUN echo "apk cache bust: ${APK_CACHE_BUST}" && \
|
||||
apk upgrade --no-cache && \
|
||||
apk add --no-cache bash su-exec curl && \
|
||||
ARCH=$(uname -m) && \
|
||||
curl -fsSL "https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz" \
|
||||
|
||||
Reference in New Issue
Block a user