diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index 4debf421..9c4b8cad 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -18,6 +18,7 @@ from collections.abc import Generator, Iterable from datetime import datetime +from enum import Enum from itertools import chain from typing import TYPE_CHECKING, Optional, Union from uuid import UUID, uuid4 @@ -56,6 +57,81 @@ from packageurl import PackageURL +@serializable.serializable_enum +class TlpClassification(str, Enum): + """ + Enum object that defines the Traffic Light Protocol (TLP) classification that controls the sharing and distribution + of the data that the BOM describes. + + .. note:: + Introduced in CycloneDX v1.7 + + .. note:: + See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.7/xml/#type_tlpClassificationType + """ + + CLEAR = 'CLEAR' + GREEN = 'GREEN' + AMBER = 'AMBER' + AMBER_AND_STRICT = 'AMBER_AND_STRICT' + RED = 'RED' + + +@serializable.serializable_class(ignore_unknown_during_deserialization=True) +class DistributionConstraints: + """ + Our internal representation of the `distributionConstraints` complex type. + Conditions and constraints governing the sharing and distribution of the data or components described by this BOM. + + .. note:: + Introduced in CycloneDX v1.7 + + .. note:: + See the CycloneDX Schema definition: https://cyclonedx.org/docs/1.7/xml/#type_metadata + """ + + def __init__( + self, *, + tlp: Optional[TlpClassification] = None, + ) -> None: + self.tlp = tlp or TlpClassification.CLEAR + + @property + @serializable.xml_sequence(0) + def tlp(self) -> TlpClassification: + """ + The Traffic Light Protocol (TLP) classification that controls the sharing and distribution of the data that the + BOM describes. + + Returns: + `TlpClassification` enum value + """ + return self._tlp + + @tlp.setter + def tlp(self, tlp: TlpClassification) -> None: + self._tlp = tlp + + def __comparable_tuple(self) -> _ComparableTuple: + return _ComparableTuple(self.tlp) + + def __eq__(self, other: object) -> bool: + if isinstance(other, DistributionConstraints): + return self.__comparable_tuple() == other.__comparable_tuple() + return False + + def __lt__(self, other: object) -> bool: + if isinstance(other, DistributionConstraints): + return self.__comparable_tuple() < other.__comparable_tuple() + return NotImplemented + + def __hash__(self) -> int: + return hash(self.__comparable_tuple()) + + def __repr__(self) -> str: + return f'' + + @serializable.serializable_class(ignore_unknown_during_deserialization=True) class BomMetaData: """ @@ -76,6 +152,7 @@ def __init__( timestamp: Optional[datetime] = None, manufacturer: Optional[OrganizationalEntity] = None, lifecycles: Optional[Iterable[Lifecycle]] = None, + distribution_constraints: Optional[DistributionConstraints] = None, # Deprecated as of v1.6 manufacture: Optional[OrganizationalEntity] = None, ) -> None: @@ -88,6 +165,7 @@ def __init__( self.properties = properties or [] self.manufacturer = manufacturer self.lifecycles = lifecycles or [] + self.distribution_constraints = distribution_constraints # deprecated properties below self.manufacture = manufacture @@ -301,10 +379,27 @@ def properties(self) -> 'SortedSet[Property]': def properties(self, properties: Iterable[Property]) -> None: self._properties = SortedSet(properties) + @property + @serializable.view(SchemaVersion1Dot7) + @serializable.xml_sequence(11) + def distribution_constraints(self) -> Optional[DistributionConstraints]: + """ + Conditions and constraints governing the sharing and distribution of the data or components described by this + BOM. + + Returns: + `DistributionConstraints` or `None` + """ + return self._distribution_constraints + + @distribution_constraints.setter + def distribution_constraints(self, distribution_constraints: Optional[DistributionConstraints]) -> None: + self._distribution_constraints = distribution_constraints + def __comparable_tuple(self) -> _ComparableTuple: return _ComparableTuple(( _ComparableTuple(self.authors), self.component, _ComparableTuple(self.licenses), self.manufacture, - _ComparableTuple(self.properties), + _ComparableTuple(self.properties), self.distribution_constraints, _ComparableTuple(self.lifecycles), self.supplier, self.timestamp, self.tools, self.manufacturer )) diff --git a/tests/_data/models.py b/tests/_data/models.py index 8d3a089d..793006a4 100644 --- a/tests/_data/models.py +++ b/tests/_data/models.py @@ -42,7 +42,7 @@ Property, XsUri, ) -from cyclonedx.model.bom import Bom, BomMetaData +from cyclonedx.model.bom import Bom, BomMetaData, DistributionConstraints, TlpClassification from cyclonedx.model.bom_ref import BomRef from cyclonedx.model.component import ( Commit, @@ -582,6 +582,7 @@ def get_bom_just_complete_metadata() -> Bom: )] bom.metadata.lifecycles = [PredefinedLifecycle(LifecyclePhase.BUILD)] bom.metadata.properties = get_properties_1() + bom.metadata.distribution_constraints = DistributionConstraints(tlp=TlpClassification.GREEN) return bom @@ -1403,6 +1404,17 @@ def get_bom_with_lifecycles() -> Bom: ) +def get_bom_with_distribution_constraints() -> Bom: + return _make_bom( + metadata=BomMetaData( + distribution_constraints=DistributionConstraints( + tlp=TlpClassification.AMBER_AND_STRICT + ), + component=Component(name='app', type=ComponentType.APPLICATION, bom_ref='my-app'), + ) + ) + + def get_bom_with_definitions_standards() -> Bom: """ Returns a BOM with definitions and standards only. @@ -1584,6 +1596,7 @@ def get_bom_for_issue540_duplicate_components() -> Bom: get_bom_with_component_setuptools_with_v16_fields, get_bom_for_issue_630_empty_property, get_bom_with_lifecycles, + get_bom_with_distribution_constraints, get_bom_with_definitions_standards, get_bom_with_definitions_and_detailed_standards, } diff --git a/tests/_data/snapshots/enum_TlpClassification-1.0.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.0.xml.bin new file mode 100644 index 00000000..acb06612 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.0.xml.bin @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.1.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.1.xml.bin new file mode 100644 index 00000000..55ef5cda --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.1.xml.bin @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.2.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.2.json.bin new file mode 100644 index 00000000..8f473bd3 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.2.json.bin @@ -0,0 +1,10 @@ +{ + "metadata": { + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.2" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.2.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.2.xml.bin new file mode 100644 index 00000000..df1938ec --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.2.xml.bin @@ -0,0 +1,6 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.3.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.3.json.bin new file mode 100644 index 00000000..02943890 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.3.json.bin @@ -0,0 +1,10 @@ +{ + "metadata": { + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.3" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.3.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.3.xml.bin new file mode 100644 index 00000000..8341ff60 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.3.xml.bin @@ -0,0 +1,6 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.4.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.4.json.bin new file mode 100644 index 00000000..48f1745d --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.4.json.bin @@ -0,0 +1,10 @@ +{ + "metadata": { + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.4" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.4.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.4.xml.bin new file mode 100644 index 00000000..d0a7d4c9 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.4.xml.bin @@ -0,0 +1,6 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.5.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.5.json.bin new file mode 100644 index 00000000..57b5e590 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.5.json.bin @@ -0,0 +1,20 @@ +{ + "metadata": { + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.5" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.5.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.5.xml.bin new file mode 100644 index 00000000..f952637c --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.5.xml.bin @@ -0,0 +1,10 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + val1 + val2 + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.6.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.6.json.bin new file mode 100644 index 00000000..b93790d4 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.6.json.bin @@ -0,0 +1,20 @@ +{ + "metadata": { + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.6.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.6.xml.bin new file mode 100644 index 00000000..6faca474 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.6.xml.bin @@ -0,0 +1,10 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + val1 + val2 + + diff --git a/tests/_data/snapshots/enum_TlpClassification-1.7.json.bin b/tests/_data/snapshots/enum_TlpClassification-1.7.json.bin new file mode 100644 index 00000000..e5f7f9c2 --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.7.json.bin @@ -0,0 +1,23 @@ +{ + "metadata": { + "distributionConstraints": { + "tlp": "CLEAR" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7" +} \ No newline at end of file diff --git a/tests/_data/snapshots/enum_TlpClassification-1.7.xml.bin b/tests/_data/snapshots/enum_TlpClassification-1.7.xml.bin new file mode 100644 index 00000000..5f78c14a --- /dev/null +++ b/tests/_data/snapshots/enum_TlpClassification-1.7.xml.bin @@ -0,0 +1,13 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + CLEAR + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.json.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.json.bin index 24e062a6..4869ed92 100644 --- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.json.bin +++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.json.bin @@ -367,6 +367,9 @@ "type": "library", "version": "50.3.2" }, + "distributionConstraints": { + "tlp": "GREEN" + }, "licenses": [ { "license": { diff --git a/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.xml.bin b/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.xml.bin index ac12da27..d188f978 100644 --- a/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.xml.bin +++ b/tests/_data/snapshots/get_bom_just_complete_metadata-1.7.xml.bin @@ -317,6 +317,9 @@ val1 val2 + + GREEN + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.0.xml.bin new file mode 100644 index 00000000..acb06612 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.0.xml.bin @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.1.xml.bin new file mode 100644 index 00000000..55ef5cda --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.1.xml.bin @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.json.bin new file mode 100644 index 00000000..18150abd --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.json.bin @@ -0,0 +1,21 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application", + "version": "" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.2" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.xml.bin new file mode 100644 index 00000000..5fb21515 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.2.xml.bin @@ -0,0 +1,13 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.json.bin new file mode 100644 index 00000000..fd64f145 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.json.bin @@ -0,0 +1,21 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application", + "version": "" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.3" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.xml.bin new file mode 100644 index 00000000..7bb6d933 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.3.xml.bin @@ -0,0 +1,13 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.json.bin new file mode 100644 index 00000000..19983566 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.json.bin @@ -0,0 +1,20 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.4" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.xml.bin new file mode 100644 index 00000000..118c192f --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.4.xml.bin @@ -0,0 +1,12 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.json.bin new file mode 100644 index 00000000..c37c40f3 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.json.bin @@ -0,0 +1,30 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.5" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.xml.bin new file mode 100644 index 00000000..77a416bc --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.5.xml.bin @@ -0,0 +1,16 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.json.bin new file mode 100644 index 00000000..7085323c --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.json.bin @@ -0,0 +1,30 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.xml.bin new file mode 100644 index 00000000..d8276254 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.6.xml.bin @@ -0,0 +1,16 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.json.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.json.bin new file mode 100644 index 00000000..ae96fe14 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.json.bin @@ -0,0 +1,33 @@ +{ + "dependencies": [ + { + "ref": "my-app" + } + ], + "metadata": { + "component": { + "bom-ref": "my-app", + "name": "app", + "type": "application" + }, + "distributionConstraints": { + "tlp": "AMBER_AND_STRICT" + }, + "timestamp": "2023-01-07T13:44:32.312678+00:00" + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ], + "serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac", + "version": 1, + "$schema": "http://cyclonedx.org/schema/bom-1.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.xml.bin b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.xml.bin new file mode 100644 index 00000000..2167d67f --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_distribution_constraints-1.7.xml.bin @@ -0,0 +1,19 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + app + + + AMBER_AND_STRICT + + + + + + + val1 + val2 + + diff --git a/tests/test_enums.py b/tests/test_enums.py index f769388e..1d749d63 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -30,7 +30,7 @@ from cyclonedx.exception import MissingOptionalDependencyException from cyclonedx.exception.serialization import SerializationOfUnsupportedComponentTypeException from cyclonedx.model import AttachedText, ExternalReference, HashType, XsUri -from cyclonedx.model.bom import Bom, BomMetaData +from cyclonedx.model.bom import Bom, BomMetaData, DistributionConstraints, TlpClassification from cyclonedx.model.component import Component, Patch, Pedigree from cyclonedx.model.issue import IssueType from cyclonedx.model.license import DisjunctiveLicense @@ -490,3 +490,21 @@ def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, lifecycles=[PredefinedLifecycle(phase=phase) for phase in LifecyclePhase] )) super()._test_cases_render(bom, of, sv) + + +@ddt +class TestEnumTlpClassification(_EnumTestCase): + + @idata(set(chain( + dp_cases_from_xml_schemas(f"./{SCHEMA_NS}simpleType[@name='tlpClassificationType']"), + dp_cases_from_json_schemas('definitions', 'tlpClassification'), + ))) + def test_knows_value(self, value: str) -> None: + super()._test_knows_value(TlpClassification, value) + + @named_data(*NAMED_OF_SV) + def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None: + bom = _make_bom(metadata=BomMetaData( + distribution_constraints=DistributionConstraints(tlp=TlpClassification.CLEAR) + )) + super()._test_cases_render(bom, of, sv) diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py index edd5b9a6..030ee4a5 100644 --- a/tests/test_model_bom.py +++ b/tests/test_model_bom.py @@ -16,6 +16,7 @@ # Copyright (c) OWASP Foundation. All Rights Reserved. import warnings from collections.abc import Callable +from random import shuffle from unittest import TestCase from uuid import uuid4 @@ -23,7 +24,7 @@ from cyclonedx.exception.model import LicenseExpressionAlongWithOthersException from cyclonedx.model import Property -from cyclonedx.model.bom import Bom, BomMetaData +from cyclonedx.model.bom import Bom, BomMetaData, DistributionConstraints, TlpClassification from cyclonedx.model.bom_ref import BomRef from cyclonedx.model.component import Component, ComponentType from cyclonedx.model.contact import OrganizationalContact, OrganizationalEntity @@ -31,6 +32,7 @@ from cyclonedx.model.lifecycle import LifecyclePhase, NamedLifecycle, PredefinedLifecycle from cyclonedx.model.tool import Tool from cyclonedx.output.json import JsonV1Dot7 +from tests import reorder from tests._data.models import ( get_bom_component_licenses_invalid, get_bom_component_nested_licenses_invalid, @@ -45,6 +47,43 @@ ) +class TestDistributionConstraints(TestCase): + + def test_create(self) -> None: + dc = DistributionConstraints(tlp=TlpClassification.GREEN) + self.assertIs(TlpClassification.GREEN, dc.tlp) + + def test_update(self) -> None: + dc = DistributionConstraints(tlp=TlpClassification.AMBER_AND_STRICT) + dc.tlp = TlpClassification.RED + self.assertIs(TlpClassification.RED, dc.tlp) + + def test_equal(self) -> None: + a = DistributionConstraints(tlp=TlpClassification.GREEN) + b = DistributionConstraints(tlp=TlpClassification.GREEN) + c = DistributionConstraints(tlp=TlpClassification.RED) + self.assertEqual(a, b) + self.assertNotEqual(a, c) + + def test_sort(self) -> None: + expected_order = [2, 1, 3, 0] + dcs = [ + DistributionConstraints(tlp=TlpClassification.RED), + DistributionConstraints(tlp=TlpClassification.AMBER), + DistributionConstraints(tlp=TlpClassification.AMBER_AND_STRICT), + DistributionConstraints(tlp=TlpClassification.CLEAR), + ] + expected_dcs = reorder(dcs, expected_order) + shuffle(dcs) + sorted_dcs = sorted(dcs) + self.assertListEqual(sorted_dcs, expected_dcs) + + def test_create_distribution_constraints(self) -> None: + dc = DistributionConstraints(tlp=TlpClassification.AMBER) + self.assertIsNotNone(dc) + self.assertEqual(TlpClassification.AMBER, dc.tlp) + + class TestBomMetaData(TestCase): def test_empty_bom_metadata(self) -> None: @@ -54,6 +93,7 @@ def test_empty_bom_metadata(self) -> None: self.assertIsNone(metadata.component) self.assertIsNone(metadata.manufacture) self.assertIsNone(metadata.supplier) + self.assertIsNone(metadata.distribution_constraints) self.assertEqual(0, len(metadata.licenses)) self.assertEqual(0, len(metadata.lifecycles)) self.assertEqual(0, len(metadata.properties)) @@ -83,9 +123,11 @@ def test_basic_bom_metadata(self) -> None: Property(name='property_1', value='value_1'), Property(name='property_2', value='value_2', ) ] + distribution_constraints = DistributionConstraints(tlp=TlpClassification.CLEAR) metadata = BomMetaData(tools=tools, authors=authors, component=component, lifecycles=lifecycles, - manufacture=manufacturer, supplier=supplier, licenses=licenses, properties=properties) + manufacture=manufacturer, supplier=supplier, licenses=licenses, properties=properties, + distribution_constraints=distribution_constraints) self.assertIsNotNone(metadata.timestamp) self.assertIsNotNone(metadata.authors) self.assertTrue(authors[0] in metadata.authors) @@ -106,6 +148,7 @@ def test_basic_bom_metadata(self) -> None: self.assertEqual(2, len(metadata.tools.tools)) self.assertTrue(tools[0] in metadata.tools.tools) self.assertTrue(tools[1] in metadata.tools.tools) + self.assertEqual(metadata.distribution_constraints, distribution_constraints) def test_bom_metadata_sorting(self) -> None: """Test that BomMetaData instances can be sorted without triggering TypeError"""