Skip to content

Commit 3683f2c

Browse files
committed
Include comparison matrix in issue detail
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 39c28e3 commit 3683f2c

File tree

1 file changed

+28
-56
lines changed

1 file changed

+28
-56
lines changed

vulnerabilities/pipelines/compute_advisory_todo.py

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@
88
#
99

1010

11+
import json
12+
1113
from aboutcode.pipeline import LoopProgress
1214

1315
from vulnerabilities.models import Advisory
1416
from vulnerabilities.models import AdvisoryToDo
1517
from vulnerabilities.models import Alias
1618
from vulnerabilities.pipelines import VulnerableCodePipeline
17-
from vulnerabilities.pipes import fetchcode_utils
1819
from vulnerabilities.pipes.advisory import advisories_checksum
1920

2021

2122
class ComputeToDo(VulnerableCodePipeline):
22-
"""Compute advisory AdvisoryToDo."""
23+
"""Compute ToDos for Advisory."""
2324

2425
pipeline_id = "compute_advisory_todo"
2526

@@ -56,7 +57,6 @@ def compute_individual_advisory_todo(self):
5657
)
5758

5859
def detect_conflicting_advisories(self):
59-
PACKAGE_VERSIONS = {}
6060
aliases = Alias.objects.filter(alias__istartswith="cve")
6161
aliases_count = aliases.count()
6262

@@ -68,21 +68,12 @@ def detect_conflicting_advisories(self):
6868
progress_step=1,
6969
)
7070
for alias in progress.iter(aliases.iterator(chunk_size=2000)):
71-
advisories = (
72-
Advisory.objects.filter(aliases__in=aliases)
73-
.exclude(advisory_todos__issue_type="MISSING_AFFECTED_AND_FIXED_BY_PACKAGES")
74-
.distinct()
75-
)
76-
purls = get_advisories_purls(advisories=advisories)
77-
get_package_versions(
78-
purls=purls,
79-
package_versions=PACKAGE_VERSIONS,
80-
logger=self.log,
81-
)
71+
advisories = alias.advisories.exclude(
72+
advisory_todos__issue_type="MISSING_AFFECTED_AND_FIXED_BY_PACKAGES"
73+
).distinct()
74+
8275
check_conflicting_affected_and_fixed_by_packages(
8376
advisories=advisories,
84-
package_versions=PACKAGE_VERSIONS,
85-
purls=purls,
8677
cve=alias,
8778
logger=self.log,
8879
)
@@ -137,30 +128,12 @@ def check_missing_affected_and_fixed_by_packages(advisory, todo_id, logger=None)
137128
todo.advisories.add(advisory)
138129

139130

