From c3f3d0d105f0dcf991175040b6d6c2b6e7e25d8f Mon Sep 17 00:00:00 2001 From: Rodney Richardson Date: Fri, 10 Jun 2022 20:58:59 +0100 Subject: [PATCH] fix: add missing `Vulnerability` comparator for sorting (#246) Partial fix for #245. Signed-off-by: Rodney Richardson --- cyclonedx/model/vulnerability.py | 8 +++++++ tests/test_model_vulnerability.py | 36 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index a189bd20..7e769222 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -1062,6 +1062,14 @@ def __eq__(self, other: object) -> bool: return hash(other) == hash(self) return False + def __lt__(self, other: Any) -> bool: + if isinstance(other, Vulnerability): + return ComparableTuple( + (self.id, self.description, self.detail, self.source, self.created, self.published)) < \ + ComparableTuple( + (other.id, other.description, other.detail, other.source, other.created, other.published)) + return NotImplemented + def __hash__(self) -> int: return hash(( self.id, self.source, tuple(self.references), tuple(self.ratings), tuple(self.cwes), self.description, diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py index b911c16f..bfcc93a1 100644 --- a/tests/test_model_vulnerability.py +++ b/tests/test_model_vulnerability.py @@ -18,6 +18,7 @@ # Copyright (c) OWASP Foundation. All Rights Reserved. import unittest +from datetime import datetime, timedelta from decimal import Decimal from unittest import TestCase from unittest.mock import Mock, patch @@ -206,6 +207,41 @@ def test_empty_vulnerability(self, mock_uuid: Mock) -> None: self.assertIsNone(v.analysis) self.assertFalse(v.affects) + def test_sort(self) -> None: + source1 = VulnerabilitySource(name='a') + source2 = VulnerabilitySource(name='b') + datetime1 = datetime.utcnow() + datetime2 = datetime1 + timedelta(seconds=5) + + # expected sort order: (id, description, detail, source, created, published) + expected_order = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11] + vulnerabilities = [ + Vulnerability(bom_ref='0', id='a', description='a', detail='a', + source=source1, created=datetime1, published=datetime1), + Vulnerability(bom_ref='1', id='a', description='a', detail='a', + source=source1, created=datetime1), + Vulnerability(bom_ref='2', id='a', description='a', detail='a', + source=source1), + Vulnerability(bom_ref='3', id='a', description='a', detail='a'), + Vulnerability(bom_ref='4', id='a', description='a'), + Vulnerability(bom_ref='5', id='a'), + Vulnerability(bom_ref='6', id='a', description='a', detail='a', + source=source1, created=datetime1, published=datetime2), + Vulnerability(bom_ref='7', id='a', description='a', detail='a', + source=source1, created=datetime2, published=datetime1), + Vulnerability(bom_ref='8', id='a', description='a', detail='a', + source=source2, created=datetime1, published=datetime1), + Vulnerability(bom_ref='9', id='a', description='a', detail='b', + source=source1, created=datetime1, published=datetime1), + Vulnerability(bom_ref='10', id='a', description='b', detail='b', + source=source1, created=datetime1, published=datetime1), + Vulnerability(bom_ref='11', id='b', description='a', detail='a', + source=source1, created=datetime1, published=datetime1), + ] + sorted_vulnerabilities = sorted(vulnerabilities) + expected_vulnerabilities = reorder(vulnerabilities, expected_order) + self.assertListEqual(sorted_vulnerabilities, expected_vulnerabilities) + class TestModelVulnerabilityAdvisory(TestCase):