Skip to content

Commit 8080fab

Browse files
committed
Merge branch 'optimize-vulnerabilities-view' into deploy_v2_ui
2 parents 768e6c7 + 7689246 commit 8080fab

File tree

6 files changed

+447
-305
lines changed

6 files changed

+447
-305
lines changed

vulnerabilities/models.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@
1212
import logging
1313
from contextlib import suppress
1414
from functools import cached_property
15+
from itertools import groupby
16+
from operator import attrgetter
1517
from typing import Union
1618

19+
from cvss.exceptions import CVSS2MalformedError
20+
from cvss.exceptions import CVSS3MalformedError
21+
from cvss.exceptions import CVSS4MalformedError
1722
from cwe2.database import Database
1823
from django.contrib.auth import get_user_model
1924
from django.contrib.auth.models import UserManager
@@ -43,6 +48,7 @@
4348

4449
from aboutcode import hashid
4550
from vulnerabilities import utils
51+
from vulnerabilities.severity_systems import EPSS
4652
from vulnerabilities.severity_systems import SCORING_SYSTEMS
4753
from vulnerabilities.utils import normalize_purl
4854
from vulnerabilities.utils import purl_to_dict
@@ -371,6 +377,95 @@ def get_related_purls(self):
371377
"""
372378
return [p.package_url for p in self.packages.distinct().all()]
373379

380+
def aggregate_fixed_and_affected_packages(self):
381+
from vulnerabilities.views import get_purl_version_class
382+
383+
sorted_fixed_by_packages = self.fixed_by_packages.filter(is_ghost=False).order_by(
384+
"type", "namespace", "name", "qualifiers", "subpath"
385+
)
386+
387+
sorted_affected_packages = self.affected_packages.all()
388+
389+
grouped_fixed_by_packages = {
390+
key: list(group)
391+
for key, group in groupby(
392+
sorted_fixed_by_packages,
393+
key=attrgetter("type", "namespace", "name", "qualifiers", "subpath"),
394+
)
395+
}
396+
397+
all_affected_fixed_by_matches = []
398+
399+
for sorted_affected_package in sorted_affected_packages:
400+
affected_fixed_by_matches = {
401+
"affected_package": sorted_affected_package,
402+
"matched_fixed_by_packages": [],
403+
}
404+
405+
# Build the key to find matching group
406+
key = (
407+
sorted_affected_package.type,
408+
sorted_affected_package.namespace,
409+
sorted_affected_package.name,
410+
sorted_affected_package.qualifiers,
411+
sorted_affected_package.subpath,
412+
)
413+
414+
# Get matching group from pre-grouped fixed_by_packages
415+
matching_fixed_packages = grouped_fixed_by_packages.get(key, [])
416+
417+
# Get version classes for comparison
418+
affected_version_class = get_purl_version_class(sorted_affected_package)
419+
affected_version = affected_version_class(sorted_affected_package.version)
420+
421+
# Compare versions and filter valid matches
422+
matched_fixed_by_packages = [
423+
fixed_by_package.purl
424+
for fixed_by_package in matching_fixed_packages
425+
if get_purl_version_class(fixed_by_package)(fixed_by_package.version)
426+
> affected_version
427+
]
428+
429+
affected_fixed_by_matches["matched_fixed_by_packages"] = matched_fixed_by_packages
430+
all_affected_fixed_by_matches.append(affected_fixed_by_matches)
431+
return sorted_fixed_by_packages, sorted_affected_packages, all_affected_fixed_by_matches
432+
433+
def get_severity_vectors_and_values(self):
434+
"""
435+
Collect severity vectors and values, excluding EPSS scoring systems and handling errors gracefully.
436+
"""
437+
severity_vectors = []
438+
severity_values = set()
439+
440+
# Exclude EPSS scoring system
441+
base_severities = self.severities.exclude(scoring_system=EPSS.identifier)
442+
443+
# QuerySet for severities with valid scoring_elements and scoring_system in SCORING_SYSTEMS
444+
valid_scoring_severities = base_severities.filter(
445+
scoring_elements__isnull=False, scoring_system__in=SCORING_SYSTEMS.keys()
446+
)
447+
448+
for severity in valid_scoring_severities:
449+
try:
450+
vector_values = SCORING_SYSTEMS[severity.scoring_system].get(
451+
severity.scoring_elements
452+
)
453+
if vector_values:
454+
severity_vectors.append(vector_values)
455+
except (
456+
CVSS2MalformedError,
457+
CVSS3MalformedError,
458+
CVSS4MalformedError,
459+
NotImplementedError,
460+
) as e:
461+
logging.error(f"CVSSMalformedError for {severity.scoring_elements}: {e}")
462+
463+
valid_value_severities = base_severities.filter(value__isnull=False).exclude(value="")
464+
465+
severity_values.update(valid_value_severities.values_list("value", flat=True))
466+
467+
return severity_vectors, severity_values
468+
374469

375470
class Weakness(models.Model):
376471
"""

0 commit comments

Comments
 (0)