From e34c4f61a5c8851de213b5243f751f37925f15cd Mon Sep 17 00:00:00 2001 From: Hank Donnay Date: Tue, 6 Jan 2026 10:56:02 -0600 Subject: [PATCH] rpm: add common version comparison function Signed-off-by: Hank Donnay Change-Id: I5f1f740f42b9ef6a8184a73873dbed56aebb5f6d --- internal/rpm/matcher.go | 49 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 internal/rpm/matcher.go diff --git a/internal/rpm/matcher.go b/internal/rpm/matcher.go new file mode 100644 index 000000000..932c1b73a --- /dev/null +++ b/internal/rpm/matcher.go @@ -0,0 +1,49 @@ +package rpm + +import ( + "context" + "fmt" + + "github.com/quay/claircore" + "github.com/quay/claircore/internal/rpmver" +) + +// MatchVulnerable is a function implementing "driver.Matcher.Vulnerable" +// in a common way. +// +// Given a package version "P" and vulnerability "V": +// +// - If a fixed version "F" is specified in "V", "P < F" is reported. +// - If a package version "F" is specified in "V", "P <= F" is reported. +// - If no version is provided in "V", this function compares against an +// "infinite" version. +// +// In addition to this version comparison, the architectures are compared. +func MatchVulnerable(ctx context.Context, rec *claircore.IndexRecord, vuln *claircore.Vulnerability) (bool, error) { + p, err := rpmver.Parse(rec.Package.Version) + if err != nil { + return false, fmt.Errorf("rpm: unable to parse package version %q: %w", + rec.Package.Version, err) + } + + var v rpmver.Version + cmp := isLTE + switch { + case vuln.FixedInVersion != "": + v, err = rpmver.Parse(vuln.FixedInVersion) + cmp = isLT + case vuln.Package.Version != "": + v, err = rpmver.Parse(vuln.Package.Version) + default: + v, err = rpmver.Parse("65535:65535-65535") + } + if err != nil { + return false, fmt.Errorf("rpm: unable to parse vulnerability version %q: %w", + rec.Package.Version, err) + } + + return cmp(rpmver.Compare(&p, &v)) && vuln.ArchOperation.Cmp(rec.Package.Arch, vuln.Package.Arch), nil +} + +func isLTE(cmp int) bool { return cmp != 1 } +func isLT(cmp int) bool { return cmp == -1 }