From 3c48d27e18e034a684251b4238c2cbfc52c023ec Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:04:17 +0200 Subject: [PATCH 01/10] tests Signed-off-by: Jan Kowalleck --- tests/test_model_vulnerability.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py index 74af5a25..eae176fb 100644 --- a/tests/test_model_vulnerability.py +++ b/tests/test_model_vulnerability.py @@ -41,7 +41,7 @@ from tests import reorder -class TestModelVulnerability(TestCase): +class TestModelVulnerabilitySeverity(TestCase): def test_v_severity_from_cvss_scores_single_critical(self) -> None: self.assertEqual( @@ -85,13 +85,33 @@ def test_v_severity_from_cvss_scores_multiple_high(self) -> None: VulnerabilitySeverity.HIGH ) +class TestModelVulnerabilityScoreSource(TestCase): + + def test_v_source_parse_other(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.get_from_vector('loremIpsum'), + VulnerabilityScoreSource.OTHER + ) + + def test_v_source_parse_cvss4_0(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.get_from_vector('CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U'), + VulnerabilityScoreSource.CVSS_V4 + ) + def test_v_source_parse_cvss3_1(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.get_from_vector('CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H'), + VulnerabilityScoreSource.CVSS_V3_1 + ) + + def test_v_source_parse_cvss3_0(self) -> None: self.assertEqual( VulnerabilityScoreSource.get_from_vector('CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), VulnerabilityScoreSource.CVSS_V3 ) - def test_v_source_parse_cvss2_1(self) -> None: + def test_v_source_parse_cvss2_0(self) -> None: self.assertEqual( VulnerabilityScoreSource.get_from_vector('CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C'), VulnerabilityScoreSource.CVSS_V2 @@ -103,7 +123,7 @@ def test_v_source_parse_owasp_1(self) -> None: VulnerabilityScoreSource.OWASP ) - def test_v_source_get_localised_vector_cvss3_1(self) -> None: + def test_v_source_get_localised_vector_cvss3_0(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector( vector='CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' @@ -166,6 +186,8 @@ def test_v_source_get_localised_vector_other_2(self) -> None: 'SOMETHING_OR_OTHER' ) +class TestModelVulnerability(TestCase): + def test_empty_vulnerability(self) -> None: v = Vulnerability() self.assertIsNone(v.bom_ref.value) From 926c4b03e72de48fdce8e07acc8a02694ffd56fa Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:15:55 +0200 Subject: [PATCH 02/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index cd6809b9..580c55fc 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -611,14 +611,17 @@ def get_from_vector(vector: str) -> 'VulnerabilityScoreSource': Always returns an instance of `VulnerabilityScoreSource`. `VulnerabilityScoreSource.OTHER` is returned if the scheme is not obvious or known to us. """ + if vector.startswith('CVSS:4.0'): + return VulnerabilityScoreSource.CVSS_V4 + if vector.startswith('CVSS:3.1'): + return VulnerabilityScoreSource.CVSS_V3_1 if vector.startswith('CVSS:3.'): return VulnerabilityScoreSource.CVSS_V3 - elif vector.startswith('CVSS:2.'): + if vector.startswith('CVSS:2.'): return VulnerabilityScoreSource.CVSS_V2 - elif vector.startswith('OWASP'): + if vector.startswith('OWASP'): return VulnerabilityScoreSource.OWASP - else: - return VulnerabilityScoreSource.OTHER + return VulnerabilityScoreSource.OTHER def get_localised_vector(self, vector: str) -> str: """ @@ -630,15 +633,15 @@ def get_localised_vector(self, vector: str) -> str: Returns: The vector without any scheme prefix as a `str`. """ - if self == VulnerabilityScoreSource.CVSS_V3 and vector.startswith('CVSS:3.'): - return re.sub('^CVSS:3\\.\\d/?', '', vector) - - if self == VulnerabilityScoreSource.CVSS_V2 and vector.startswith('CVSS:2.'): - return re.sub('^CVSS:2\\.\\d/?', '', vector) - - if self == VulnerabilityScoreSource.OWASP and vector.startswith('OWASP'): - return re.sub('^OWASP/?', '', vector) - + if self is VulnerabilityScoreSource.CVSS_V4 and vector.startswith('CVSS:4.'): + return re.sub(r'^CVSS:3\.\d/?', '', vector) + if (self is VulnerabilityScoreSource.CVSS_V3_1 or self is VulnerabilityScoreSource.CVSS_V3) \ + and vector.startswith('CVSS:3.'): + return re.sub(r'^CVSS:3\.\d/?', '', vector) + if self is VulnerabilityScoreSource.CVSS_V2 and vector.startswith('CVSS:2.'): + return re.sub(r'^CVSS:2\.\d/?', '', vector) + if self is VulnerabilityScoreSource.OWASP and vector.startswith('OWASP'): + return re.sub(r'^OWASP/?', '', vector) return vector def get_value_pre_1_4(self) -> str: From 786f09feb09d18e849e14519db70cb10415027a7 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:19:46 +0200 Subject: [PATCH 03/10] wip Signed-off-by: Jan Kowalleck --- tests/test_model_vulnerability.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py index eae176fb..0cb10f2e 100644 --- a/tests/test_model_vulnerability.py +++ b/tests/test_model_vulnerability.py @@ -123,7 +123,7 @@ def test_v_source_parse_owasp_1(self) -> None: VulnerabilityScoreSource.OWASP ) - def test_v_source_get_localised_vector_cvss3_0(self) -> None: + def test_v_source_get_localised_vector_cvss3_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector( vector='CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' @@ -131,56 +131,56 @@ def test_v_source_get_localised_vector_cvss3_0(self) -> None: 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_cvss3_2(self) -> None: + def test_v_source_get_localised_vector_cvss3_noslash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector(vector='CVSS:3.0AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_cvss3_3(self) -> None: + def test_v_source_get_localised_vector_cvss3_none(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_cvss2_1(self) -> None: + def test_v_source_get_localised_vector_cvss2_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V2.get_localised_vector( vector='CVSS:2.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_cvss2_2(self) -> None: + def test_v_source_get_localised_vector_cvss2_noslash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V2.get_localised_vector(vector='CVSS:2.1AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_cvss2_3(self) -> None: + def test_v_source_get_localised_vector_cvss2_none(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V2.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_owasp_1(self) -> None: + def test_v_source_get_localised_vector_owasp_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.OWASP.get_localised_vector(vector='OWASP/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_owasp_2(self) -> None: + def test_v_source_get_localised_vector_owasp_noslash(self) -> None: self.assertEqual( VulnerabilityScoreSource.OWASP.get_localised_vector(vector='OWASPAV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_owasp_3(self) -> None: + def test_v_source_get_localised_vector_owasp_none(self) -> None: self.assertEqual( VulnerabilityScoreSource.OWASP.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) - def test_v_source_get_localised_vector_other_2(self) -> None: + def test_v_source_get_localised_vector_other(self) -> None: self.assertEqual( VulnerabilityScoreSource.OTHER.get_localised_vector(vector='SOMETHING_OR_OTHER'), 'SOMETHING_OR_OTHER' From b4f127316566a52dd66989fe787977600d798896 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:43:35 +0200 Subject: [PATCH 04/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 2 +- tests/test_model_vulnerability.py | 67 +++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index 580c55fc..655a62d9 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -636,7 +636,7 @@ def get_localised_vector(self, vector: str) -> str: if self is VulnerabilityScoreSource.CVSS_V4 and vector.startswith('CVSS:4.'): return re.sub(r'^CVSS:3\.\d/?', '', vector) if (self is VulnerabilityScoreSource.CVSS_V3_1 or self is VulnerabilityScoreSource.CVSS_V3) \ - and vector.startswith('CVSS:3.'): + and vector.startswith('CVSS:3.'): return re.sub(r'^CVSS:3\.\d/?', '', vector) if self is VulnerabilityScoreSource.CVSS_V2 and vector.startswith('CVSS:2.'): return re.sub(r'^CVSS:2\.\d/?', '', vector) diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py index 0cb10f2e..3c9ced3e 100644 --- a/tests/test_model_vulnerability.py +++ b/tests/test_model_vulnerability.py @@ -85,6 +85,7 @@ def test_v_severity_from_cvss_scores_multiple_high(self) -> None: VulnerabilitySeverity.HIGH ) + class TestModelVulnerabilityScoreSource(TestCase): def test_v_source_parse_other(self) -> None: @@ -95,97 +96,131 @@ def test_v_source_parse_other(self) -> None: def test_v_source_parse_cvss4_0(self) -> None: self.assertEqual( - VulnerabilityScoreSource.get_from_vector('CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U'), + VulnerabilityScoreSource.get_from_vector( + 'CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:U'), VulnerabilityScoreSource.CVSS_V4 ) def test_v_source_parse_cvss3_1(self) -> None: self.assertEqual( - VulnerabilityScoreSource.get_from_vector('CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H'), + VulnerabilityScoreSource.get_from_vector( + 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H'), VulnerabilityScoreSource.CVSS_V3_1 ) def test_v_source_parse_cvss3_0(self) -> None: self.assertEqual( - VulnerabilityScoreSource.get_from_vector('CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.get_from_vector( + 'CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), VulnerabilityScoreSource.CVSS_V3 ) def test_v_source_parse_cvss2_0(self) -> None: self.assertEqual( - VulnerabilityScoreSource.get_from_vector('CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C'), + VulnerabilityScoreSource.get_from_vector( + 'CVSS:2.0/AV:N/AC:L/Au:N/C:N/I:N/A:C'), VulnerabilityScoreSource.CVSS_V2 ) def test_v_source_parse_owasp_1(self) -> None: self.assertEqual( - VulnerabilityScoreSource.get_from_vector('OWASP/K9:M1:O0:Z2/D1:X1:W1:L3/C2:I1:A1:T1/F1:R1:S2:P3/50'), + VulnerabilityScoreSource.get_from_vector( + 'OWASP/K9:M1:O0:Z2/D1:X1:W1:L3/C2:I1:A1:T1/F1:R1:S2:P3/50'), VulnerabilityScoreSource.OWASP ) + def test_v_source_get_localised_vector_cvss3_1_slash(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V3.get_localised_vector( + 'CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H'), + 'AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H' + ) + + def test_v_source_get_localised_vector_cvss3_1_noslash(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V3_1.get_localised_vector( + 'CVSS:3.0AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' + ) + + def test_v_source_get_localised_vector_cvss3_1_none(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V3_1.get_localised_vector( + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' + ) + def test_v_source_get_localised_vector_cvss3_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector( - vector='CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' - ), + 'CVSS:3.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_cvss3_noslash(self) -> None: self.assertEqual( - VulnerabilityScoreSource.CVSS_V3.get_localised_vector(vector='CVSS:3.0AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.CVSS_V3.get_localised_vector( + 'CVSS:3.0AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_cvss3_none(self) -> None: self.assertEqual( - VulnerabilityScoreSource.CVSS_V3.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.CVSS_V3.get_localised_vector( + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_cvss2_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V2.get_localised_vector( - vector='CVSS:2.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + 'CVSS:2.0/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_cvss2_noslash(self) -> None: self.assertEqual( - VulnerabilityScoreSource.CVSS_V2.get_localised_vector(vector='CVSS:2.1AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.CVSS_V2.get_localised_vector( + 'CVSS:2.0AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_cvss2_none(self) -> None: self.assertEqual( - VulnerabilityScoreSource.CVSS_V2.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.CVSS_V2.get_localised_vector( + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_owasp_slash(self) -> None: self.assertEqual( - VulnerabilityScoreSource.OWASP.get_localised_vector(vector='OWASP/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.OWASP.get_localised_vector( + 'OWASP/AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_owasp_noslash(self) -> None: self.assertEqual( - VulnerabilityScoreSource.OWASP.get_localised_vector(vector='OWASPAV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.OWASP.get_localised_vector( + 'OWASPAV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_owasp_none(self) -> None: self.assertEqual( - VulnerabilityScoreSource.OWASP.get_localised_vector(vector='AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), + VulnerabilityScoreSource.OWASP.get_localised_vector( + 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N'), 'AV:L/AC:L/PR:N/UI:R/S:C/C:L/I:N/A:N' ) def test_v_source_get_localised_vector_other(self) -> None: self.assertEqual( - VulnerabilityScoreSource.OTHER.get_localised_vector(vector='SOMETHING_OR_OTHER'), + VulnerabilityScoreSource.OTHER.get_localised_vector( + 'SOMETHING_OR_OTHER'), 'SOMETHING_OR_OTHER' ) + class TestModelVulnerability(TestCase): def test_empty_vulnerability(self) -> None: From e477a864d9809d4dcd9ae1bcae4c0e572c7ed40a Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:45:46 +0200 Subject: [PATCH 05/10] wip Signed-off-by: Jan Kowalleck --- tests/test_model_vulnerability.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_model_vulnerability.py b/tests/test_model_vulnerability.py index 3c9ced3e..6c90a8ad 100644 --- a/tests/test_model_vulnerability.py +++ b/tests/test_model_vulnerability.py @@ -129,6 +129,27 @@ def test_v_source_parse_owasp_1(self) -> None: VulnerabilityScoreSource.OWASP ) + def test_v_source_get_localised_vector_cvss4_slash(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V4.get_localised_vector( + 'CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N'), + 'AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N' + ) + + def test_v_source_get_localised_vector_cvss4_noslash(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V4.get_localised_vector( + 'CVSS:4.0AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N'), + 'AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N' + ) + + def test_v_source_get_localised_vector_cvss4_none(self) -> None: + self.assertEqual( + VulnerabilityScoreSource.CVSS_V4.get_localised_vector( + 'AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N'), + 'AV:N/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N' + ) + def test_v_source_get_localised_vector_cvss3_1_slash(self) -> None: self.assertEqual( VulnerabilityScoreSource.CVSS_V3.get_localised_vector( From 128b25d11099a4a7999f1f4b7d79525a75c31e2d Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:47:30 +0200 Subject: [PATCH 06/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index 655a62d9..1867b7fa 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -634,7 +634,7 @@ def get_localised_vector(self, vector: str) -> str: The vector without any scheme prefix as a `str`. """ if self is VulnerabilityScoreSource.CVSS_V4 and vector.startswith('CVSS:4.'): - return re.sub(r'^CVSS:3\.\d/?', '', vector) + return re.sub(r'^CVSS:4\.\d/?', '', vector) if (self is VulnerabilityScoreSource.CVSS_V3_1 or self is VulnerabilityScoreSource.CVSS_V3) \ and vector.startswith('CVSS:3.'): return re.sub(r'^CVSS:3\.\d/?', '', vector) From 21aeb754a7c8f50f1c62eb7bed420e1cd8bfcac0 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 11:48:00 +0200 Subject: [PATCH 07/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index 1867b7fa..9fcb911c 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -652,7 +652,7 @@ def get_value_pre_1_4(self) -> str: Returns: `str` """ - if self == VulnerabilityScoreSource.OWASP: + if self is VulnerabilityScoreSource.OWASP: return 'OWASP Risk' return self.value # type:ignore[no-any-return] From e204726165bfbfb782ad7272b9b33d56cf797d4f Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 12:00:49 +0200 Subject: [PATCH 08/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index 9fcb911c..f236fd42 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -611,7 +611,7 @@ def get_from_vector(vector: str) -> 'VulnerabilityScoreSource': Always returns an instance of `VulnerabilityScoreSource`. `VulnerabilityScoreSource.OTHER` is returned if the scheme is not obvious or known to us. """ - if vector.startswith('CVSS:4.0'): + if vector.startswith('CVSS:4.'): return VulnerabilityScoreSource.CVSS_V4 if vector.startswith('CVSS:3.1'): return VulnerabilityScoreSource.CVSS_V3_1 From 63b63057080a498a5108c3d131f5f7f4923fb94e Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 12:01:16 +0200 Subject: [PATCH 09/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index f236fd42..d328a12e 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -613,9 +613,9 @@ def get_from_vector(vector: str) -> 'VulnerabilityScoreSource': """ if vector.startswith('CVSS:4.'): return VulnerabilityScoreSource.CVSS_V4 - if vector.startswith('CVSS:3.1'): - return VulnerabilityScoreSource.CVSS_V3_1 if vector.startswith('CVSS:3.'): + if vector.startswith('CVSS:3.1'): + return VulnerabilityScoreSource.CVSS_V3_1 return VulnerabilityScoreSource.CVSS_V3 if vector.startswith('CVSS:2.'): return VulnerabilityScoreSource.CVSS_V2 From 0efbf0a4b5886af1ac60ab2d4f5172230da66264 Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 9 Jun 2025 12:02:41 +0200 Subject: [PATCH 10/10] wip Signed-off-by: Jan Kowalleck --- cyclonedx/model/vulnerability.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cyclonedx/model/vulnerability.py b/cyclonedx/model/vulnerability.py index d328a12e..b217583a 100644 --- a/cyclonedx/model/vulnerability.py +++ b/cyclonedx/model/vulnerability.py @@ -635,8 +635,9 @@ def get_localised_vector(self, vector: str) -> str: """ if self is VulnerabilityScoreSource.CVSS_V4 and vector.startswith('CVSS:4.'): return re.sub(r'^CVSS:4\.\d/?', '', vector) - if (self is VulnerabilityScoreSource.CVSS_V3_1 or self is VulnerabilityScoreSource.CVSS_V3) \ - and vector.startswith('CVSS:3.'): + if ( + self in (VulnerabilityScoreSource.CVSS_V3_1, VulnerabilityScoreSource.CVSS_V3) + ) and vector.startswith('CVSS:3.'): return re.sub(r'^CVSS:3\.\d/?', '', vector) if self is VulnerabilityScoreSource.CVSS_V2 and vector.startswith('CVSS:2.'): return re.sub(r'^CVSS:2\.\d/?', '', vector)