fix(ci): pass trivy image scans
CI / secrets-scan (push) Successful in 6s
CI / sast (push) Successful in 13s
CI / vuln-scan (push) Successful in 15s
CI / build-images (push) Successful in 3m22s
CI / test (push) Successful in 26s
CI / lint (push) Successful in 28s
CI / push (push) Has been skipped
CI / image-scan (push) Failing after 16s
CI / secrets-scan (push) Successful in 6s
CI / sast (push) Successful in 13s
CI / vuln-scan (push) Successful in 15s
CI / build-images (push) Successful in 3m22s
CI / test (push) Successful in 26s
CI / lint (push) Successful in 28s
CI / push (push) Has been skipped
CI / image-scan (push) Failing after 16s
Three independent issues caused 35 + 15 HIGH/CRITICAL findings: 1. Client base — nginx:1.27-alpine pulled Alpine 3.21.3, which carries old libcrypto3/libssl3/libpng/libxml2/musl/nghttp2/zlib. Bumped to nginx:1.29-alpine and added `apk update && apk upgrade --no-cache` so the layer pulls every available patch in the current Alpine repo. Verified: 0 findings. 2. Server runtime — npm/yarn/corepack ship bundled inside the node:20-alpine image at /usr/local/lib/node_modules/npm/... They drag in cross-spawn, glob, minimatch, tar, and friends — all of which had HIGH CVEs. We never invoke them at runtime (CMD is `node dist/main.js`); deleting them in the runtime stage cuts 11 of the 15 findings. Also added `apk upgrade` for parity with the client. 3. Multer transitive — @nestjs/platform-express pulls in multer 2.0.2 which has three HIGH CVEs (fixed in 2.1.1). Added a pnpm `overrides` entry to pin it. For the remaining lodash CVE-2026-4800: Trivy lists 4.18.0 as the fixed version, but that release isn't published on npm. Added .trivyignore + wired --ignorefile into the trivy invocations, with a comment explaining why and when to re-evaluate. Verification (local builds + trivy scans): - teh-riehl-server: 0 HIGH/CRITICAL across all targets. - teh-riehl-client: 0 vulnerabilities (alpine 3.23.4). - Server boots, /api/health returns ok. - Client serves /config.js with APP_API_BASE_URL override. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -276,9 +276,11 @@ jobs:
|
||||
# failure is visible inline (the SARIF run below writes only to file).
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v "$PWD:/src" \
|
||||
aquasec/trivy:latest image \
|
||||
--severity HIGH,CRITICAL \
|
||||
--ignore-unfixed \
|
||||
--ignorefile /src/.trivyignore \
|
||||
--format table \
|
||||
tehriehlincremental-server:${SHA_SHORT} || true
|
||||
# Real gate + SARIF artifact.
|
||||
@@ -289,6 +291,7 @@ jobs:
|
||||
--severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
--ignore-unfixed \
|
||||
--ignorefile /src/.trivyignore \
|
||||
--format sarif --output /src/trivy-image-server.sarif \
|
||||
tehriehlincremental-server:${SHA_SHORT}
|
||||
|
||||
@@ -297,9 +300,11 @@ jobs:
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v "$PWD:/src" \
|
||||
aquasec/trivy:latest image \
|
||||
--severity HIGH,CRITICAL \
|
||||
--ignore-unfixed \
|
||||
--ignorefile /src/.trivyignore \
|
||||
--format table \
|
||||
tehriehlincremental-client:${SHA_SHORT} || true
|
||||
docker run --rm \
|
||||
@@ -309,6 +314,7 @@ jobs:
|
||||
--severity HIGH,CRITICAL \
|
||||
--exit-code 1 \
|
||||
--ignore-unfixed \
|
||||
--ignorefile /src/.trivyignore \
|
||||
--format sarif --output /src/trivy-image-client.sarif \
|
||||
tehriehlincremental-client:${SHA_SHORT}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Trivy CVE allowlist.
|
||||
# Format: one CVE ID per line, comments allowed. Used by both fs and image scans.
|
||||
#
|
||||
# Each entry below MUST cite why we can't simply upgrade. Re-evaluate quarterly
|
||||
# (or whenever the fixed version actually publishes to npm).
|
||||
|
||||
# lodash CVE-2026-4800: Trivy lists 4.18.0 as the fixed version, but that
|
||||
# release does not exist on npm (latest stable is still 4.17.21). lodash is
|
||||
# pulled in transitively via @nestjs's dependency chain; nothing in our code
|
||||
# imports it directly. Re-check when 4.18.0 is actually published.
|
||||
CVE-2026-4800
|
||||
@@ -25,5 +25,10 @@
|
||||
"prettier": "^3.3.3",
|
||||
"typescript": "^5.6.2",
|
||||
"typescript-eslint": "^8.8.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"multer": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,13 @@ COPY packages/client packages/client
|
||||
RUN pnpm --filter @teh-riehl/client build
|
||||
|
||||
# ---- Runtime ----------------------------------------------------------------
|
||||
FROM nginx:1.27-alpine AS runtime
|
||||
FROM nginx:1.29-alpine AS runtime
|
||||
|
||||
# Pull the latest patched system packages BEFORE copying app content, so the
|
||||
# layer cache for our content stays small and we only re-fetch upgrades when
|
||||
# the base image moves. Knocks out the libcrypto/libpng/libxml/musl/nghttp2
|
||||
# /zlib HIGH+CRITICAL vulns that ship in the unpatched base.
|
||||
RUN apk update && apk upgrade --no-cache && rm -rf /var/cache/apk/*
|
||||
|
||||
# Static SPA + custom nginx config + the runtime-config entrypoint.
|
||||
COPY --from=builder /repo/packages/client/dist /usr/share/nginx/html
|
||||
|
||||
@@ -57,7 +57,21 @@ RUN set -eux; \
|
||||
|
||||
# ---- Runtime ----------------------------------------------------------------
|
||||
FROM node:20-alpine AS runtime
|
||||
RUN apk add --no-cache openssl tini
|
||||
|
||||
# Patch the base image, install runtime-only system deps, and strip out the
|
||||
# npm/yarn/corepack CLI bundles. We never invoke any of those at runtime
|
||||
# (CMD is `node dist/main.js`) and their bundled deps (cross-spawn, glob,
|
||||
# minimatch, tar, etc.) drag in a long list of HIGH-severity CVEs that
|
||||
# would fail the image scan.
|
||||
RUN apk update && apk upgrade --no-cache && \
|
||||
apk add --no-cache openssl tini && \
|
||||
rm -rf /usr/local/lib/node_modules/npm \
|
||||
/usr/local/lib/node_modules/corepack \
|
||||
/usr/local/bin/npm \
|
||||
/usr/local/bin/npx \
|
||||
/usr/local/bin/corepack \
|
||||
/opt/yarn-v* \
|
||||
/var/cache/apk/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /deploy/node_modules ./node_modules
|
||||
|
||||
Generated
+7
-21
@@ -4,6 +4,9 @@ settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
multer: ^2.1.1
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -2855,18 +2858,14 @@ packages:
|
||||
resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
|
||||
ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
|
||||
ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
|
||||
multer@2.0.2:
|
||||
resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==}
|
||||
multer@2.1.1:
|
||||
resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==}
|
||||
engines: {node: '>= 10.16.0'}
|
||||
|
||||
mute-stream@0.0.8:
|
||||
@@ -3925,10 +3924,6 @@ packages:
|
||||
xmlchars@2.2.0:
|
||||
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
|
||||
|
||||
xtend@4.0.2:
|
||||
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
|
||||
@@ -4427,7 +4422,7 @@ snapshots:
|
||||
body-parser: 1.20.4
|
||||
cors: 2.8.5
|
||||
express: 4.22.1
|
||||
multer: 2.0.2
|
||||
multer: 2.1.1
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -6628,23 +6623,16 @@ snapshots:
|
||||
|
||||
minipass@7.1.3: {}
|
||||
|
||||
mkdirp@0.5.6:
|
||||
dependencies:
|
||||
minimist: 1.2.8
|
||||
|
||||
ms@2.0.0: {}
|
||||
|
||||
ms@2.1.3: {}
|
||||
|
||||
multer@2.0.2:
|
||||
multer@2.1.1:
|
||||
dependencies:
|
||||
append-field: 1.0.0
|
||||
busboy: 1.6.0
|
||||
concat-stream: 2.0.0
|
||||
mkdirp: 0.5.6
|
||||
object-assign: 4.1.1
|
||||
type-is: 1.6.18
|
||||
xtend: 4.0.2
|
||||
|
||||
mute-stream@0.0.8: {}
|
||||
|
||||
@@ -7680,8 +7668,6 @@ snapshots:
|
||||
|
||||
xmlchars@2.2.0: {}
|
||||
|
||||
xtend@4.0.2: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
Reference in New Issue
Block a user