fix: More fixes to vuln matching
Chart Release / chart (push) Successful in 31s
Server Deploy / deploy (push) Successful in 1m42s

This commit is contained in:
2026-08-07 13:29:15 +01:00
parent e28238191d
commit 78f1bf853c
+56 -1
View File
@@ -47,7 +47,7 @@ func Match(src AdvisorySource, os models.OSRelease, pkgs []models.InstalledPacka
cache := make(map[string][]Advisory, len(pkgs))
var out []Result
for _, p := range pkgs {
for _, p := range newestPerSource(os.Family, pkgs) {
// Debian and Ubuntu advisories are keyed on the source package: one
// advisory against "openssl" covers libssl3, openssl and libssl-dev.
srcName := p.SourceName
@@ -111,6 +111,61 @@ func Match(src AdvisorySource, os models.OSRelease, pkgs []models.InstalledPacka
return out, nil
}
// newestPerSource collapses the installed set to one binary package per source
// package: the one carrying the highest version.
//
// Advisories are keyed on the source, so every binary package of a source asks
// the same question. Normally they all carry the same version and the answer is
// the same, so collapsing is free. The kernel is the exception that makes it
// necessary: Ubuntu encodes the ABI in the binary name, so an upgrade INSTALLS
// linux-headers-6.8.0-137 beside linux-headers-6.8.0-124 rather than replacing
// it, and the old one lingers until an autoremove. Matched per binary package,
// a fully patched host reports every superseded ABI package as vulnerable —
// which is the noise this exists to stop — and reports it twice over, once for
// linux-headers-6.8.0-124 and again for its -generic sibling.
//
// The version, not the name, decides. There is no kernel special case here: a
// source's newest installed version is what the fix landed as, whatever the
// source is.
//
// A comparison that cannot be made keeps the incumbent rather than guessing;
// the loser is dropped either way, and dropping the parseable one would be the
// false-negative direction.
func newestPerSource(family string, pkgs []models.InstalledPackage) []models.InstalledPackage {
best := make(map[string]models.InstalledPackage, len(pkgs))
order := make([]string, 0, len(pkgs))
for _, p := range pkgs {
src := p.SourceName
if src == "" {
src = p.Name
}
cur, seen := best[src]
if !seen {
best[src] = p
order = append(order, src)
continue
}
older, err := LessThan(family, cur.Version, p.Version)
if err != nil {
log.Printf("vulndb: newest for source %s: compare %s vs %s: %v",
src, cur.Version, p.Version, err)
continue
}
if older {
Debugf("source %s: %s %s supersedes %s %s",
src, p.Name, p.Version, cur.Name, cur.Version)
best[src] = p
}
}
out := make([]models.InstalledPackage, 0, len(order))
for _, src := range order {
out = append(out, best[src])
}
return out
}
// actionable decides whether an advisory with no fixed version is a finding.
//
// trivy-db fills Status only when FixedVersion is empty, and Ubuntu publishes a