Skip to content

Commit be8d607

Browse files
committed
feat: prepare "contrib" area
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
1 parent c0ca9bc commit be8d607

9 files changed

Lines changed: 118 additions & 39 deletions

File tree

cyclonedx/contrib/component/builders.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919

2020

2121
from hashlib import sha1
22-
from typing import Optional
2322
from os.path import exists
23+
from typing import Optional
2424

25-
from ...model import HashType, HashAlgorithm
25+
from ...model import HashAlgorithm, HashType
2626
from ...model.component import Component, ComponentType
2727

28+
2829
class ComponentBuilder:
2930

3031
def make_for_file(self, absolute_file_path: str, *,

cyclonedx/contrib/hash/factories.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@
1919

2020
__all__ = ['HashTypeFactory']
2121

22-
from ...model import HashType, HashAlgorithm
23-
2422
from ...exception.model import UnknownHashTypeException
25-
26-
23+
from ...model import HashAlgorithm, HashType
2724

2825
_MAP_HASHLIB: dict[str, HashAlgorithm] = {
2926
# from hashlib.algorithms_guaranteed
@@ -43,6 +40,7 @@
4340
# shake_256:
4441
}
4542

43+
4644
class HashTypeFactory:
4745

4846
def from_hashlib_alg(self, hashlib_alg: str, content: str) -> HashType:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This file is part of CycloneDX Python Library
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
"""Vulnerability related functionality"""
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# This file is part of CycloneDX Python Library
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
# SPDX-License-Identifier: Apache-2.0
16+
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
18+
"""CVSS related utilities"""
19+
20+
__all__ = ['vs_from_cvss_scores']
21+
22+
from typing import Union
23+
24+
from ...model.vulnerability import VulnerabilitySeverity
25+
26+
27+
def vs_from_cvss_scores(scores: Union[tuple[float, ...], float, None]) -> VulnerabilitySeverity:
28+
"""
29+
Derives the Severity of a Vulnerability from it's declared CVSS scores.
30+
31+
Args:
32+
scores: A `tuple` of CVSS scores. CVSS scoring system allows for up to three separate scores.
33+
34+
Returns:
35+
Always returns an instance of :class:`cyclonedx.model.vulnerability.VulnerabilitySeverity`.
36+
"""
37+
if type(scores) is float:
38+
scores = (scores,)
39+
40+
if scores is None:
41+
return VulnerabilitySeverity.UNKNOWN
42+
43+
max_cvss_score: float
44+
if isinstance(scores, tuple):
45+
max_cvss_score = max(scores)
46+
else:
47+
max_cvss_score = float(scores)
48+
49+
if max_cvss_score >= 9.0:
50+
return VulnerabilitySeverity.CRITICAL
51+
elif max_cvss_score >= 7.0:
52+
return VulnerabilitySeverity.HIGH
53+
elif max_cvss_score >= 4.0:
54+
return VulnerabilitySeverity.MEDIUM
55+
elif max_cvss_score > 0.0:
56+
return VulnerabilitySeverity.LOW
57+
else:
58+
return VulnerabilitySeverity.NONE

cyclonedx/model/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from typing import Any, Optional, Union
3232
from urllib.parse import quote as url_quote
3333
from uuid import UUID
34-
from warnings import warn, deprecated
34+
from warnings import deprecated, warn
3535
from xml.etree.ElementTree import Element as XmlElement # nosec B405
3636

3737
import py_serializable as serializable

cyclonedx/model/bom.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import py_serializable as serializable
2828
from sortedcontainers import SortedSet
29+
from typing_extensions import deprecated
2930

3031
from .._internal.compare import ComparableTuple as _ComparableTuple
3132
from .._internal.time import get_now_utc as _get_now_utc
@@ -706,6 +707,8 @@ def get_component_by_purl(self, purl: Optional['PackageURL']) -> Optional[Compon
706707
707708
Returns:
708709
`Component` or `None`
710+
711+
.. deprecated:: next
709712
"""
710713
if purl:
711714
found = [x for x in self.components if x.purl == purl]
@@ -720,6 +723,8 @@ def get_urn_uuid(self) -> str:
720723
721724
Returns:
722725
URN formatted UUID that uniquely identified this Bom instance.
726+
727+
.. deprecated:: next
723728
"""
724729
return self.serial_number.urn
725730

@@ -733,6 +738,8 @@ def has_component(self, component: Component) -> bool:
733738
734739
Returns:
735740
`bool` - `True` if the supplied Component is part of this Bom, `False` otherwise.
741+
742+
.. deprecated:: next
736743
"""
737744
return component in self.components
738745

@@ -751,6 +758,8 @@ def get_vulnerabilities_for_bom_ref(self, bom_ref: BomRef) -> 'SortedSet[Vulnera
751758
752759
Returns:
753760
`SortedSet` of `Vulnerability`
761+
762+
.. deprecated:: next
754763
"""
755764

756765
vulnerabilities: SortedSet[Vulnerability] = SortedSet()
@@ -766,6 +775,8 @@ def has_vulnerabilities(self) -> bool:
766775
767776
Returns:
768777
`bool` - `True` if this Bom has at least one Vulnerability, `False` otherwise.
778+
779+
.. deprecated:: next
769780
"""
770781
return bool(self.vulnerabilities)
771782

@@ -788,6 +799,10 @@ def register_dependency(self, target: Dependable, depends_on: Optional[Iterable[
788799
self.register_dependency(target=_d2, depends_on=None)
789800

790801
def urn(self) -> str:
802+
"""
803+
.. deprecated:: next
804+
"""
805+
# idea: have 'serial_number' be a string, and use it instead of this method
791806
return f'{_BOM_LINK_PREFIX}{self.serial_number}/{self.version}'
792807

793808
def validate(self) -> bool:
@@ -797,7 +812,10 @@ def validate(self) -> bool:
797812
798813
Returns:
799814
`bool`
815+
816+
.. deprecated:: next
800817
"""
818+
# !! deprecated function. have this as an part of the normlization process, like the BomRefDiscrimator
801819
# 0. Make sure all Dependable have a Dependency entry
802820
if self.metadata.component:
803821
self.register_dependency(target=self.metadata.component)

cyclonedx/model/component.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@
4949
from . import (
5050
AttachedText,
5151
ExternalReference,
52+
HashAlgorithm,
5253
HashType,
5354
IdentifiableAction,
5455
Property,
5556
XsUri,
56-
_HashTypeRepositorySerializationHelper, HashAlgorithm,
57+
_HashTypeRepositorySerializationHelper,
5758
)
5859
from .bom_ref import BomRef
5960
from .component_evidence import ComponentEvidence, _ComponentEvidenceSerializationHelper
@@ -966,8 +967,8 @@ def for_file(absolute_file_path: str, path_for_bom: Optional[str]) -> 'Component
966967

967968
component = ComponentBuilder().make_for_file(absolute_file_path, name=path_for_bom)
968969
sha1_hash = next(h.content for h in component.hashes if h.alg is HashAlgorithm.SHA_1)
969-
component.version=f'0.0.0-{sha1_hash[0:12]}'
970-
component.purl=PackageURL( # DEPRECATED: a file has no PURL!
970+
component.version = f'0.0.0-{sha1_hash[0:12]}'
971+
component.purl = PackageURL( # DEPRECATED: a file has no PURL!
971972
type='generic', name=path_for_bom if path_for_bom else absolute_file_path,
972973
version=f'0.0.0-{sha1_hash[0:12]}'
973974
)

cyclonedx/model/license.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@ class LicenseAcknowledgement(str, Enum):
5959
# In an error, the name of the enum was `LicenseExpressionAcknowledgement`.
6060
# Even though this was changed, there might be some downstream usage of this symbol, so we keep it around ...
6161
LicenseExpressionAcknowledgement = LicenseAcknowledgement
62-
"""Deprecated alias for :class:`LicenseAcknowledgement`"""
62+
"""Deprecated - Alias for :class:`LicenseAcknowledgement`
63+
64+
.. deprecated:: next Import `LicenseAcknowledgement` instead.
65+
The exported original symbol itself is NOT deprecated - only this import path.
66+
"""
6367

6468

6569
@serializable.serializable_class(

cyclonedx/model/vulnerability.py

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
import py_serializable as serializable
4040
from sortedcontainers import SortedSet
41+
from typing_extensions import deprecated
4142

4243
from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str
4344
from .._internal.compare import ComparableTuple as _ComparableTuple
@@ -724,38 +725,18 @@ class VulnerabilitySeverity(str, Enum):
724725
UNKNOWN = 'unknown'
725726

726727
@staticmethod
728+
@deprecated('Deprecated - use cyclonedx.contrib.vulnerability.cvss.vs_from_cvss_scores instead')
727729
def get_from_cvss_scores(scores: Union[tuple[float, ...], float, None]) -> 'VulnerabilitySeverity':
728-
"""
730+
"""Deprecated — Alias of :func:`cyclonedx.contrib.vulnerability.cvss.vs_from_cvss_scores()`.
731+
729732
Derives the Severity of a Vulnerability from it's declared CVSS scores.
730733
731-
Args:
732-
scores: A `tuple` of CVSS scores. CVSS scoring system allows for up to three separate scores.
734+
.. deprecated:: next
735+
Use ``cyclonedx.contrib.vulnerability.cvss.VulnerabilitySeverity_from_cvss_scores()`` instead.
736+
"""
737+
from ..contrib.vulnerability.cvss import vs_from_cvss_scores
733738

734-
Returns:
735-
Always returns an instance of `VulnerabilitySeverity`.
736-
"""
737-
if type(scores) is float:
738-
scores = (scores,)
739-
740-
if scores is None:
741-
return VulnerabilitySeverity.UNKNOWN
742-
743-
max_cvss_score: float
744-
if isinstance(scores, tuple):
745-
max_cvss_score = max(scores)
746-
else:
747-
max_cvss_score = float(scores)
748-
749-
if max_cvss_score >= 9.0:
750-
return VulnerabilitySeverity.CRITICAL
751-
elif max_cvss_score >= 7.0:
752-
return VulnerabilitySeverity.HIGH
753-
elif max_cvss_score >= 4.0:
754-
return VulnerabilitySeverity.MEDIUM
755-
elif max_cvss_score > 0.0:
756-
return VulnerabilitySeverity.LOW
757-
else:
758-
return VulnerabilitySeverity.NONE
739+
return vs_from_cvss_scores(scores)
759740

760741

761742
@serializable.serializable_class(ignore_unknown_during_deserialization=True)

0 commit comments

Comments
 (0)