Skip to content

fix(security): clear all .trivyignore exceptions by rebuilding the postgres and restic images (#1001) - #1041

Merged
RonaldHensbergen merged 6 commits into
mainfrom
fix/1001-trivyignore-audit
Oct 31, 2026
Merged

RonaldHensbergen merged 6 commits into
mainfrom
fix/1001-trivyignore-audit

Conversation

@RonaldHensbergen

Copy link
Copy Markdown
Owner

Closes #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 (trixie/bookworm/alpine) rebuilds it with a fixed Go toolchain, so all 26 Go stdlib CVEs against usr/local/bin/gosu persist in every current digest;
  • restic/restic:0.19.1 is 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 current postgres:18 digest (979bccf…, 2026-10-28; also updated in modules/warehouse/postgres/module.yaml and the local gitignored docker-compose.yml / .cds/haven-dev-noinit.yml) and replace gosu with a source build from the pinned GOSU_VERSION=1.20 tag compiled with Go 1.27.3 in a digest-pinned golang:1.27.3-alpine stage.
  • images/restic/Dockerfile: compile restic from source — RESTIC_VERSION=0.19.1 tarball + go get of the fixed module versions (go-jose/v4 v4.1.6, klauspost/compress v1.18.7, x/crypto v0.57.0, x/net v0.60.0, x/text v0.42.0, grpc v1.83.2) + Go 1.27.3, on a digest-pinned alpine:3.24 base instead of the prebuilt restic/restic image.
  • .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 from ARG RESTIC_VERSION= (the FROM restic/restic: line is gone); tag scheme unchanged (0.19.1-…).
  • renovate.json: regex managers keep GOSU_VERSION, RESTIC_VERSION and the go get module pins tracked (docker/golang datasources).
  • Makefile: docker-build repo-root context case list now matches docker-smoke-test.yml (adds dbt/dlt/restic — drive-by fix, their COPY paths are repo-root relative).
  • tests/test_image_digest_check.py example pin + CHANGELOG.md Unreleased entry.

Verification (local, same Trivy v0.75.0 invocation as the scan workflow)

  • Built both images from the repo root: cds/postgres:scan → all 26 gosu/stdlib CVEs gone, gosu target clean, no new findings (17 remaining OS findings are all affected/fix_deferred with no fixed version → ignored by --ignore-unfixed); cds/restic:scan → 0 HIGH/CRITICAL.
  • CI gate reproduction: trivy image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed --ignorefile .trivyignore --exit-code 1 → exit 0 for both images.
  • scripts/audit_trivyignore.py on the new reports: no entries left to flag.
  • Binaries run: gosu 1.20 (go1.27.3), restic 0.19.1 compiled with go1.27.3.
  • Full test suite: 1971 passed, 24 skipped; renovate-config-validator --strict clean; markdownlint clean on changed md files.

Note: the audit covers published digests, so the audit issue will fully clear after publish-images.yml republishes these images on merge; the PR-time scan gate above is the merge-time proof.

…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>
RonaldHensbergen and others added 2 commits October 30, 2026 23:47
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 RonaldHensbergen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread .trivyignore Resolved
Comment thread images/postgres/Dockerfile Resolved
Comment thread images/restic/Dockerfile Resolved
…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>

Copy link
Copy Markdown
Owner Author

Review comments addressed

All three inline threads from the review are now replied to and resolved:

  • .trivyignore merge-window note — awareness only, no change (accepted [trivyignore-audit] Resolved or expiring vulnerability exceptions #934 pattern); resolved as noted.
  • gosu tarball sha256 (images/postgres/Dockerfile) — fixed in 31ad353: GOSU_TARBALL_SHA256 verified with sha256sum -c before extraction; build proven locally (succeeds with the pin, fails closed with a wrong hash; gosu 1.20 (go1.27.3) runs).
  • restic tarball sha256 (images/restic/Dockerfile) — fixed in 31ad353: RESTIC_TARBALL_SHA256 verified the same way; image builds and restic 0.19.1 compiled with go1.27.3 runs.

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.

RonaldHensbergen and others added 2 commits October 31, 2026 14:10
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
@sonarqubecloud

Copy link
Copy Markdown

@RonaldHensbergen
RonaldHensbergen merged commit 838366b into main Oct 31, 2026
25 checks passed
@RonaldHensbergen
RonaldHensbergen deleted the fix/1001-trivyignore-audit branch October 31, 2026 13:58
RonaldHensbergen added a commit that referenced this pull request Oct 31, 2026
Resolve the CHANGELOG.md [Unreleased] conflict with #1041 by keeping
both Fixed entries.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[trivyignore-audit] Resolved or expiring vulnerability exceptions

1 participant