Repository navigation
fix(security): clear all .trivyignore exceptions by rebuilding the postgres and restic images (#1001) - #1041
RonaldHensbergen wants to merge 5 commits into
Conversation
…stgres and restic images (#1001) The trivyignore audit listed 34 exceptions as still reported although fixed package versions exist. A base-digest bump alone cannot clear them: the postgres:18 image ships a prebuilt gosu binary (no tag rebuilds it with a fixed Go toolchain), and restic 0.19.1 is still the latest upstream release whose published binary is built with vulnerable Go modules. - images/postgres/Dockerfile: pin the current postgres:18 digest (979bccf..., 2026-10-28) in the Dockerfile and modules/warehouse/postgres/module.yaml (plus the gitignored local docker-compose.yml / .cds profile), and replace the base image's gosu with a build from the pinned gosu 1.20 tag compiled with Go 1.27.3 in a digest-pinned golang builder stage. - images/restic/Dockerfile: compile restic v0.19.1 from source with Go 1.27.3 and the fixed module versions (go-jose/v4 4.1.6, klauspost/compress 1.18.7, x/crypto 0.57.0, x/net 0.60.0, x/text 0.42.0, grpc 1.83.2) on a digest-pinned alpine:3.24 base instead of using the prebuilt restic/restic image. - .trivyignore: drop all 34 resolved entries (26 gosu/stdlib CVEs, 8 restic module advisories incl. GHSA-hrxh-6v49-42gf); header comment kept. - publish-images.yml: derive the restic base version from the new ARG RESTIC_VERSION pin (the restic/restic FROM line is gone). - renovate.json: regex managers track ARG GOSU_VERSION (tianon/gosu), ARG RESTIC_VERSION (restic/restic) and the go-get module pins (golang datasource) so the source pins stay current. - Makefile: add dbt/dlt/restic to the docker-build repo-root context case list, matching docker-smoke-test.yml (their COPY paths are repo-root relative; drive-by fix). - tests/test_image_digest_check.py: example pin updated to the new digest. - CHANGELOG.md: Unreleased entry. Verified locally with Trivy v0.75.0 (same invocation as the scan workflow): both rebuilt images pass the HIGH/CRITICAL gate with --ignore-unfixed and the now-empty .trivyignore (exit 0); the audit script reports no remaining entries; all 34 audited IDs are absent from the rebuilt images and no new findings appear. Full test suite: 1971 passed, 24 skipped. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
markdownlint MD012/no-multiple-blanks failed the CI lint job on CHANGELOG.md:90; the entry is now followed by a single blank line. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
RonaldHensbergen
left a comment
There was a problem hiding this comment.
Review summary
Quality verdict: merge-ready. No blocking or major findings; three minor inline notes (one awareness item on the merge window, two optional supply-chain hardening suggestions). No open points remain.
Note on process: this PR is authored under my own account, so GitHub rejects a formal self-APPROVE ("Can not approve your own pull request"). I therefore submit this as COMMENT; the merge-readiness judgment above stands on the evidence listed, and the formal approve/merge still needs the requested reviewer (SemTiOne) or an admin merge.
Verified
- CI on head f3e3d64: all 23 check runs green, including "scan (postgres, images/postgres/Dockerfile)" and "scan (restic, images/restic/Dockerfile)" — the Trivy v0.75.0 HIGH/CRITICAL gate (--ignore-unfixed --ignorefile .trivyignore --exit-code 1) on the rebuilt images with the now-empty .trivyignore — plus build-images, lint, audit, smoke-test, test (ubuntu/macos/windows, 3.14), and sonarcloud (Quality Gate passed).
- Local tests: tests/test_image_digest_check.py + tests/test_trivyignore.py (25 passed); tests/test_publish_images_workflow.py + tests/test_image_security_scan_workflow.py + tests/test_image_verification.py (97 passed, 15 subtests).
- Audit mapping (#1001): all 34 audit entries map to the fix — the 26 gosu/stdlib findings (prebuilt gosu built with go1.24.6) are cleared by building gosu 1.20 from source with Go 1.27.3 (1.27.3 is among the audit fixed stdlib versions); the 8 restic module findings are covered by the "go get" pins (x/net v0.60.0, compress v1.18.7, x/crypto v0.57.0, x/text v0.42.0, grpc v1.83.2, go-jose/v4 v4.1.6 — each >= the audit fixed versions).
- Upstream artifacts current: gosu tag 1.20, restic v0.19.1 (latest release, 2026-07-05), go1.27.3 (2026-10-19), alpine 3.24; the digest-pinned bases resolve (build-images pulled them).
- Publish tag scheme unchanged: the restic case in publish-images.yml now reads "ARG RESTIC_VERSION=0.19.1" -> "0.19.1", identical to the old "FROM restic/restic:0.19.1@..." extraction; the postgres case still greps "^FROM postgres:" (the gosu stage is "FROM golang:... AS gosu", no collision).
- Makefile drive-by fix matches docker-smoke-test.yml:31, image-security-scan.yml and publish-images.yml — repo-root build context for dbt/dlt/postgres/restic, whose COPY paths are repo-root relative.
- Dropping the upstream restic image ENTRYPOINT is safe: modules/backup/restic/module.yaml sets entrypoint [cds-restic-scheduler] / [cds-restic-restore] explicitly on both services; the scripts invoke "restic" via PATH -> /usr/bin/restic (COPY target). The postgres base ENTRYPOINT/CMD is untouched and gosu 1.20 is a compatible drop-in for the entrypoint script.
- renovate.json: three regex managers valid and scoped via managerFilePatterns; the module-pin regex matches only the six "go get" entries (@sha256: digests do not match @v...). CI lint-renovate clean.
- No stale references: old digests 32ca0af.../136600b... gone from all tracked files; docker-compose.yml and .cds/haven-dev-noinit.yml are gitignored (git check-ignore confirms), so their absence from the PR is correct; tests/fixtures/signed-images.json tracks published cds images, not the upstream base digest — no PR-time fixture change needed.
- Conventions: CHANGELOG entry under [Unreleased] -> ### Fixed with single-blank-line separation; no new E-/W-codes in the diff (none needed — no renderer changes); docs/image-scanning.md describes the exception mechanism generically (no hardcoded counts), so the header-only .trivyignore is consistent and test_trivyignore.py passes on it; image READMEs updated; markdownlint clean in CI.
- Precedent: removing entries at PR time matches #934 (3f50f4b); the PR-time scan gate is the merge-time proof and the push-to-main publish republishes immediately after merge.
Findings
- minor (non-blocking) — merge window vs. signed-images fixture: see the inline comment on .trivyignore.
- minor (optional) — content-hash pinning of the gosu/restic source tarballs: see the inline comments on both Dockerfiles.
Geen openstaande punten meer; de PR is naar mijn oordeel merge-klaar.
…56 in the image builds (#1041) Address the review hardening notes on #1041: the codeload tarballs for GOSU_VERSION and RESTIC_VERSION are now downloaded to a file and checked with sha256sum -c against GOSU_TARBALL_SHA256 / RESTIC_TARBALL_SHA256 before extraction, so the build fails closed on a tag re-point or a compromised codeload response. No Renovate datasource covers codeload tarball hashes, so the sha256 ARGs are documented as manual companions of the version ARGs (renovate.json descriptions, image READMEs) and the CHANGELOG entry notes the pinning. Hashes verified stable across two independent downloads and both images build and run locally with the pins (gosu 1.20 go1.27.3, restic 0.19.1 go1.27.3); a wrong --build-arg hash fails the build at the checksum step. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Review comments addressedAll three inline threads from the review are now replied to and resolved:
Both sha256 ARGs are documented as manual companions of the version ARGs (Dockerfile comments, renovate.json manager descriptions, image READMEs), and the CHANGELOG entry mentions the pinning. Local verification on 31ad353: 1908 passed / 29 skipped (tests/test_cds_runtime.py needs SQLAlchemy, not installed in this sandbox — CI covers it), renovate.json valid, both images build with the pins. |
|



Closes #1001.
The trivyignore audit listed 34 exceptions as still reported although fixed package versions exist. A base-digest bump alone cannot clear them:
postgres:18image ships a prebuilt gosu binary — no tag (trixie/bookworm/alpine) rebuilds it with a fixed Go toolchain, so all 26 Go stdlib CVEs againstusr/local/bin/gosupersist in every current digest;restic/restic:0.19.1is still the latest upstream release (GitHub and Docker Hub), and its published binary is built with vulnerable Go modules, so no upstream image refresh can clear those 8 findings.Changes
images/postgres/Dockerfile: pin the currentpostgres:18digest (979bccf…, 2026-10-28; also updated inmodules/warehouse/postgres/module.yamland the local gitignoreddocker-compose.yml/.cds/haven-dev-noinit.yml) and replace gosu with a source build from the pinnedGOSU_VERSION=1.20tag compiled with Go 1.27.3 in a digest-pinnedgolang:1.27.3-alpinestage.images/restic/Dockerfile: compile restic from source —RESTIC_VERSION=0.19.1tarball +go getof the fixed module versions (go-jose/v4v4.1.6,klauspost/compressv1.18.7,x/cryptov0.57.0,x/netv0.60.0,x/textv0.42.0,grpcv1.83.2) + Go 1.27.3, on a digest-pinnedalpine:3.24base instead of the prebuiltrestic/resticimage..trivyignore: all 34 resolved entries removed (header comment kept, matching the [trivyignore-audit] Resolved or expiring vulnerability exceptions #934 precedent).publish-images.yml: restic base version now read fromARG RESTIC_VERSION=(theFROM restic/restic:line is gone); tag scheme unchanged (0.19.1-…).renovate.json: regex managers keepGOSU_VERSION,RESTIC_VERSIONand thego getmodule pins tracked (docker/golang datasources).Makefile:docker-buildrepo-root context case list now matchesdocker-smoke-test.yml(adds dbt/dlt/restic — drive-by fix, their COPY paths are repo-root relative).tests/test_image_digest_check.pyexample pin +CHANGELOG.mdUnreleased entry.Verification (local, same Trivy v0.75.0 invocation as the scan workflow)
cds/postgres:scan→ all 26 gosu/stdlib CVEs gone, gosu target clean, no new findings (17 remaining OS findings are allaffected/fix_deferredwith no fixed version → ignored by--ignore-unfixed);cds/restic:scan→ 0 HIGH/CRITICAL.trivy image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --ignorefile .trivyignore --exit-code 1→ exit 0 for both images.scripts/audit_trivyignore.pyon the new reports: no entries left to flag.gosu 1.20 (go1.27.3),restic 0.19.1 compiled with go1.27.3.renovate-config-validator --strictclean; markdownlint clean on changed md files.Note: the audit covers published digests, so the audit issue will fully clear after
publish-images.ymlrepublishes these images on merge; the PR-time scan gate above is the merge-time proof.