Skip to content

Commit a40f834

Browse files
committed
fix: build Debian affected packages per release
The purl was built inside the release loop but used after it, so every affected package got the last release's distro. Resolved releases also added their current repository version as a fix, and affected versions from all releases were merged into one range. Each release now gets its own package with only its own affected and fixed versions. Releases with fixed_version "0" are skipped since Debian uses that for releases that were never affected. Fixes #2460 Signed-off-by: Sahil Lenka <sahillenka44@gmail.com>
1 parent da7dcf2 commit a40f834

2 files changed

Lines changed: 74 additions & 31 deletions

File tree

‎vulnerabilities/pipelines/v2_importers/debian_importer.py‎

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from vulnerabilities.importer import ReferenceV2
2323
from vulnerabilities.pipelines import VulnerableCodeBaseImporterPipelineV2
2424
from vulnerabilities.utils import create_weaknesses_list
25-
from vulnerabilities.utils import dedupe
2625
from vulnerabilities.utils import fetch_response
2726
from vulnerabilities.utils import get_item
2827

@@ -115,8 +114,7 @@ def collect_advisories(self) -> Iterable[AdvisoryData]:
115114
def parse(self, pkg_name: str, records: Mapping[str, Any]) -> Iterable[AdvisoryData]:
116115

117116
for record_identifier, record in records.items():
118-
affected_versions = []
119-
fixed_versions = []
117+
affected_packages = []
120118

121119
releases = record["releases"].items()
122120
for release_name, release_record in releases:
@@ -128,41 +126,37 @@ def parse(self, pkg_name: str, records: Mapping[str, Any]) -> Iterable[AdvisoryD
128126
)
129127
continue
130128

131-
purl = PackageURL(
132-
name=pkg_name,
133-
type="deb",
134-
namespace="debian",
135-
qualifiers={"distro": release_name},
136-
)
129+
# Debian uses "0" for releases that were never affected
130+
fixed_version = release_record.get("fixed_version")
131+
if fixed_version == "0":
132+
continue
137133

138-
if release_record.get("status", "") == "resolved":
139-
fixed_versions.append(version)
140-
else:
141-
affected_versions.append(version)
134+
affected_version_range = None
135+
if release_record.get("status", "") != "resolved":
136+
affected_version_range = DebianVersionRange.from_versions([version])
142137

143-
if release_record.get("fixed_version"):
144-
fixed_versions.append(release_record["fixed_version"])
138+
fixed_version_range = None
139+
if fixed_version:
140+
fixed_version_range = DebianVersionRange.from_versions([fixed_version])
145141

146-
references = []
147-
debianbug = record.get("debianbug")
148-
if debianbug:
149-
bug_url = f"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug={debianbug}"
150-
references.append(ReferenceV2(url=bug_url, reference_id=str(debianbug)))
151-
affected_versions = dedupe(affected_versions)
152-
fixed_versions = dedupe(fixed_versions)
153-
if affected_versions:
154-
affected_version_range = DebianVersionRange.from_versions(affected_versions)
155-
else:
156-
affected_version_range = None
157-
affected_packages = []
158-
for fixed_version in fixed_versions:
159142
affected_packages.append(
160143
AffectedPackageV2(
161-
package=purl,
144+
package=PackageURL(
145+
name=pkg_name,
146+
type="deb",
147+
namespace="debian",
148+
qualifiers={"distro": release_name},
149+
),
162150
affected_version_range=affected_version_range,
163-
fixed_version_range=DebianVersionRange.from_versions([fixed_version]),
151+
fixed_version_range=fixed_version_range,
164152
)
165153
)
154+
155+
references = []
156+
debianbug = record.get("debianbug")
157+
if debianbug:
158+
bug_url = f"https://bugs.debian.org/cgi-bin/bugreport.cgi?bug={debianbug}"
159+
references.append(ReferenceV2(url=bug_url, reference_id=str(debianbug)))
166160
weaknesses = get_cwe_from_debian_advisory(record)
167161

168162
yield AdvisoryDataV2(

‎vulnerabilities/tests/pipelines/v2_importers/test_debian_importer.py‎

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ def test_affected_packages_generation(importer, sample_response):
120120
for pkg in affected_packages:
121121
assert isinstance(pkg, AffectedPackageV2)
122122
assert isinstance(pkg.package, PackageURL)
123-
assert isinstance(pkg.fixed_version_range, DebianVersionRange)
123+
124+
bullseye, bookworm = affected_packages
125+
assert bullseye.package.qualifiers == {"distro": "bullseye"}
126+
assert isinstance(bullseye.fixed_version_range, DebianVersionRange)
127+
assert bookworm.package.qualifiers == {"distro": "bookworm"}
128+
assert isinstance(bookworm.affected_version_range, DebianVersionRange)
124129

125130

126131
def test_debian_bug_reference(importer, sample_response):
@@ -135,3 +140,47 @@ def test_debian_bug_reference(importer, sample_response):
135140
assert isinstance(ref, ReferenceV2)
136141
assert ref.reference_id == "123456"
137142
assert "bugs.debian.org" in ref.url
143+
144+
145+
def test_affected_packages_are_built_per_release(importer):
146+
records = {
147+
"CVE-2024-0727": {
148+
"releases": {
149+
"bookworm": {
150+
"status": "resolved",
151+
"repositories": {"bookworm": "3.0.20-1~deb12u2"},
152+
"fixed_version": "3.0.13-1~deb12u1",
153+
},
154+
"trixie": {
155+
"status": "resolved",
156+
"repositories": {"trixie": "3.5.7-1~deb13u2"},
157+
"fixed_version": "3.1.5-1",
158+
},
159+
"bullseye": {
160+
"status": "resolved",
161+
"repositories": {"bullseye": "1.1.1w-0+deb11u1"},
162+
"fixed_version": "0",
163+
},
164+
"sid": {
165+
"status": "open",
166+
"repositories": {"sid": "3.6.5-1"},
167+
},
168+
}
169+
}
170+
}
171+
172+
advisory = next(importer.parse("openssl", records))
173+
result = {
174+
pkg.package.qualifiers["distro"]: (
175+
str(pkg.affected_version_range) if pkg.affected_version_range else None,
176+
str(pkg.fixed_version_range) if pkg.fixed_version_range else None,
177+
)
178+
for pkg in advisory.affected_packages
179+
}
180+
181+
assert len(advisory.affected_packages) == 3
182+
assert result == {
183+
"bookworm": (None, "vers:deb/3.0.13-1~deb12u1"),
184+
"trixie": (None, "vers:deb/3.1.5-1"),
185+
"sid": ("vers:deb/3.6.5-1", None),
186+
}

0 commit comments

Comments
 (0)