fix: capture ${source:Version}, the number OSV ranges are actually stated in #1

Merged
christianmanivong merged 1 commits from fix/capture-source-version into master 2026-09-14 04:11:34 +00:00
2 changed files with 70 additions and 6 deletions
+20 -3
View File
@@ -835,11 +835,13 @@ class LinuxDriver(OSDriver):
def _get_packages_apt(self) -> list[PackageDict]:
out = self._send(
"dpkg-query -W -f='${Package}\\t${Version}\\t${Installed-Size}"
"\\t${source:Package}\\t${binary:Summary}\\n' 2>/dev/null"
"\\t${source:Package}\\t${source:Version}\\t${binary:Summary}\\n' 2>/dev/null"
)
packages: list[PackageDict] = []
for line in out.splitlines():
parts = line.split("\t", 4)
# Summary stays last and keeps whatever it contains: maxsplit must
# equal the number of tabs the format writes, not the field count.
parts = line.split("\t", 5)
if len(parts) < 2:
continue
name = parts[0].strip()
@@ -847,7 +849,21 @@ class LinuxDriver(OSDriver):
size = int(parts[2].strip()) * 1024 if len(parts) > 2 and parts[2].strip().isdigit() else 0
# Debian source package (e.g. openssh-server → openssh) for OSV matching.
source_package = parts[3].strip() if len(parts) > 3 and parts[3].strip() else name
description = parts[4].strip() if len(parts) > 4 else ""
# And its version, which is a different number from this package's.
#
# OSV states Debian ranges in *source* versions. A source package
# that ships several binaries gives each its own upstream version:
# libldb2 is 2:2.11.0+samba4.22.11+dfsg-… while its source, samba,
# is 2:4.22.11+dfsg-…. A consumer matching on source_package and
# comparing `version` compares two unrelated numbers — dpkg reads
# ldb's 2.11.0 as older than the 2:4.17.4+dfsg-1 that fixed
# CVE-2022-44640, and a host five releases past the fix was reported
# vulnerable on four packages at once.
#
# dpkg leaves this empty when it equals `Version`; so does an older
# dpkg that does not know the field at all.
source_version = parts[4].strip() if len(parts) > 4 and parts[4].strip() else version
description = parts[5].strip() if len(parts) > 5 else ""
packages.append({
"name": name,
"version": version,
@@ -856,6 +872,7 @@ class LinuxDriver(OSDriver):
"size": size,
"source": "apt",
"source_package": source_package,
"source_version": source_version,
})
return packages
+50 -3
View File
@@ -153,9 +153,22 @@ def test_parse_uptime_invalid(driver):
# ---------------------------------------------------------------------------
#: What `dpkg-query` actually returns for the format this driver asks for.
#:
#: The previous fixture carried four fields against a format string asking for
#: five, so `source_package` was silently receiving the description and no
#: assertion noticed. A fixture simpler than the data cannot fail the way the
#: data does.
APT_PKG_OUTPUT = (
"openssh-server\t1:9.2p1-2+deb12u2\t512\tsecure shell server\n"
"curl\t7.88.1-10+deb12u5\t1024\tcommand line tool for transferring data\n"
"openssh-server\t1:9.2p1-2+deb12u2\t512\topenssh\t1:9.2p1-2+deb12u2"
"\tsecure shell server\n"
"curl\t7.88.1-10+deb12u5\t1024\tcurl\t7.88.1-10+deb12u5"
"\tcommand line tool for transferring data\n"
# The shape that matters: a binary package whose own upstream version has
# nothing to do with its source package's. ldb 2.11.0 is built from samba
# 4.22.11, and OSV states Debian ranges in source versions.
"libldb2\t2:2.11.0+samba4.22.11+dfsg-0+deb13u1\t2048\tsamba"
"\t2:4.22.11+dfsg-0+deb13u1\tLDB shared library\n"
)
@@ -163,11 +176,45 @@ def test_get_packages_apt(driver):
driver._pkg_manager = "apt"
with patch.object(driver, "_send", return_value=APT_PKG_OUTPUT):
pkgs = driver.get_packages()
assert len(pkgs) == 2
assert len(pkgs) == 3
assert pkgs[0]["name"] == "openssh-server"
assert pkgs[0]["version"] == "1:9.2p1-2+deb12u2"
assert pkgs[0]["installed"] is True
assert pkgs[0]["source"] == "apt"
assert pkgs[0]["description"] == "secure shell server"
def test_get_packages_apt_keeps_the_source_package_and_its_version(driver):
"""OSV states Debian ranges in *source* package versions.
A consumer that matches on the source package and then compares the binary
package's version is comparing two unrelated numbers. On a Debian 13 host
that reported four Samba libraries as vulnerable to CVE-2022-44640 while
running samba 4.22.11 — five releases past the fix — because dpkg reads
ldb's own `2.11.0` as older than samba's `2:4.17.4+dfsg-1`.
The driver cannot fix the comparison, but it is the only place that can
supply the number to compare.
"""
driver._pkg_manager = "apt"
with patch.object(driver, "_send", return_value=APT_PKG_OUTPUT):
pkgs = {p["name"]: p for p in driver.get_packages()}
assert pkgs["libldb2"]["source_package"] == "samba"
assert pkgs["libldb2"]["source_version"] == "2:4.22.11+dfsg-0+deb13u1"
assert pkgs["libldb2"]["version"] == "2:2.11.0+samba4.22.11+dfsg-0+deb13u1"
assert pkgs["libldb2"]["description"] == "LDB shared library"
def test_get_packages_apt_falls_back_when_dpkg_gives_no_source(driver):
"""`source:Package` is empty for a package whose source name equals its own.
Older dpkg builds leave `source:Version` empty in that case too."""
driver._pkg_manager = "apt"
with patch.object(driver, "_send", return_value="curl\t7.88.1-10\t1024\t\t\ttool\n"):
(pkg,) = driver.get_packages()
assert pkg["source_package"] == "curl"
assert pkg["source_version"] == "7.88.1-10"
# ---------------------------------------------------------------------------