From dd7a2eab5f6d73f3dcee7d279575fd124001cea0 Mon Sep 17 00:00:00 2001 From: Jakob Wennberg Date: Mon, 31 Aug 2026 09:58:55 +0100 Subject: [PATCH] fix(docker): bump node:22-alpine digest so the frozen apk-upgrade layer re-runs (CVE-2026-14456) (#2071) The scheduled image scan has been red since 2026-08-30 on fixable HIGH CVE-2026-14456 (libssl3/libcrypto3 3.5.7-r0, fixed 3.5.8-r0). Both Dockerfile stages already run apk upgrade, but the GHCR buildx layer cache freezes that layer, so post-pin fixes never reach the published image. Bumping the pinned FROM digest (alpine 3.23 to 3.24.1) busts the cache and the re-run upgrade installs 3.5.8-r0 (verified in both new bases). cron.Dockerfile gains the same apk upgrade line. --- DECISIONS.md | 1 + Dockerfile | 4 ++-- docker/cron.Dockerfile | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 04b21b8d..c25b5d71 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1380,3 +1380,4 @@ One line per decision: `[YYYY-MM-DD] : `. Appended by agents and [2026-08-30] Receipt-hunt excludes prominent-amounts fallback candidates (amountSource tag on UnderlagCandidate): the nightly hunt scans outflows only and its 0.8 skip-adjudication threshold was calibrated for invoice totals, so a fallback pair (0.85 on date+printed-figure, no merchant) would auto-classify certain on a wrong-by-construction pairing. Fallback docs stay reachable via picker + agent candidates. [2026-08-31] Re-versioned the ignore_transaction CHECK pair to 20260831070000/070001 and rebuilt its value list from main's 20260830160000: three op-type CHECK pairs (book_skattekonto 130000, delete_draft_invoice 150000, update_salary_run 160000) landed on main after this branch's pair was written, and a wholesale re-created CHECK from a stale list applying last would silently revoke those op types on prod (the standing migration hazard from the #1411 rebuild). [2026-08-31] Login/register methods come from GoTrue (/auth/v1/settings + admin customProviders) instead of app-side flags; NEXT_PUBLIC_GOOGLE_AUTH_ENABLED removed (PR #1869): the Supabase dashboard becomes the single switch, an allowlist of auth-js provider ids filters non-login entries like anonymous_users, and hosted rendering is unchanged because Google is enabled in prod GoTrue. The Vercel env var stays set for old-build rollback safety; delete it after a few deploys. +[2026-08-31] Image-scan red fixed by bumping the node:22-alpine digest (alpine 3.23 to 3.24.1), not by widening the gate: the Dockerfile's apk-upgrade layer is frozen by the GHCR buildx layer cache, so a fix published after the last cache-busting change (libssl3 3.5.8-r0 for CVE-2026-14456) never reaches the published image until the FROM digest moves; the red scheduled scan is the designed alarm for exactly this bump. cron.Dockerfile gained the same apk upgrade (it had none). diff --git a/Dockerfile b/Dockerfile index bc9e4c63..a2f4586b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # ── Stage 1: Base ── -FROM node:22-alpine@sha256:968df39aedcea65eeb078fb336ed7191baf48f972b4479711397108be0966920 AS base +FROM node:22-alpine@sha256:c610fcdfb1d5b4740dd70c284ed3cb16bb857e0f7166196e36a5501df7a3aa32 AS base # `apk upgrade` patches OS packages (e.g. libssl3/libcrypto3) that have fixes # published after the pinned base digest was built, so the Trivy image scan in # CI doesn't fail on fixable Alpine CVEs. The digest stays pinned for a @@ -54,7 +54,7 @@ ENV NEXT_TELEMETRY_DISABLED=1 RUN npm run build # ── Stage 4: Runner ── -FROM node:22-alpine@sha256:968df39aedcea65eeb078fb336ed7191baf48f972b4479711397108be0966920 AS runner +FROM node:22-alpine@sha256:c610fcdfb1d5b4740dd70c284ed3cb16bb857e0f7166196e36a5501df7a3aa32 AS runner WORKDIR /app # Patch OS packages (libssl3/libcrypto3, …) with fixes published after the diff --git a/docker/cron.Dockerfile b/docker/cron.Dockerfile index 1a60c550..40e82206 100644 --- a/docker/cron.Dockerfile +++ b/docker/cron.Dockerfile @@ -11,7 +11,11 @@ ARG SUPERCRONIC_SHA256_AMD64=feefa310da569c81b99e1027b86b27b51e6ee9ab647747b4909 ARG SUPERCRONIC_SHA256_ARM64=f1f8585c66de020fef494dd636058f99949d108f569fef00016a1c8b9eb145b3 # curl stays in the image: the crontab uses it at runtime to call the app. -RUN apk add --no-cache curl \ +# `apk upgrade` first: it patches OS packages (e.g. libssl3/libcrypto3) that +# have fixes published after the pinned base digest was built, same rationale +# as the main Dockerfile. The digest stays pinned; only security patches float. +RUN apk upgrade --no-cache \ + && apk add --no-cache curl \ && case ${TARGETARCH} in \ amd64) ARCH=linux-amd64; SHA=${SUPERCRONIC_SHA256_AMD64} ;; \ arm64) ARCH=linux-arm64; SHA=${SUPERCRONIC_SHA256_ARM64} ;; \