Repository navigation
fix(ci): govulncheck fails repo-wide on 3 unfixable lib/pq advisories, blocking every merge #1849
Description
Blocks every merge. Not caused by any PR.
What
Security Scanning → Run govulncheck CVE scanner (all modules) now fails on three advisories in github.com/lib/pq@v1.10.9:
| ID | Module | Fixed in |
|---|---|---|
| GO-2026-6170 | github.com/lib/pq |
N/A |
| GO-2026-6171 | github.com/lib/pq |
N/A |
| GO-2026-6172 | github.com/lib/pq |
N/A |
All three report Fixed in: N/A. No version bump clears them, now or on any schedule.
lib/pq is an indirect dependency in the root go.mod (v1.10.9 // indirect) and appears in no other module's go.mod.
Why it appeared with no code change
Same mechanism as #1829: govulncheck fetches the vulnerability database at run time, so previously-green commits turn red when advisories are published.
Evidence it is time-based rather than change-based:
main@4b2d54de7showsCI - Build & Testsuccess, but that run predates the advisories. It is green only because it has not re-run.- PR sec(ci): delete only the ECR repo each staging state owns (#1820) #1848, whose diff touches only
.github/workflows/*.ymlandscripts/test-select-ecr-repos-to-delete.shand no Go code at all, fails on this step.
The next push to main, and every PR, will fail until this is resolved.
Why this is harder than #1829
#1829 was stdlib advisories fixed in go1.26.6; a one-line toolchain bump cleared them. Here there is no fixed version to move to. The options are all judgement calls:
- Remove the dependency.
lib/pqis deprecated upstream in favour ofpgx, and this repo already usespgx(pgxpoolappears throughoutinternal/database). Determine what still pullslib/pqin: if it arrives transitively through a single dependency, bumping or replacing that dependency may drop it entirely. This is the only option that actually removes the exposure. - Establish it is unreachable and record that. Note the finding is currently failing the gate, and CI's govulncheck runs in source mode, which exits 0 when findings sit only at import/require level. That it fails implies the analysis reaches vulnerable symbols. Verify that directly before assuming otherwise, and check the binary too:
govulncheck -mode=binaryagainst/app/cudlyfrom the built image tells you whether it ships. - A narrowly justified, documented exception. Only if 1 is infeasible and 2 shows it unreachable. Not a blanket ignore list, and not
continue-on-error, which would blind the gate to everything else. This repo has been through two rounds of exactly that failure mode (sec(build): shipped image still builds on go1.26.5, so the stdlib CVEs remain in the artifact after #1832 #1833, sec(ci): nothing scans the container image we ship, only source; a baked-in vulnerable binary is invisible by construction #1836).
Do not
Suppress the whole step, add --ignore-unfixed-style narrowing to govulncheck, or set continue-on-error. The gate is the only thing standing between a fresh advisory and a silent merge, and #1836 exists because scanning gaps let two CVE rounds ship green.
Verification bar
Whatever is chosen: re-run the per-module loop at the CI-pinned govulncheck v1.1.4 and show the result, capturing exit codes into variables rather than reading a pipeline's status. If the fix is a dependency removal, prove lib/pq is absent from the module graph afterwards (go mod why / go list -m all), not merely absent from go.mod.
Related: #1829 (same mechanism, fixable by a bump), #1837 (an unfixable advisory accepted with reasoning rather than suppressed), #1836 (why scanning gaps matter here).
Activity
fix(build): build the migrate CLI from this module so its deps match …
docs: use pgx5:// in the copy-pasteable migrate commands
docs(test): correct the lib/pq advisory count in the guard's comment
test(db): assert lib/pq is absent from the build closures, not only u…