From c1b71ab5055b684aae1e160582dda1c10671ee80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ondrej=20Baranovi=C4=8D?= Date: Fri, 28 Aug 2026 17:17:53 +0200 Subject: [PATCH] feat: Add version_range property to Component for CycloneDX v1.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the versionRange property for Compoments as specified in the CycloneDX v1.7 schema. The versionRange can be specified instead of the version for external components to specify the accepted version range. * Add version_range property to Component with serialization decorators. * Adjust Component.__repr__ to show whether a component is external and the version_range if provided. * Extend Bom.validate with validation for CycloneDX v1.7 requirements regarding versionRange and isExternal. * Add unit tests for Component.version_range proprety and Bom.validate changes. * Add serialization snapshot tests for various kinds of external components. Implements part of #903 Signed-off-by: Ondrej Baranovič --- cyclonedx/model/bom.py | 14 ++- cyclonedx/model/component.py | 78 ++++++++++++++-- tests/_data/models.py | 88 +++++++++++++++++-- ...ternal_component_with_version-1.0.xml.bin} | 1 - ...ternal_component_with_version-1.1.xml.bin} | 1 - ...ernal_component_with_version-1.2.json.bin} | 1 - ...ternal_component_with_version-1.2.xml.bin} | 1 - ...ernal_component_with_version-1.3.json.bin} | 1 - ...ternal_component_with_version-1.3.xml.bin} | 1 - ...ernal_component_with_version-1.4.json.bin} | 1 - ...ternal_component_with_version-1.4.xml.bin} | 1 - ...ernal_component_with_version-1.5.json.bin} | 1 - ...ternal_component_with_version-1.5.xml.bin} | 1 - ...ernal_component_with_version-1.6.json.bin} | 1 - ...ternal_component_with_version-1.6.xml.bin} | 1 - ...ernal_component_with_version-1.7.json.bin} | 1 - ...ternal_component_with_version-1.7.xml.bin} | 1 - ...l_component_with_version_range-1.0.xml.bin | 10 +++ ...l_component_with_version_range-1.1.xml.bin | 9 ++ ..._component_with_version_range-1.2.json.bin | 23 +++++ ...l_component_with_version_range-1.2.xml.bin | 15 ++++ ..._component_with_version_range-1.3.json.bin | 23 +++++ ...l_component_with_version_range-1.3.xml.bin | 15 ++++ ..._component_with_version_range-1.4.json.bin | 22 +++++ ...l_component_with_version_range-1.4.xml.bin | 14 +++ ..._component_with_version_range-1.5.json.bin | 32 +++++++ ...l_component_with_version_range-1.5.xml.bin | 18 ++++ ..._component_with_version_range-1.6.json.bin | 32 +++++++ ...l_component_with_version_range-1.6.xml.bin | 18 ++++ ..._component_with_version_range-1.7.json.bin | 34 +++++++ ...l_component_with_version_range-1.7.xml.bin | 19 ++++ ...rnal_component_without_version-1.0.xml.bin | 10 +++ ...rnal_component_without_version-1.1.xml.bin | 9 ++ ...nal_component_without_version-1.2.json.bin | 23 +++++ ...rnal_component_without_version-1.2.xml.bin | 15 ++++ ...nal_component_without_version-1.3.json.bin | 23 +++++ ...rnal_component_without_version-1.3.xml.bin | 15 ++++ ...nal_component_without_version-1.4.json.bin | 22 +++++ ...rnal_component_without_version-1.4.xml.bin | 14 +++ ...nal_component_without_version-1.5.json.bin | 32 +++++++ ...rnal_component_without_version-1.5.xml.bin | 18 ++++ ...nal_component_without_version-1.6.json.bin | 32 +++++++ ...rnal_component_without_version-1.6.xml.bin | 18 ++++ ...nal_component_without_version-1.7.json.bin | 33 +++++++ ...rnal_component_without_version-1.7.xml.bin | 18 ++++ tests/test_model_bom.py | 7 ++ tests/test_model_component.py | 21 +++++ tests/test_output_json.py | 2 + tests/test_output_xml.py | 2 + 49 files changed, 766 insertions(+), 26 deletions(-) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.0.xml.bin => get_bom_with_external_component_with_version-1.0.xml.bin} (89%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.1.xml.bin => get_bom_with_external_component_with_version-1.1.xml.bin} (91%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.2.json.bin => get_bom_with_external_component_with_version-1.2.json.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.2.xml.bin => get_bom_with_external_component_with_version-1.2.xml.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.3.json.bin => get_bom_with_external_component_with_version-1.3.json.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.3.xml.bin => get_bom_with_external_component_with_version-1.3.xml.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.4.json.bin => get_bom_with_external_component_with_version-1.4.json.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.4.xml.bin => get_bom_with_external_component_with_version-1.4.xml.bin} (94%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.5.json.bin => get_bom_with_external_component_with_version-1.5.json.bin} (95%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.5.xml.bin => get_bom_with_external_component_with_version-1.5.xml.bin} (95%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.6.json.bin => get_bom_with_external_component_with_version-1.6.json.bin} (95%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.6.xml.bin => get_bom_with_external_component_with_version-1.6.xml.bin} (95%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.7.json.bin => get_bom_with_external_component_with_version-1.7.json.bin} (96%) rename tests/_data/snapshots/{get_bom_with_external_component_1_7-1.7.xml.bin => get_bom_with_external_component_with_version-1.7.xml.bin} (95%) create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.0.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.1.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.0.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.1.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.xml.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.json.bin create mode 100644 tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.xml.bin diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index 7cb0081e9..687afaf4d 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -44,7 +44,7 @@ from ..serialization import UrnUuidHelper from . import _BOM_LINK_PREFIX, ExternalReference, Property from .bom_ref import BomRef -from .component import Component +from .component import Component, _ComponentValidationHelper from .contact import OrganizationalContact, OrganizationalEntity from .definition import Definitions from .dependency import Dependable, Dependency @@ -863,6 +863,18 @@ def validate(self) -> bool: raise LicenseExpressionAlongWithOthersException( f'Found LicenseExpression along with others licenses in: {elem!r}') + # 4. Validates that each component conforms to CycloneDX 1.7 constraints: + # - root component may not have is_external=true + # - version and version_range are mutually exclusive + # - version_range requires is_external=true + if self.metadata.component and self.metadata.component.is_external: + warn( + f'The Component this BOM is describing {self.metadata.component.purl} must not have is_external=true.', + category=UserWarning, stacklevel=1 + ) + for _c in self._get_all_components(): + _ComponentValidationHelper.validate(_c) + return True def __comparable_tuple(self) -> _ComparableTuple: diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py index bc7152aeb..bd83ee349 100644 --- a/cyclonedx/model/component.py +++ b/cyclonedx/model/component.py @@ -34,7 +34,7 @@ from .._internal.bom_ref import bom_ref_from_str as _bom_ref_from_str from .._internal.compare import ComparablePackageURL as _ComparablePackageURL, ComparableTuple as _ComparableTuple -from ..exception.model import InvalidOmniBorIdException, InvalidSwhidException +from ..exception.model import InvalidOmniBorIdException, InvalidSwhidException, MutuallyExclusivePropertiesException from ..exception.serialization import ( CycloneDxDeserializationException, SerializationOfUnexpectedValueException, @@ -991,6 +991,7 @@ def __init__( publisher: Optional[str] = None, group: Optional[str] = None, version: Optional[str] = None, + version_range: Optional[str] = None, description: Optional[str] = None, scope: Optional[ComponentScope] = None, is_external: Optional[bool] = None, @@ -1025,6 +1026,8 @@ def __init__( self.publisher = publisher self.group = group self.name = name + self.version = version + self.version_range = version_range self.description = description self.scope = scope self.is_external = is_external @@ -1047,7 +1050,6 @@ def __init__( # spec-deprecated properties below self.author = author self.modified = modified - self.version = version @property @serializable.type_mapping(_ComponentTypeSerializationHelper) @@ -1272,6 +1274,34 @@ def version(self, version: Optional[str]) -> None: warn('`@.version`has a maximum length of 1024 from CycloneDX v1.6 onwards.', UserWarning) self._version = version + @property + @serializable.view(SchemaVersion1Dot7) + @serializable.json_name('versionRange') + @serializable.xml_name('versionRange') + @serializable.xml_sequence(8) + @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) + def version_range(self) -> Optional[str]: + """ + For an external component, this specifies the accepted version range. + + The value must adhere to the Package URL Version Range syntax (vers), as defined at + https://github.com/package-url/vers-spec + + May only be used if .isExternal is set to true. + + Must be used exclusively, either 'version' or 'version_range', but not both. + + Returns: + `str` if set, else `None` + """ + return self._version_range + + @version_range.setter + def version_range(self, version_range: Optional[str]) -> None: + if version_range and not 1 <= len(version_range) <= 4096: + warn('`@.version_range`has a minimum length of 1 and a maximum length of 4096 characters.', UserWarning) + self._version_range = version_range + @property @serializable.xml_sequence(9) @serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING) @@ -1702,7 +1732,7 @@ def get_pypi_url(self) -> str: def __comparable_tuple(self) -> _ComparableTuple: return _ComparableTuple(( - self.type, self.group, self.name, self.version, + self.type, self.group, self.name, self.version, self.version_range, self.bom_ref.value, None if self.purl is None else _ComparablePackageURL(self.purl), self.swid, self.cpe, _ComparableTuple(self.swhids), @@ -1732,5 +1762,43 @@ def __hash__(self) -> int: return hash(self.__comparable_tuple()) def __repr__(self) -> str: - return f'' + if not self.is_external: + # omit is_external unless it is set to the non-default value (i.e. True) + return f'' + elif self.version_range is None: + return f'' + else: + return f'' + + +class _ComponentValidationHelper: + """ THIS CLASS IS NON-PUBLIC API """ + + @staticmethod + def validate_version_choice(component: Component) -> None: + """ Validates that version and version_range are not both set. """ + if component.version is not None and component.version_range is not None: + raise MutuallyExclusivePropertiesException( + f'Component cannot have both `version` and `version_range` set. Component: {component.name}' + ) + + @staticmethod + def validate_version_range_requirements(component: Component) -> None: + """ Validates that version_range is used correctly with is_external. """ + if component.version_range is not None and not component.is_external: + raise MutuallyExclusivePropertiesException( + f'Component cannot have `version_range` set unless `is_external=true`. Component: {component.name}' + ) + + @staticmethod + def validate(component: Component) -> None: + """ + Validates that the component conforms to CycloneDX 1.7 constraints: + - version and version_range are mutually exclusive + - version_range requires is_external=true + """ + _ComponentValidationHelper.validate_version_choice(component) + _ComponentValidationHelper.validate_version_range_requirements(component) diff --git a/tests/_data/models.py b/tests/_data/models.py index e2052878f..709ec03e4 100644 --- a/tests/_data/models.py +++ b/tests/_data/models.py @@ -599,8 +599,33 @@ def get_bom_with_external_references() -> Bom: return bom -def get_bom_with_external_component_1_7() -> Bom: - bom = _make_bom(components=[get_component_external()]) +def get_bom_with_external_component_without_version() -> Bom: + bom = _make_bom(components=[get_component_external_without_version()]) + return bom + + +def get_bom_with_external_component_with_version() -> Bom: + bom = _make_bom(components=[get_component_external_with_version()]) + return bom + + +def get_bom_with_external_component_with_version_range() -> Bom: + bom = _make_bom(components=[get_component_external_with_version_range()]) + return bom + + +def get_bom_with_external_component_with_version_and_version_range_invalid() -> Bom: + bom = _make_bom(components=[get_component_external_with_version_and_version_range_invalid()]) + return bom + + +def get_bom_with_non_external_explicit_component_with_version_range_invalid() -> Bom: + bom = _make_bom(components=[get_component_non_external_explicit_with_version_range_invalid()]) + return bom + + +def get_bom_with_non_external_implicit_component_with_version_range_invalid() -> Bom: + bom = _make_bom(components=[get_component_non_external_implicit_with_version_range_invalid()]) return bom @@ -864,16 +889,65 @@ def get_component_setuptools_simple( ) -def get_component_external() -> Component: +def get_component_external_without_version() -> Component: return Component( - name='external-lib', version='1.0.0', + name='external-lib', + type=ComponentType.LIBRARY, + is_external=True, + bom_ref='external-lib', + ) + + +def get_component_external_with_version() -> Component: + return Component( + name='external-lib', + version='1.0.0', type=ComponentType.LIBRARY, is_external=True, - scope=ComponentScope.REQUIRED, bom_ref='external-lib-1.0.0', ) +def get_component_external_with_version_range() -> Component: + return Component( + name='external-lib', + version_range='vers:all/*', + type=ComponentType.LIBRARY, + is_external=True, + bom_ref='external-lib-with-range', + ) + + +def get_component_external_with_version_and_version_range_invalid() -> Component: + return Component( + name='external-lib', + version='1.0.0', + version_range='vers:all/*', + type=ComponentType.LIBRARY, + is_external=True, + bom_ref='external-lib-with-version-and-version-range', + ) + + +def get_component_non_external_explicit_with_version_range_invalid() -> Component: + return Component( + name='internal-lib', + version_range='vers:all/*', + type=ComponentType.LIBRARY, + is_external=False, + bom_ref='internal-lib-with-range', + ) + + +def get_component_non_external_implicit_with_version_range_invalid() -> Component: + return Component( + name='internal-lib', + version_range='vers:all/*', + type=ComponentType.LIBRARY, + bom_ref='internal-lib-with-range', + ) + + def get_component_setuptools_simple_no_version(bom_ref: Optional[str] = None) -> Component: return Component( name='setuptools', bom_ref=bom_ref or 'pkg:pypi/setuptools?extension=tar.gz', @@ -1718,7 +1792,9 @@ def get_bom_for_issue941_nested_dependencies_irreversible_migrate() -> Bom: get_bom_with_licenses, get_bom_with_multiple_licenses, get_bom_for_issue_497_urls, - get_bom_with_external_component_1_7, + get_bom_with_external_component_without_version, + get_bom_with_external_component_with_version, + get_bom_with_external_component_with_version_range, get_bom_for_issue_598_multiple_components_with_purl_qualifiers, get_bom_with_component_setuptools_with_v16_fields, get_bom_for_issue_630_empty_property, diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.0.xml.bin similarity index 89% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.0.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.0.xml.bin index aaae83372..431fbb720 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.0.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.0.xml.bin @@ -4,7 +4,6 @@ external-lib 1.0.0 - required false diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.1.xml.bin similarity index 91% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.1.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.1.xml.bin index 06e044d33..41be067a3 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.1.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.1.xml.bin @@ -4,7 +4,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.json.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.json.bin index fe5a4e0ac..08a472a6a 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.json.bin @@ -3,7 +3,6 @@ { "bom-ref": "external-lib-1.0.0", "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.xml.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.xml.bin index 266020af7..a61e8b68f 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.2.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.2.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.json.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.json.bin index 8500a9f79..305418a62 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.json.bin @@ -3,7 +3,6 @@ { "bom-ref": "external-lib-1.0.0", "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.xml.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.xml.bin index 120d5d288..b6c4950da 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.3.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.3.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.json.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.json.bin index c2c3bbea0..aefdb0a52 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.json.bin @@ -3,7 +3,6 @@ { "bom-ref": "external-lib-1.0.0", "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.xml.bin similarity index 94% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.xml.bin index 2d85c7dec..d625e7567 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.4.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.4.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.json.bin similarity index 95% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.json.bin index f3d168966..f1073439a 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.json.bin @@ -3,7 +3,6 @@ { "bom-ref": "external-lib-1.0.0", "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.xml.bin similarity index 95% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.xml.bin index f06f8a0b5..3d43b3a9f 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.5.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.5.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.json.bin similarity index 95% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.json.bin index bf66e8484..67195c68f 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.json.bin @@ -3,7 +3,6 @@ { "bom-ref": "external-lib-1.0.0", "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.xml.bin similarity index 95% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.xml.bin index c81104a76..67d30f889 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.6.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.6.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.json.bin similarity index 96% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.json.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.json.bin index c3c2f85b3..3fefcee2b 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.json.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.json.bin @@ -4,7 +4,6 @@ "bom-ref": "external-lib-1.0.0", "isExternal": true, "name": "external-lib", - "scope": "required", "type": "library", "version": "1.0.0" } diff --git a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.xml.bin similarity index 95% rename from tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.xml.bin rename to tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.xml.bin index b16d837f9..b4854e27b 100644 --- a/tests/_data/snapshots/get_bom_with_external_component_1_7-1.7.xml.bin +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version-1.7.xml.bin @@ -7,7 +7,6 @@ external-lib 1.0.0 - required diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.0.xml.bin new file mode 100644 index 000000000..2e921e5f6 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.0.xml.bin @@ -0,0 +1,10 @@ + + + + + external-lib + + false + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.1.xml.bin new file mode 100644 index 000000000..a76e0521a --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.1.xml.bin @@ -0,0 +1,9 @@ + + + + + external-lib + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.json.bin new file mode 100644 index 000000000..a8fd61908 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.json.bin @@ -0,0 +1,23 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "name": "external-lib", + "type": "library", + "version": "" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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/get_bom_with_external_component_with_version_range-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.xml.bin new file mode 100644 index 000000000..954b82a92 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.2.xml.bin @@ -0,0 +1,15 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.json.bin new file mode 100644 index 000000000..0e198bc78 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.json.bin @@ -0,0 +1,23 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "name": "external-lib", + "type": "library", + "version": "" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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/get_bom_with_external_component_with_version_range-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.xml.bin new file mode 100644 index 000000000..090ea8571 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.3.xml.bin @@ -0,0 +1,15 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.json.bin new file mode 100644 index 000000000..89caf5ae2 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.json.bin @@ -0,0 +1,22 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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/get_bom_with_external_component_with_version_range-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.xml.bin new file mode 100644 index 000000000..911dd6f78 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.4.xml.bin @@ -0,0 +1,14 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.json.bin new file mode 100644 index 000000000..fdb5c0993 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.json.bin @@ -0,0 +1,32 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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/get_bom_with_external_component_with_version_range-1.5.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.xml.bin new file mode 100644 index 000000000..36be7f3a5 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.5.xml.bin @@ -0,0 +1,18 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.json.bin new file mode 100644 index 000000000..bffa7454f --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.json.bin @@ -0,0 +1,32 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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/get_bom_with_external_component_with_version_range-1.6.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.xml.bin new file mode 100644 index 000000000..a6d467841 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.6.xml.bin @@ -0,0 +1,18 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.json.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.json.bin new file mode 100644 index 000000000..fcdd4571d --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.json.bin @@ -0,0 +1,34 @@ +{ + "components": [ + { + "bom-ref": "external-lib-with-range", + "isExternal": true, + "name": "external-lib", + "type": "library", + "versionRange": "vers:all/*" + } + ], + "dependencies": [ + { + "ref": "external-lib-with-range" + } + ], + "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.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.xml.bin new file mode 100644 index 000000000..7c48d2b44 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_with_version_range-1.7.xml.bin @@ -0,0 +1,19 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + vers:all/* + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.0.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.0.xml.bin new file mode 100644 index 000000000..2e921e5f6 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.0.xml.bin @@ -0,0 +1,10 @@ + + + + + external-lib + + false + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.1.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.1.xml.bin new file mode 100644 index 000000000..44e2fd2f5 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.1.xml.bin @@ -0,0 +1,9 @@ + + + + + external-lib + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.json.bin new file mode 100644 index 000000000..3923e132e --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.json.bin @@ -0,0 +1,23 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "name": "external-lib", + "type": "library", + "version": "" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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/get_bom_with_external_component_without_version-1.2.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.xml.bin new file mode 100644 index 000000000..e11664583 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.2.xml.bin @@ -0,0 +1,15 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.json.bin new file mode 100644 index 000000000..93221671d --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.json.bin @@ -0,0 +1,23 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "name": "external-lib", + "type": "library", + "version": "" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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/get_bom_with_external_component_without_version-1.3.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.xml.bin new file mode 100644 index 000000000..6567e8b16 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.3.xml.bin @@ -0,0 +1,15 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.json.bin new file mode 100644 index 000000000..ab185131d --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.json.bin @@ -0,0 +1,22 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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/get_bom_with_external_component_without_version-1.4.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.xml.bin new file mode 100644 index 000000000..dba1982cb --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.4.xml.bin @@ -0,0 +1,14 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.json.bin new file mode 100644 index 000000000..2cb415941 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.json.bin @@ -0,0 +1,32 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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/get_bom_with_external_component_without_version-1.5.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.xml.bin new file mode 100644 index 000000000..8123396b5 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.5.xml.bin @@ -0,0 +1,18 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.json.bin new file mode 100644 index 000000000..51ef0fce6 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.json.bin @@ -0,0 +1,32 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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/get_bom_with_external_component_without_version-1.6.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.xml.bin new file mode 100644 index 000000000..8ac54fc19 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.6.xml.bin @@ -0,0 +1,18 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + val1 + val2 + + diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.json.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.json.bin new file mode 100644 index 000000000..fd9ee1f2a --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.json.bin @@ -0,0 +1,33 @@ +{ + "components": [ + { + "bom-ref": "external-lib", + "isExternal": true, + "name": "external-lib", + "type": "library" + } + ], + "dependencies": [ + { + "ref": "external-lib" + } + ], + "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.7.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.7" +} \ No newline at end of file diff --git a/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.xml.bin b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.xml.bin new file mode 100644 index 000000000..756ae7307 --- /dev/null +++ b/tests/_data/snapshots/get_bom_with_external_component_without_version-1.7.xml.bin @@ -0,0 +1,18 @@ + + + + 2023-01-07T13:44:32.312678+00:00 + + + + external-lib + + + + + + + val1 + val2 + + diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py index 030ee4a56..fe3193453 100644 --- a/tests/test_model_bom.py +++ b/tests/test_model_bom.py @@ -217,6 +217,13 @@ def test_warning_missing_dependency(self) -> None: self.assertEqual(len(w.warnings), 1) self.assertIn('has no defined dependencies ', str(w.warnings[0])) + def test_warning_root_component_is_external(self) -> None: + with self.assertWarns(expected_warning=UserWarning) as w: + bom = Bom(metadata=BomMetaData(component=Component(name='root_component', is_external=True))) + _ = JsonV1Dot7(bom).output_as_string() + self.assertEqual(len(w.warnings), 1) + self.assertIn('must not have is_external=true', str(w.warnings[0])) + def test_empty_bom_defined_serial(self) -> None: serial_number = uuid4() bom = Bom(serial_number=serial_number) diff --git a/tests/test_model_component.py b/tests/test_model_component.py index f7b8fc80a..b3d10236b 100644 --- a/tests/test_model_component.py +++ b/tests/test_model_component.py @@ -304,6 +304,27 @@ def test_is_external_sorting(self) -> None: expected_components = reorder(components, expected_order) self.assertListEqual(sorted_components, expected_components) + def test_version_range_comparison(self) -> None: + component_all = Component(name='test-component', is_external=True, version_range='vers:all/*') + component_none = Component(name='test-component', is_external=True, version_range='vers:none/*') + self.assertEqual(component_all, component_all) + self.assertEqual(component_none, component_none) + self.assertNotEqual(component_all, component_none) + self.assertLess(component_all, component_none) + self.assertNotEqual(hash(component_all), hash(component_none)) + + def test_version_range_sorting(self) -> None: + # version is compared before version_range, None sorts as greater than any string + expected_order = [1, 2, 0] + components = [ + Component(name='test_component', is_external=True), + Component(name='test_component', is_external=True, version='1.0.0'), + Component(name='test_component', is_external=True, version_range='vers:all/*'), + ] + sorted_components = sorted(components) + expected_components = reorder(components, expected_order) + self.assertListEqual(sorted_components, expected_components) + def test_nested_components_1(self) -> None: comp_b = Component(name='comp_b') comp_c = Component(name='comp_c') diff --git a/tests/test_output_json.py b/tests/test_output_json.py index b9340a4e2..062f38cfe 100644 --- a/tests/test_output_json.py +++ b/tests/test_output_json.py @@ -30,6 +30,7 @@ InvalidOmniBorIdException, InvalidSwhidException, LicenseExpressionAlongWithOthersException, + MutuallyExclusivePropertiesException, UnknownComponentDependencyException, ) from cyclonedx.exception.output import FormatNotSupportedException @@ -93,6 +94,7 @@ def test_invalid(self, get_bom: Callable[[], Bom], sv: SchemaVersion) -> None: LicenseExpressionAlongWithOthersException, InvalidOmniBorIdException, InvalidSwhidException, + MutuallyExclusivePropertiesException, UnknownComponentDependencyException, )): return None # expected diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py index 6e887dedb..2cb685857 100644 --- a/tests/test_output_xml.py +++ b/tests/test_output_xml.py @@ -29,6 +29,7 @@ InvalidOmniBorIdException, InvalidSwhidException, LicenseExpressionAlongWithOthersException, + MutuallyExclusivePropertiesException, UnknownComponentDependencyException, ) from cyclonedx.model.bom import Bom @@ -81,6 +82,7 @@ def test_invalid(self, get_bom: Callable[[], Bom], sv: SchemaVersion) -> None: LicenseExpressionAlongWithOthersException, InvalidOmniBorIdException, InvalidSwhidException, + MutuallyExclusivePropertiesException, UnknownComponentDependencyException, )): return None # expected