Skip to content

Commit 0df2982

Browse files
haklirRiku Häkli
and
Riku Häkli
authored
fix: Add missing comparator for VulnerabilityAnalysis (#812)
When trying to generate a CycloneDX BOM that has two vulnerabilities that only differ in their analysis, you get ``` TypeError: '<' not supported between instances of 'VulnerabilityAnalysis' and 'VulnerabilityAnalysis' ``` This PR adds the `__lt__` method for the VulnerabilityAnalysis model to fix sorting and also includes a test case to verify the fix. --------- Signed-off-by: Riku Häkli <hakli.riku@gmail.com> Co-authored-by: Riku Häkli <hakli.riku@gmail.com>
1 parent 036eb76 commit 0df2982

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

cyclonedx/model/vulnerability.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,11 @@ def __eq__(self, other: object) -> bool:
349349
return self.__comparable_tuple() == other.__comparable_tuple()
350350
return False
351351

352+
def __lt__(self, other: Any) -> bool:
353+
if isinstance(other, VulnerabilityAnalysis):
354+
return self.__comparable_tuple() < other.__comparable_tuple()
355+
return NotImplemented
356+
352357
def __hash__(self) -> int:
353358
return hash(self.__comparable_tuple())
354359

tests/test_model_vulnerability.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,18 @@
2020
from unittest import TestCase
2121

2222
from cyclonedx.model import XsUri
23-
from cyclonedx.model.impact_analysis import ImpactAnalysisAffectedStatus
23+
from cyclonedx.model.impact_analysis import (
24+
ImpactAnalysisAffectedStatus,
25+
ImpactAnalysisJustification,
26+
ImpactAnalysisResponse,
27+
ImpactAnalysisState,
28+
)
2429
from cyclonedx.model.vulnerability import (
2530
BomTarget,
2631
BomTargetVersionRange,
2732
Vulnerability,
2833
VulnerabilityAdvisory,
34+
VulnerabilityAnalysis,
2935
VulnerabilityRating,
3036
VulnerabilityReference,
3137
VulnerabilityScoreSource,
@@ -334,3 +340,24 @@ def test_sort(self) -> None:
334340
sorted_targets = sorted(targets)
335341
expected_targets = reorder(targets, expected_order)
336342
self.assertListEqual(sorted_targets, expected_targets)
343+
344+
345+
class TestModelVulnerabilityAnalysis(TestCase):
346+
347+
def test_sort(self) -> None:
348+
# expected sort order: ([state], [justification], [responses], [detail], [first_issued], [last_updated])
349+
expected_order = [3, 1, 0, 2, 5, 4]
350+
analyses = [
351+
VulnerabilityAnalysis(state=ImpactAnalysisState.EXPLOITABLE),
352+
VulnerabilityAnalysis(state=ImpactAnalysisState.EXPLOITABLE,
353+
responses=[ImpactAnalysisResponse.CAN_NOT_FIX]),
354+
VulnerabilityAnalysis(state=ImpactAnalysisState.NOT_AFFECTED,
355+
justification=ImpactAnalysisJustification.CODE_NOT_PRESENT),
356+
VulnerabilityAnalysis(state=ImpactAnalysisState.EXPLOITABLE,
357+
justification=ImpactAnalysisJustification.REQUIRES_ENVIRONMENT),
358+
VulnerabilityAnalysis(first_issued=datetime(2024, 4, 4), last_updated=datetime(2025, 5, 5)),
359+
VulnerabilityAnalysis(first_issued=datetime(2023, 3, 3), last_updated=datetime(2023, 3, 3)),
360+
]
361+
sorted_analyses = sorted(analyses)
362+
expected_analyses = reorder(analyses, expected_order)
363+
self.assertListEqual(sorted_analyses, expected_analyses)

0 commit comments

Comments
 (0)