140-
def get_package_versions(purls, package_versions, logger=None):
141-
for purl in purls:
142-
if purl in package_versions:
143-
continue
144-
versions = fetchcode_utils.versions(purl=purl, logger=logger)
145-
package_versions[purl] = versions
146-
147-
148-
def get_advisories_purls(advisories):
149-
purls = set()
150-
for advisory in advisories:
151-
advisory_obj = advisory.to_advisory_data()
152-
purls.update([str(i.package) for i in advisory_obj.affected_packages])
153-
return purls
154-
155-
156-
def check_conflicting_affected_and_fixed_by_packages(
157-
advisories, package_versions, purls, cve, logger=None
158-
):
131+
def check_conflicting_affected_and_fixed_by_packages(advisories, cve, logger=None):
159132
"""
160133
Add appropriate AdvisoryToDo for conflicting affected/fixed packages.
161134
162135
Compute the comparison matrix for the given set of advisories. Iterate through each advisory
163-
and compute and store fixed versions and normalized affected versions for each advisory,
136+
and compute and store fixed versions and affected versionrange for each advisory,
164137
keyed by purl.
165138
166139
Use the matrix to determine conflicts in affected/fixed versions for each purl. If for any purl
@@ -171,7 +144,7 @@ def check_conflicting_affected_and_fixed_by_packages(
171144
{
172145
"pkg:npm/foo/bar": {
173146
"affected": {
174-
Advisory1: frozenset(NormalizedVersionRange1, NormalizedVersionRange2),
147+
Advisory1: frozenset(VersionRange1, VersionRange2),
175148
Advisory2: frozenset(...),
176149
},
177150
"fixed": {
@@ -195,11 +168,11 @@ def check_conflicting_affected_and_fixed_by_packages(
195168
matrix = {}
196169
for advisory in advisories:
197170
advisory_obj = advisory.to_advisory_data()
171+
advisory_id = advisory.unique_content_id
198172
for affected in advisory_obj.affected_packages or []:
199-
affected_purl = str(affected.package)
200-
201-
if affected_purl not in purls or not purls[affected_purl]:
173+
if not affected:
202174
continue
175+
affected_purl = str(affected.package)
203176

204177
initialize_sub_matrix(
205178
matrix=matrix,
@@ -208,13 +181,12 @@ def check_conflicting_affected_and_fixed_by_packages(
208181
)
209182

210183
if fixed_version := affected.fixed_version:
211-
matrix[affected_purl]["fixed"][advisory].add(fixed_version)
184+
matrix[affected_purl]["fixed"][advisory_id].add(str(fixed_version))
212185

213186
if affected.affected_version_range:
214-
normalized_vers = affected.affected_version_range.normalize(
215-
known_versions=package_versions[affected_purl],
187+
matrix[affected_purl]["affected"][advisory_id].add(
188+
str(affected.affected_version_range)
216189
)
217-
matrix[affected_purl]["affected"][advisory].add(normalized_vers)
218190

219191
has_conflicting_affected_packages = False
220192
has_conflicting_fixed_package = False
@@ -223,22 +195,19 @@ def check_conflicting_affected_and_fixed_by_packages(
223195
fixed = board.get("fixed", {}).values()
224196
affected = board.get("affected", {}).values()
225197

226-
# Compare affected_vers set across different advisories.
227198
unique_set_of_affected_vers = {frozenset(vers) for vers in affected}
228-
229-
# Compare fixed_version set across different advisories.
230199
unique_set_of_fixed_versions = {frozenset(versions) for versions in fixed}
231200

232201
if len(unique_set_of_affected_vers) > 1:
233202
has_conflicting_affected_packages = True
203+
conflicting_affected = json.dumps(unique_set_of_affected_vers, default=list)
234204
messages.append(
235-
f"{cve}: {purl} with conflicting affected versions {unique_set_of_affected_vers}"
205+
f"{cve}: {purl} with conflicting affected versions {conflicting_affected}"
236206
)
237207
if len(unique_set_of_fixed_versions) > 1:
238208
has_conflicting_fixed_package = True
239-
messages.append(
240-
f"{cve}: {purl} with conflicting fixed version {unique_set_of_fixed_versions}"
241-
)
209+
conflicting_fixed = json.dumps(unique_set_of_fixed_versions, default=list)
210+
messages.append(f"{cve}: {purl} with conflicting fixed version {conflicting_fixed}")
242211

243212
if not has_conflicting_affected_packages and not has_conflicting_fixed_package:
244213
return
@@ -249,30 +218,33 @@ def check_conflicting_affected_and_fixed_by_packages(
249218
elif not has_conflicting_affected_packages:
250219
issue_type = "CONFLICTING_FIXED_BY_PACKAGES"
251220

221+
messages.append("Comparison matrix:")
222+
messages.append(json.dumps(matrix, indent=2, default=list))
252223
todo_id = advisories_checksum(advisories)
253224
todo, created = AdvisoryToDo.objects.get_or_create(
254225
related_advisories_id=todo_id,
255226
issue_type=issue_type,
256227
defaults={
257-
"issue_details": "\n".join(messages),
228+
"issue_detail": "\n".join(messages),
258229
},
259230
)
260231
if created:
261232
todo.advisories.add(*advisories)
262233

263234

264235
def initialize_sub_matrix(matrix, affected_purl, advisory):
236+
advisory_id = advisory.unique_content_id
265237
if affected_purl not in matrix:
266238
matrix[affected_purl] = {
267239
"affected": {
268-
advisory: set(),
240+
advisory_id: set(),
269241
},
270242
"fixed": {
271-
advisory: set(),
243+
advisory_id: set(),
272244
},
273245
}
274246
else:
275247
if advisory not in matrix[affected_purl]["affected"]:
276-
matrix[affected_purl]["affected"] = set()
248+
matrix[affected_purl]["affected"][advisory_id] = set()
277249
if advisory not in matrix[affected_purl]["fixed"]:
278-
matrix[affected_purl]["fixed"] = set()
250+
matrix[affected_purl]["fixed"][advisory_id] = set()

0 commit comments

Comments
 (0)