diff --git a/.isort.cfg b/.isort.cfg index 31d172da..520c9a1b 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -2,7 +2,7 @@ ## read the docs: https://pycqa.github.io/isort/docs/configuration/options.html ## keep in sync with flake8 config - in `tox.ini` file known_first_party = cyclonedx -skip_gitignore = true +skip_gitignore = false skip_glob = build/*,dist/*,__pycache__,.eggs,*.egg-info*, *_cache,*.cache, @@ -15,3 +15,6 @@ ensure_newline_before_comments = true include_trailing_comma = true line_length = 120 multi_line_output = 3 +src_paths = + cyclonedx + tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8da43c37..b92ff6d9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,13 +7,13 @@ repos: entry: poetry run tox -e mypy pass_filenames: false language: system -# - repo: local -# hooks: -# - id: system -# name: isort -# entry: poetry run isort -# pass_filenames: false -# language: system + - repo: local + hooks: + - id: system + name: isort + entry: poetry run isort -c . + pass_filenames: false + language: system - repo: local hooks: - id: system diff --git a/cyclonedx/model/bom.py b/cyclonedx/model/bom.py index 08636280..9cbf8363 100644 --- a/cyclonedx/model/bom.py +++ b/cyclonedx/model/bom.py @@ -18,7 +18,7 @@ # Copyright (c) OWASP Foundation. All Rights Reserved. import warnings from datetime import datetime, timezone -from typing import Iterable, Optional +from typing import Iterable, Optional, Set from uuid import UUID, uuid4 from sortedcontainers import SortedSet @@ -356,6 +356,16 @@ def external_references(self) -> "SortedSet[ExternalReference]": def external_references(self, external_references: Iterable[ExternalReference]) -> None: self._external_references = SortedSet(external_references) + def _get_all_components(self) -> Set[Component]: + components: Set[Component] = set() + if self.metadata.component: + components.update(self.metadata.component.get_all_nested_components(include_self=True)) + + for c in self.components: + components.update(c.get_all_nested_components(include_self=True)) + + return components + def has_vulnerabilities(self) -> bool: """ Check whether this Bom has any declared vulnerabilities. @@ -376,8 +386,8 @@ def validate(self) -> bool: """ # 1. Make sure dependencies are all in this Bom. - all_bom_refs = set([self.metadata.component.bom_ref] if self.metadata.component else []) | set( - map(lambda c: c.bom_ref, self.components)) | set(map(lambda s: s.bom_ref, self.services)) + all_bom_refs = set(map(lambda c: c.bom_ref, self._get_all_components())) | set( + map(lambda s: s.bom_ref, self.services)) all_dependency_bom_refs = set().union(*(c.dependencies for c in self.components)) dependency_diff = all_dependency_bom_refs - all_bom_refs @@ -389,9 +399,9 @@ def validate(self) -> bool: # 2. Dependencies should exist for the Component this BOM is describing, if one is set if self.metadata.component and not self.metadata.component.dependencies: warnings.warn( - f'The Component this BOM is describing {self.metadata.component.purl} has no defined dependencies' - f'which means the Dependency Graph is incomplete - you should add direct dependencies to this Component' - f'to complete the Dependency Graph data.', + f'The Component this BOM is describing (PURL={self.metadata.component.purl}) has no defined ' + f'dependencies which means the Dependency Graph is incomplete - you should add direct dependencies to ' + f'this Component to complete the Dependency Graph data.', UserWarning ) diff --git a/cyclonedx/model/component.py b/cyclonedx/model/component.py index dc1f7dd1..f3074f67 100644 --- a/cyclonedx/model/component.py +++ b/cyclonedx/model/component.py @@ -20,7 +20,7 @@ import warnings from enum import Enum from os.path import exists -from typing import Any, Iterable, Optional +from typing import Any, Iterable, Optional, Set # See https://github.com/package-url/packageurl-python/issues/65 from packageurl import PackageURL # type: ignore @@ -1159,6 +1159,16 @@ def has_vulnerabilities(self) -> bool: """ return bool(self.get_vulnerabilities()) + def get_all_nested_components(self, include_self: bool = False) -> Set["Component"]: + components = set() + if include_self: + components.add(self) + + for c in self.components: + components.update(c.get_all_nested_components(include_self=True)) + + return components + def get_pypi_url(self) -> str: if self.version: return f'https://pypi.org/project/{self.name}/{self.version}' diff --git a/cyclonedx/output/json.py b/cyclonedx/output/json.py index 94630fea..4556f3d2 100644 --- a/cyclonedx/output/json.py +++ b/cyclonedx/output/json.py @@ -115,6 +115,9 @@ def _specialise_output_for_schema_version(self, bom_json: Dict[Any, Any]) -> str del bom_json['metadata']['properties'] # Iterate Components + if self.get_bom().metadata.component: + bom_json['metadata'] = self._recurse_specialise_component(bom_json=bom_json['metadata'], + base_key='component') bom_json = self._recurse_specialise_component(bom_json=bom_json) # Iterate Services @@ -155,60 +158,67 @@ def _get_schema_uri(self) -> Optional[str]: def _recurse_specialise_component(self, bom_json: Dict[Any, Any], base_key: str = 'components') -> Dict[Any, Any]: if base_key in bom_json.keys(): - for i in range(len(bom_json[base_key])): - if not self.component_supports_mime_type_attribute() \ - and 'mime-type' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['mime-type'] - - if not self.component_supports_supplier() and 'supplier' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['supplier'] - - if not self.component_supports_author() and 'author' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['author'] - - if self.component_version_optional() and 'version' in bom_json[base_key][i] \ - and bom_json[base_key][i].get('version', '') == "": - del bom_json[base_key][i]['version'] - - if not self.component_supports_pedigree() and 'pedigree' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['pedigree'] - elif 'pedigree' in bom_json[base_key][i].keys(): - if 'ancestors' in bom_json[base_key][i]['pedigree'].keys(): - # recurse into ancestors - bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component( - bom_json=bom_json[base_key][i]['pedigree'], base_key='ancestors' - ) - if 'descendants' in bom_json[base_key][i]['pedigree'].keys(): - # recurse into descendants - bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component( - bom_json=bom_json[base_key][i]['pedigree'], base_key='descendants' - ) - if 'variants' in bom_json[base_key][i]['pedigree'].keys(): - # recurse into variants - bom_json[base_key][i]['pedigree'] = self._recurse_specialise_component( - bom_json=bom_json[base_key][i]['pedigree'], base_key='variants' - ) - - if not self.external_references_supports_hashes() and 'externalReferences' \ - in bom_json[base_key][i].keys(): - for j in range(len(bom_json[base_key][i]['externalReferences'])): - del bom_json[base_key][i]['externalReferences'][j]['hashes'] - - if not self.component_supports_properties() and 'properties' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['properties'] - - # recurse - if 'components' in bom_json[base_key][i].keys(): - bom_json[base_key][i] = self._recurse_specialise_component(bom_json=bom_json[base_key][i]) - - if not self.component_supports_evidence() and 'evidence' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['evidence'] - - if not self.component_supports_release_notes() and 'releaseNotes' in bom_json[base_key][i].keys(): - del bom_json[base_key][i]['releaseNotes'] + if isinstance(bom_json[base_key], dict): + bom_json[base_key] = self._specialise_component_data(component_json=bom_json[base_key]) + else: + for i in range(len(bom_json[base_key])): + bom_json[base_key][i] = self._specialise_component_data(component_json=bom_json[base_key][i]) return bom_json + def _specialise_component_data(self, component_json: Dict[Any, Any]) -> Dict[Any, Any]: + if not self.component_supports_mime_type_attribute() and 'mime-type' in component_json.keys(): + del component_json['mime-type'] + + if not self.component_supports_supplier() and 'supplier' in component_json.keys(): + del component_json['supplier'] + + if not self.component_supports_author() and 'author' in component_json.keys(): + del component_json['author'] + + if self.component_version_optional() and 'version' in component_json \ + and component_json.get('version', '') == "": + del component_json['version'] + + if not self.component_supports_pedigree() and 'pedigree' in component_json.keys(): + del component_json['pedigree'] + elif 'pedigree' in component_json.keys(): + if 'ancestors' in component_json['pedigree'].keys(): + # recurse into ancestors + component_json['pedigree'] = self._recurse_specialise_component( + bom_json=component_json['pedigree'], base_key='ancestors' + ) + if 'descendants' in component_json['pedigree'].keys(): + # recurse into descendants + component_json['pedigree'] = self._recurse_specialise_component( + bom_json=component_json['pedigree'], base_key='descendants' + ) + if 'variants' in component_json['pedigree'].keys(): + # recurse into variants + component_json['pedigree'] = self._recurse_specialise_component( + bom_json=component_json['pedigree'], base_key='variants' + ) + + if not self.external_references_supports_hashes() and 'externalReferences' \ + in component_json.keys(): + for j in range(len(component_json['externalReferences'])): + del component_json['externalReferences'][j]['hashes'] + + if not self.component_supports_properties() and 'properties' in component_json.keys(): + del component_json['properties'] + + # recurse + if 'components' in component_json.keys(): + component_json = self._recurse_specialise_component(bom_json=component_json) + + if not self.component_supports_evidence() and 'evidence' in component_json.keys(): + del component_json['evidence'] + + if not self.component_supports_release_notes() and 'releaseNotes' in component_json.keys(): + del component_json['releaseNotes'] + + return component_json + class JsonV1Dot0(Json, SchemaVersion1Dot0): diff --git a/poetry.lock b/poetry.lock index 226d23d1..941c9a9c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -45,7 +45,7 @@ toml = ["tomli"] [[package]] name = "distlib" -version = "0.3.4" +version = "0.3.5" description = "Distribution utilities" category = "dev" optional = false @@ -166,7 +166,7 @@ plugins = ["setuptools"] [[package]] name = "jsonschema" -version = "4.6.1" +version = "4.7.2" description = "An implementation of JSON Schema validation for Python" category = "dev" optional = false @@ -234,14 +234,15 @@ python-versions = "*" [[package]] name = "packageurl-python" -version = "0.9.9" +version = "0.10.0" description = "A purl aka. Package URL parser and builder" category = "main" optional = false python-versions = ">=3.6" [package.extras] -test = ["isort", "pytest"] +test = ["black", "isort", "pytest"] +build = ["wheel"] [[package]] name = "packaging" @@ -358,7 +359,7 @@ python-versions = ">=3.6" [[package]] name = "tox" -version = "3.25.0" +version = "3.25.1" description = "tox is a generic virtualenv management and test command line tool" category = "dev" optional = false @@ -389,7 +390,7 @@ python-versions = ">=3.6" [[package]] name = "types-setuptools" -version = "57.4.17" +version = "63.2.2" description = "Typing stubs for setuptools" category = "dev" optional = false @@ -397,7 +398,7 @@ python-versions = "*" [[package]] name = "types-toml" -version = "0.10.4" +version = "0.10.8" description = "Typing stubs for toml" category = "dev" optional = false @@ -413,11 +414,11 @@ python-versions = ">=3.6" [[package]] name = "virtualenv" -version = "20.15.1" +version = "20.16.2" description = "Virtual Python Environment builder" category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.6" [package.dependencies] distlib = ">=0.3.1,<1" @@ -425,11 +426,10 @@ filelock = ">=3.2,<4" importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} platformdirs = ">=2,<3" -six = ">=1.9.0,<2" [package.extras] docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] -testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] +testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)"] [[package]] name = "xmldiff" @@ -458,337 +458,45 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.6" -content-hash = "2aa5c305ab89542157a2859ca04386e430884cc5e65a5f7d6bc0dad7376abc3a" +content-hash = "2d54fab7cbd2e7c837e362936f030fe70ce8ed9114529f828a5f865b14f9d1d0" [metadata.files] -attrs = [ - {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, - {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, -] -autopep8 = [ - {file = "autopep8-1.6.0-py2.py3-none-any.whl", hash = "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"}, - {file = "autopep8-1.6.0.tar.gz", hash = "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -coverage = [ - {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, - {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, - {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, - {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, - {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, - {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, - {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, - {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, - {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, - {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, - {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, - {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, - {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, - {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, - {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, - {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, - {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, - {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, - {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, - {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, -] -distlib = [ - {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, - {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, -] -filelock = [ - {file = "filelock-3.4.1-py3-none-any.whl", hash = "sha256:a4bc51381e01502a30e9f06dd4fa19a1712eab852b6fb0f84fd7cce0793d8ca3"}, - {file = "filelock-3.4.1.tar.gz", hash = "sha256:0f12f552b42b5bf60dba233710bf71337d35494fc8bdd4fd6d9f6d082ad45e06"}, -] -flake8 = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, -] -flake8-annotations = [ - {file = "flake8-annotations-2.7.0.tar.gz", hash = "sha256:52e53c05b0c06cac1c2dec192ea2c36e85081238add3bd99421d56f574b9479b"}, - {file = "flake8_annotations-2.7.0-py3-none-any.whl", hash = "sha256:3edfbbfb58e404868834fe6ec3eaf49c139f64f0701259f707d043185545151e"}, -] -flake8-bugbear = [ - {file = "flake8-bugbear-22.7.1.tar.gz", hash = "sha256:e450976a07e4f9d6c043d4f72b17ec1baf717fe37f7997009c8ae58064f88305"}, - {file = "flake8_bugbear-22.7.1-py3-none-any.whl", hash = "sha256:db5d7a831ef4412a224b26c708967ff816818cabae415e76b8c58df156c4b8e5"}, -] -flake8-isort = [ - {file = "flake8-isort-4.1.2.post0.tar.gz", hash = "sha256:dee69bc3c09f0832df88acf795845db8a6673b79237371a05fa927ce095248e5"}, - {file = "flake8_isort-4.1.2.post0-py3-none-any.whl", hash = "sha256:4f95b40706dbb507cff872b34683283662e945d6028d3c8257e69de5fc6b7446"}, -] -importlib-metadata = [ - {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, - {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, -] -importlib-resources = [ - {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, - {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -jsonschema = [ - {file = "jsonschema-4.6.1-py3-none-any.whl", hash = "sha256:5eb781753403847fb320f05e9ab2191725b58c5e7f97f1bed63285ca423159bc"}, - {file = "jsonschema-4.6.1.tar.gz", hash = "sha256:ec2802e6a37517f09d47d9ba107947589ae1d25ff557b925d83a321fc2aa5d3b"}, -] -lxml = [ - {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, - {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, - {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, - {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, - {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, - {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, - {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, - {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, - {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, - {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, - {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, - {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, - {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, - {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, - {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, - {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, - {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, - {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, - {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, - {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, - {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -mypy = [ - {file = "mypy-0.961-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0"}, - {file = "mypy-0.961-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15"}, - {file = "mypy-0.961-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bdd5ca340beffb8c44cb9dc26697628d1b88c6bddf5c2f6eb308c46f269bb6f3"}, - {file = "mypy-0.961-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3e09f1f983a71d0672bbc97ae33ee3709d10c779beb613febc36805a6e28bb4e"}, - {file = "mypy-0.961-cp310-cp310-win_amd64.whl", hash = "sha256:e999229b9f3198c0c880d5e269f9f8129c8862451ce53a011326cad38b9ccd24"}, - {file = "mypy-0.961-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b24be97351084b11582fef18d79004b3e4db572219deee0212078f7cf6352723"}, - {file = "mypy-0.961-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f4a21d01fc0ba4e31d82f0fff195682e29f9401a8bdb7173891070eb260aeb3b"}, - {file = "mypy-0.961-cp36-cp36m-win_amd64.whl", hash = "sha256:439c726a3b3da7ca84a0199a8ab444cd8896d95012c4a6c4a0d808e3147abf5d"}, - {file = "mypy-0.961-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5a0b53747f713f490affdceef835d8f0cb7285187a6a44c33821b6d1f46ed813"}, - {file = "mypy-0.961-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e9f70df36405c25cc530a86eeda1e0867863d9471fe76d1273c783df3d35c2e"}, - {file = "mypy-0.961-cp37-cp37m-win_amd64.whl", hash = "sha256:b88f784e9e35dcaa075519096dc947a388319cb86811b6af621e3523980f1c8a"}, - {file = "mypy-0.961-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d5aaf1edaa7692490f72bdb9fbd941fbf2e201713523bdb3f4038be0af8846c6"}, - {file = "mypy-0.961-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9f5f5a74085d9a81a1f9c78081d60a0040c3efb3f28e5c9912b900adf59a16e6"}, - {file = "mypy-0.961-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f4b794db44168a4fc886e3450201365c9526a522c46ba089b55e1f11c163750d"}, - {file = "mypy-0.961-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:64759a273d590040a592e0f4186539858c948302c653c2eac840c7a3cd29e51b"}, - {file = "mypy-0.961-cp38-cp38-win_amd64.whl", hash = "sha256:63e85a03770ebf403291ec50097954cc5caf2a9205c888ce3a61bd3f82e17569"}, - {file = "mypy-0.961-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f1332964963d4832a94bebc10f13d3279be3ce8f6c64da563d6ee6e2eeda932"}, - {file = "mypy-0.961-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:006be38474216b833eca29ff6b73e143386f352e10e9c2fbe76aa8549e5554f5"}, - {file = "mypy-0.961-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9940e6916ed9371809b35b2154baf1f684acba935cd09928952310fbddaba648"}, - {file = "mypy-0.961-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a5ea0875a049de1b63b972456542f04643daf320d27dc592d7c3d9cd5d9bf950"}, - {file = "mypy-0.961-cp39-cp39-win_amd64.whl", hash = "sha256:1ece702f29270ec6af25db8cf6185c04c02311c6bb21a69f423d40e527b75c56"}, - {file = "mypy-0.961-py3-none-any.whl", hash = "sha256:03c6cc893e7563e7b2949b969e63f02c000b32502a1b4d1314cabe391aa87d66"}, - {file = "mypy-0.961.tar.gz", hash = "sha256:f730d56cb924d371c26b8eaddeea3cc07d78ff51c521c6d04899ac6904b75492"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -packageurl-python = [ - {file = "packageurl-python-0.9.9.tar.gz", hash = "sha256:872a0434b9a448b3fa97571711f69dd2a3fb72345ad66c90b17d827afea82f09"}, - {file = "packageurl_python-0.9.9-py3-none-any.whl", hash = "sha256:07aa852d1c48b0e86e625f6a32d83f96427739806b269d0f8142788ee807114b"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -platformdirs = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, -] -pluggy = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, -] -py = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] -pycodestyle = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, -] -pyflakes = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, -] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] -pyrsistent = [ - {file = "pyrsistent-0.18.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26"}, - {file = "pyrsistent-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win32.whl", hash = "sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6"}, - {file = "pyrsistent-0.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win32.whl", hash = "sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8"}, - {file = "pyrsistent-0.18.1-cp37-cp37m-win_amd64.whl", hash = "sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286"}, - {file = "pyrsistent-0.18.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec"}, - {file = "pyrsistent-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win32.whl", hash = "sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca"}, - {file = "pyrsistent-0.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a"}, - {file = "pyrsistent-0.18.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045"}, - {file = "pyrsistent-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win32.whl", hash = "sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc"}, - {file = "pyrsistent-0.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07"}, - {file = "pyrsistent-0.18.1.tar.gz", hash = "sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -sortedcontainers = [ - {file = "sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0"}, - {file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] -tox = [ - {file = "tox-3.25.0-py2.py3-none-any.whl", hash = "sha256:0805727eb4d6b049de304977dfc9ce315a1938e6619c3ab9f38682bb04662a5a"}, - {file = "tox-3.25.0.tar.gz", hash = "sha256:37888f3092aa4e9f835fc8cc6dadbaaa0782651c41ef359e3a5743fcb0308160"}, -] -typed-ast = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, -] -types-setuptools = [ - {file = "types-setuptools-57.4.17.tar.gz", hash = "sha256:9d556fcaf6808a1cead4aaa41e5c07a61f0152a875811e1239738eba4e0b7b16"}, - {file = "types_setuptools-57.4.17-py3-none-any.whl", hash = "sha256:9c7cdaf0d55113e24ac17103bde2d434472abf1dbf444238e989fe4e798ffa26"}, -] -types-toml = [ - {file = "types-toml-0.10.4.tar.gz", hash = "sha256:9340e7c1587715581bb13905b3af30b79fe68afaccfca377665d5e63b694129a"}, - {file = "types_toml-0.10.4-py3-none-any.whl", hash = "sha256:4a9ffd47bbcec49c6fde6351a889b2c1bd3c0ef309fa0eed60dc28e58c8b9ea6"}, -] -typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, -] -virtualenv = [ - {file = "virtualenv-20.15.1-py2.py3-none-any.whl", hash = "sha256:b30aefac647e86af6d82bfc944c556f8f1a9c90427b2fb4e3bfbf338cb82becf"}, - {file = "virtualenv-20.15.1.tar.gz", hash = "sha256:288171134a2ff3bfb1a2f54f119e77cd1b81c29fc1265a2356f3e8d14c7d58c4"}, -] -xmldiff = [ - {file = "xmldiff-2.4-py2.py3-none-any.whl", hash = "sha256:213c2f4c39ed71811a9ceeec1c8bdf2e673e5527261ea11708b3acfa6c2bdb00"}, - {file = "xmldiff-2.4.tar.gz", hash = "sha256:05bea20ce1f2c9678683bcce0c3ba9981f87d92b709d190e018bcbf047eccf63"}, -] -zipp = [ - {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, - {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, -] +attrs = [] +autopep8 = [] +colorama = [] +coverage = [] +distlib = [] +filelock = [] +flake8 = [] +flake8-annotations = [] +flake8-bugbear = [] +flake8-isort = [] +importlib-metadata = [] +importlib-resources = [] +isort = [] +jsonschema = [] +lxml = [] +mccabe = [] +mypy = [] +mypy-extensions = [] +packageurl-python = [] +packaging = [] +platformdirs = [] +pluggy = [] +py = [] +pycodestyle = [] +pyflakes = [] +pyparsing = [] +pyrsistent = [] +six = [] +sortedcontainers = [] +toml = [] +tomli = [] +tox = [] +typed-ast = [] +types-setuptools = [] +types-toml = [] +typing-extensions = [] +virtualenv = [] +xmldiff = [] +zipp = [] diff --git a/pyproject.toml b/pyproject.toml index 0a993936..1781f647 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ sortedcontainers = "^2.4.0" [tool.poetry.dev-dependencies] tox = "^3.25.0" coverage = "^6.2" -mypy = ">= 0.920, < 1.00" +mypy = ">= 0.920, <= 0.961" autopep8 = "^1.6.0" isort = { version = "^5.10.0", python = ">= 3.6.1" } flake8 = "^4.0.1" diff --git a/tests/data.py b/tests/data.py index 585dddf8..4fa73737 100644 --- a/tests/data.py +++ b/tests/data.py @@ -138,26 +138,7 @@ def get_bom_with_metadata_component_and_dependencies() -> Bom: def get_bom_with_component_setuptools_complete() -> Bom: - component = get_component_setuptools_simple(bom_ref=MOCK_UUID_6) - component.supplier = get_org_entity_1() - component.publisher = 'CycloneDX' - component.description = 'This component is awesome' - component.scope = ComponentScope.REQUIRED - component.copyright = 'Apache 2.0 baby!' - component.cpe = 'cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*' - component.swid = get_swid_1() - component.pedigree = get_pedigree_1() - component.external_references.add( - get_external_reference_1() - ) - component.properties = get_properties_1() - component.components.update([ - get_component_setuptools_simple(), - get_component_toml_with_hashes_with_references() - ]) - component.evidence = ComponentEvidence(copyright_=[Copyright(text='Commercial'), Copyright(text='Commercial 2')]) - component.release_notes = get_release_notes() - return Bom(components=[component]) + return Bom(components=[get_component_setuptools_complete()]) def get_bom_with_component_setuptools_with_vulnerability() -> Bom: @@ -229,9 +210,7 @@ def get_bom_with_component_toml_1() -> Bom: def get_bom_just_complete_metadata() -> Bom: bom = Bom() bom.metadata.authors = [get_org_contact_1(), get_org_contact_2()] - bom.metadata.component = Component( - name='cyclonedx-python-lib', version='1.0.0', component_type=ComponentType.LIBRARY - ) + bom.metadata.component = get_component_setuptools_complete() bom.metadata.manufacture = get_org_entity_1() bom.metadata.supplier = get_org_entity_2() bom.metadata.licenses = [LicenseChoice(license_=License( @@ -340,10 +319,67 @@ def get_bom_with_nested_services() -> Bom: return bom -def get_component_setuptools_simple(bom_ref: Optional[str] = None) -> Component: +def get_bom_for_issue_275_components() -> Bom: + app = Component(bom_ref=MOCK_UUID_1, name="app", version="1.0.0") + comp_a = Component(bom_ref=MOCK_UUID_2, name="comp_a", version="1.0.0") + comp_b = Component(bom_ref=MOCK_UUID_3, name="comp_b", version="1.0.0") + comp_c = Component(bom_ref=MOCK_UUID_4, name="comp_c", version="1.0.0") + + comp_b.components.add(comp_c) + comp_b.dependencies.add(comp_c.bom_ref) + + libs = [comp_a, comp_b] + app.dependencies.add(comp_a.bom_ref) + app.dependencies.add(comp_b.bom_ref) + + bom = Bom(components=libs) + bom.metadata.component = app + return bom + + +# def get_bom_for_issue_275_services() -> Bom: +# app = Component(name="app", version="1.0.0") +# serv_a = Service(name='Service A') +# serv_b = Service(name='Service B') +# serv_c = Service(name='Service C') +# +# serv_b.services.add(serv_c) +# serv_b.dependencies.add(serv_c.bom_ref) +# +# bom = Bom(services=[serv_a, serv_b]) +# bom.metadata.component = app +# return bom + + +def get_component_setuptools_complete(include_pedigree: bool = True) -> Component: + component = get_component_setuptools_simple(bom_ref=None) + component.supplier = get_org_entity_1() + component.publisher = 'CycloneDX' + component.description = 'This component is awesome' + component.scope = ComponentScope.REQUIRED + component.copyright = 'Apache 2.0 baby!' + component.cpe = 'cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*' + component.swid = get_swid_1() + if include_pedigree: + component.pedigree = get_pedigree_1() + component.external_references.add( + get_external_reference_1() + ) + component.properties = get_properties_1() + component.components.update([ + get_component_setuptools_simple(), + get_component_toml_with_hashes_with_references() + ]) + component.evidence = ComponentEvidence(copyright_=[Copyright(text='Commercial'), Copyright(text='Commercial 2')]) + component.release_notes = get_release_notes() + return component + + +def get_component_setuptools_simple( + bom_ref: Optional[str] = 'pkg:pypi/setuptools@50.3.2?extension=tar.gz') -> Component: return Component( name='setuptools', version='50.3.2', - bom_ref=bom_ref or 'pkg:pypi/setuptools@50.3.2?extension=tar.gz', + bom_ref=bom_ref, purl=PackageURL( type='pypi', name='setuptools', version='50.3.2', qualifiers='extension=tar.gz' ), diff --git a/tests/fixtures/json/1.2/bom_issue_275_components.json b/tests/fixtures/json/1.2/bom_issue_275_components.json new file mode 100644 index 00000000..16df9e10 --- /dev/null +++ b/tests/fixtures/json/1.2/bom_issue_275_components.json @@ -0,0 +1,64 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json", + "bomFormat": "CycloneDX", + "components": [ + { + "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "name": "comp_a", + "type": "library", + "version": "1.0.0" + }, + { + "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857", + "components": [ + { + "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789", + "name": "comp_c", + "type": "library", + "version": "1.0.0" + } + ], + "name": "comp_b", + "type": "library", + "version": "1.0.0" + } + ], + "dependencies": [ + { + "dependsOn": [ + "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "0b049d09-64c0-4490-a0f5-c84d9aacf857" + ], + "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3" + }, + { + "dependsOn": [], + "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda" + }, + { + "dependsOn": [ + "cd3e9c95-9d41-49e7-9924-8cf0465ae789" + ], + "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857" + } + ], + "metadata": { + "component": { + "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3", + "name": "app", + "type": "library", + "version": "1.0.0" + }, + "timestamp": "2022-07-27T10:06:17.101289+00:00", + "tools": [ + { + "name": "cyclonedx-python-lib", + "vendor": "CycloneDX", + "version": "0.11.0" + } + ] + }, + "serialNumber": "urn:uuid:b1d647c9-e4c5-4d8f-be8a-1751ac3ad4d5", + "specVersion": "1.2", + "version": 1 +} \ No newline at end of file diff --git a/tests/fixtures/json/1.2/bom_with_full_metadata.json b/tests/fixtures/json/1.2/bom_with_full_metadata.json index 6b6c7de8..7cfee9db 100644 --- a/tests/fixtures/json/1.2/bom_with_full_metadata.json +++ b/tests/fixtures/json/1.2/bom_with_full_metadata.json @@ -25,10 +25,203 @@ } ], "component": { - "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857", "type": "library", - "name": "cyclonedx-python-lib", - "version": "1.0.0" + "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857", + "supplier": { + "name": "CycloneDX", + "url": [ + "https://cyclonedx.org" + ], + "contact": [ + { + "name": "Paul Horton", + "email": "paul.horton@owasp.org" + }, + { + "name": "A N Other", + "email": "someone@somewhere.tld", + "phone": "+44 (0)1234 567890" + } + ] + }, + "author": "Test Author", + "publisher": "CycloneDX", + "name": "setuptools", + "version": "50.3.2", + "description": "This component is awesome", + "scope": "required", + "licenses": [ + { + "expression": "MIT License" + } + ], + "copyright": "Apache 2.0 baby!", + "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*", + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "swid": { + "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", + "name": "Test Application", + "version": "3.4.5", + "text": { + "contentType": "text/xml", + "encoding": "base64", + "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==" + } + }, + "pedigree": { + "ancestors": [ + { + "type": "library", + "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a", + "author": "Test Author", + "name": "setuptools", + "version": "", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + } + ], + "descendants": [ + { + "type": "library", + "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc", + "author": "Test Author", + "name": "setuptools", + "version": "", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment" + } + ] + } + ], + "variants": [ + { + "type": "library", + "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment" + } + ] + }, + { + "type": "library", + "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + } + ], + "commits": [ + { + "uid": "a-random-uid", + "message": "A commit message" + } + ], + "patches": [ + { + "type": "backport" + } + ], + "notes": "Some notes here please" + }, + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment" + } + ], + "components": [ + { + "type": "library", + "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment" + } + ] + } + ] }, "manufacture": { "name": "CycloneDX", diff --git a/tests/fixtures/json/1.3/bom_issue_275_components.json b/tests/fixtures/json/1.3/bom_issue_275_components.json new file mode 100644 index 00000000..4a574815 --- /dev/null +++ b/tests/fixtures/json/1.3/bom_issue_275_components.json @@ -0,0 +1,64 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json", + "bomFormat": "CycloneDX", + "components": [ + { + "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "name": "comp_a", + "type": "library", + "version": "1.0.0" + }, + { + "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857", + "components": [ + { + "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789", + "name": "comp_c", + "type": "library", + "version": "1.0.0" + } + ], + "name": "comp_b", + "type": "library", + "version": "1.0.0" + } + ], + "dependencies": [ + { + "dependsOn": [ + "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "0b049d09-64c0-4490-a0f5-c84d9aacf857" + ], + "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3" + }, + { + "dependsOn": [], + "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda" + }, + { + "dependsOn": [ + "cd3e9c95-9d41-49e7-9924-8cf0465ae789" + ], + "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857" + } + ], + "metadata": { + "component": { + "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3", + "name": "app", + "type": "library", + "version": "1.0.0" + }, + "timestamp": "2022-07-27T10:06:17.101289+00:00", + "tools": [ + { + "name": "cyclonedx-python-lib", + "vendor": "CycloneDX", + "version": "0.11.0" + } + ] + }, + "serialNumber": "urn:uuid:b1d647c9-e4c5-4d8f-be8a-1751ac3ad4d5", + "specVersion": "1.3", + "version": 1 +} \ No newline at end of file diff --git a/tests/fixtures/json/1.3/bom_with_full_metadata.json b/tests/fixtures/json/1.3/bom_with_full_metadata.json index ca5ea2fa..7b217e0d 100644 --- a/tests/fixtures/json/1.3/bom_with_full_metadata.json +++ b/tests/fixtures/json/1.3/bom_with_full_metadata.json @@ -25,10 +25,247 @@ } ], "component": { - "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", "type": "library", - "name": "cyclonedx-python-lib", - "version": "1.0.0" + "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "supplier": { + "name": "CycloneDX", + "url": [ + "https://cyclonedx.org" + ], + "contact": [ + { + "name": "Paul Horton", + "email": "paul.horton@owasp.org" + }, + { + "name": "A N Other", + "email": "someone@somewhere.tld", + "phone": "+44 (0)1234 567890" + } + ] + }, + "author": "Test Author", + "publisher": "CycloneDX", + "name": "setuptools", + "version": "50.3.2", + "description": "This component is awesome", + "scope": "required", + "licenses": [ + { + "expression": "MIT License" + } + ], + "copyright": "Apache 2.0 baby!", + "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*", + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "swid": { + "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", + "name": "Test Application", + "version": "3.4.5", + "text": { + "contentType": "text/xml", + "encoding": "base64", + "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==" + } + }, + "pedigree": { + "ancestors": [ + { + "type": "library", + "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a", + "author": "Test Author", + "name": "setuptools", + "version": "", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + } + ], + "descendants": [ + { + "type": "library", + "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc", + "author": "Test Author", + "name": "setuptools", + "version": "", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + } + ], + "variants": [ + { + "type": "library", + "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + }, + { + "type": "library", + "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + } + ], + "commits": [ + { + "uid": "a-random-uid", + "message": "A commit message" + } + ], + "patches": [ + { + "type": "backport" + } + ], + "notes": "Some notes here please" + }, + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ], + "components": [ + { + "type": "library", + "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + } + ], + "evidence": { + "copyright": [ + { + "text": "Commercial" + }, + { + "text": "Commercial 2" + } + ] + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ] }, "manufacture": { "name": "CycloneDX", diff --git a/tests/fixtures/json/1.4/bom_issue_275_components.json b/tests/fixtures/json/1.4/bom_issue_275_components.json new file mode 100644 index 00000000..bd9667dd --- /dev/null +++ b/tests/fixtures/json/1.4/bom_issue_275_components.json @@ -0,0 +1,98 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json", + "bomFormat": "CycloneDX", + "components": [ + { + "bom-ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "name": "comp_a", + "type": "library", + "version": "1.0.0" + }, + { + "bom-ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857", + "components": [ + { + "bom-ref": "cd3e9c95-9d41-49e7-9924-8cf0465ae789", + "name": "comp_c", + "type": "library", + "version": "1.0.0" + } + ], + "name": "comp_b", + "type": "library", + "version": "1.0.0" + } + ], + "dependencies": [ + { + "dependsOn": [ + "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda", + "0b049d09-64c0-4490-a0f5-c84d9aacf857" + ], + "ref": "be2c6502-7e9a-47db-9a66-e34f729810a3" + }, + { + "dependsOn": [], + "ref": "17e3b199-dc0b-42ef-bfdd-1fa81a1e3eda" + }, + { + "dependsOn": [ + "cd3e9c95-9d41-49e7-9924-8cf0465ae789" + ], + "ref": "0b049d09-64c0-4490-a0f5-c84d9aacf857" + } + ], + "metadata": { + "component": { + "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3", + "name": "app", + "type": "library", + "version": "1.0.0" + }, + "timestamp": "2022-07-27T10:06:17.101289+00:00", + "tools": [ + { + "externalReferences": [ + { + "type": "build-system", + "url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions" + }, + { + "type": "distribution", + "url": "https://pypi.org/project/cyclonedx-python-lib/" + }, + { + "type": "documentation", + "url": "https://cyclonedx.github.io/cyclonedx-python-lib/" + }, + { + "type": "issue-tracker", + "url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues" + }, + { + "type": "license", + "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE" + }, + { + "type": "release-notes", + "url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md" + }, + { + "type": "vcs", + "url": "https://github.com/CycloneDX/cyclonedx-python-lib" + }, + { + "type": "website", + "url": "https://cyclonedx.org" + } + ], + "name": "cyclonedx-python-lib", + "vendor": "CycloneDX", + "version": "0.11.0" + } + ] + }, + "serialNumber": "urn:uuid:b1d647c9-e4c5-4d8f-be8a-1751ac3ad4d5", + "specVersion": "1.4", + "version": 1 +} \ No newline at end of file diff --git a/tests/fixtures/json/1.4/bom_with_full_metadata.json b/tests/fixtures/json/1.4/bom_with_full_metadata.json index 3563916f..5d4aea74 100644 --- a/tests/fixtures/json/1.4/bom_with_full_metadata.json +++ b/tests/fixtures/json/1.4/bom_with_full_metadata.json @@ -59,10 +59,304 @@ } ], "component": { - "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3", "type": "library", - "name": "cyclonedx-python-lib", - "version": "1.0.0" + "bom-ref": "be2c6502-7e9a-47db-9a66-e34f729810a3", + "supplier": { + "name": "CycloneDX", + "url": [ + "https://cyclonedx.org" + ], + "contact": [ + { + "name": "Paul Horton", + "email": "paul.horton@owasp.org" + }, + { + "name": "A N Other", + "email": "someone@somewhere.tld", + "phone": "+44 (0)1234 567890" + } + ] + }, + "author": "Test Author", + "publisher": "CycloneDX", + "name": "setuptools", + "version": "50.3.2", + "description": "This component is awesome", + "scope": "required", + "licenses": [ + { + "expression": "MIT License" + } + ], + "copyright": "Apache 2.0 baby!", + "cpe": "cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:*", + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "swid": { + "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", + "name": "Test Application", + "version": "3.4.5", + "text": { + "contentType": "text/xml", + "encoding": "base64", + "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==" + } + }, + "pedigree": { + "ancestors": [ + { + "type": "library", + "bom-ref": "ccc8d7ee-4b9c-4750-aee0-a72585152291", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "8a3893b3-9923-4adb-a1d3-47456636ba0a", + "author": "Test Author", + "name": "setuptools", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + } + ], + "descendants": [ + { + "type": "library", + "bom-ref": "28b2d8ce-def0-446f-a221-58dee0b44acc", + "author": "Test Author", + "name": "setuptools", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "555ca729-93c6-48f3-956e-bdaa4a2f0bfa", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + } + ], + "variants": [ + { + "type": "library", + "bom-ref": "e7abdcca-5ba2-4f29-b2cf-b1e1ef788e66", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + }, + { + "type": "library", + "bom-ref": "ded1d73e-1fca-4302-b520-f1bc53979958", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + } + ], + "commits": [ + { + "uid": "a-random-uid", + "message": "A commit message" + } + ], + "patches": [ + { + "type": "backport" + } + ], + "notes": "Some notes here please" + }, + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ], + "components": [ + { + "type": "library", + "bom-ref": "pkg:pypi/setuptools@50.3.2?extension=tar.gz", + "author": "Test Author", + "name": "setuptools", + "version": "50.3.2", + "licenses": [ + { + "expression": "MIT License" + } + ], + "purl": "pkg:pypi/setuptools@50.3.2?extension=tar.gz" + }, + { + "type": "library", + "bom-ref": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "name": "toml", + "version": "0.10.2", + "purl": "pkg:pypi/toml@0.10.2?extension=tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://cyclonedx.org", + "comment": "No comment", + "hashes": [ + { + "alg": "SHA-256", + "content": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + } + ] + } + ] + } + ], + "evidence": { + "copyright": [ + { + "text": "Commercial" + }, + { + "text": "Commercial 2" + } + ] + }, + "releaseNotes": { + "type": "major", + "title": "Release Notes Title", + "featuredImage": "https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png", + "socialImage": "https://cyclonedx.org/cyclonedx-icon.png", + "description": "This release is a test release", + "timestamp": "2021-12-31T10:00:00+00:00", + "aliases": [ + "First Test Release" + ], + "tags": [ + "test", + "alpha" + ], + "resolves": [ + { + "type": "security", + "id": "CVE-2021-44228", + "name": "Apache Log3Shell", + "description": "Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features...", + "source": { + "name": "NVD", + "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44228" + }, + "references": [ + "https://logging.apache.org/log4j/2.x/security.html", + "https://central.sonatype.org/news/20211213_log4shell_help" + ] + } + ], + "notes": [ + { + "locale": "en-GB", + "text": { + "contentType": "text/plain; charset=UTF-8", + "encoding": "base64", + "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==" + } + }, + { + "locale": "en-US", + "text": { + "contentType": "text/plain; charset=UTF-8", + "encoding": "base64", + "content": "U29tZSBzaW1wbGUgcGxhaW4gdGV4dA==" + } + } + ], + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ] + }, + "properties": [ + { + "name": "key1", + "value": "val1" + }, + { + "name": "key2", + "value": "val2" + } + ] }, "manufacture": { "name": "CycloneDX", diff --git a/tests/fixtures/xml/1.0/bom_issue_275_components.xml b/tests/fixtures/xml/1.0/bom_issue_275_components.xml new file mode 100644 index 00000000..c8a909c2 --- /dev/null +++ b/tests/fixtures/xml/1.0/bom_issue_275_components.xml @@ -0,0 +1,22 @@ + + + + + comp_a + 1.0.0 + false + + + comp_b + 1.0.0 + false + + + comp_c + 1.0.0 + false + + + + + \ No newline at end of file diff --git a/tests/fixtures/xml/1.1/bom_issue_275_components.xml b/tests/fixtures/xml/1.1/bom_issue_275_components.xml new file mode 100644 index 00000000..579eca0f --- /dev/null +++ b/tests/fixtures/xml/1.1/bom_issue_275_components.xml @@ -0,0 +1,19 @@ + + + + + comp_a + 1.0.0 + + + comp_b + 1.0.0 + + + comp_c + 1.0.0 + + + + + \ No newline at end of file diff --git a/tests/fixtures/xml/1.1/bom_setuptools_complete.xml b/tests/fixtures/xml/1.1/bom_setuptools_complete.xml index 0a116a29..2a72edfb 100644 --- a/tests/fixtures/xml/1.1/bom_setuptools_complete.xml +++ b/tests/fixtures/xml/1.1/bom_setuptools_complete.xml @@ -1,7 +1,7 @@ - + CycloneDX setuptools 50.3.2 diff --git a/tests/fixtures/xml/1.2/bom_issue_275_components.xml b/tests/fixtures/xml/1.2/bom_issue_275_components.xml new file mode 100644 index 00000000..f707c02c --- /dev/null +++ b/tests/fixtures/xml/1.2/bom_issue_275_components.xml @@ -0,0 +1,43 @@ + + + + 2021-09-01T10:50:42.051979+00:00 + + + CycloneDX + cyclonedx-python-lib + VERSION + + + + app + 1.0.0 + + + + + comp_a + 1.0.0 + + + comp_b + 1.0.0 + + + comp_c + 1.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/fixtures/xml/1.2/bom_setuptools_complete.xml b/tests/fixtures/xml/1.2/bom_setuptools_complete.xml index 8f86e9ee..7d83187f 100644 --- a/tests/fixtures/xml/1.2/bom_setuptools_complete.xml +++ b/tests/fixtures/xml/1.2/bom_setuptools_complete.xml @@ -11,7 +11,7 @@ - + CycloneDX https://cyclonedx.org @@ -156,6 +156,6 @@ - + \ No newline at end of file diff --git a/tests/fixtures/xml/1.2/bom_with_full_metadata.xml b/tests/fixtures/xml/1.2/bom_with_full_metadata.xml index 900b1663..8fe33131 100644 --- a/tests/fixtures/xml/1.2/bom_with_full_metadata.xml +++ b/tests/fixtures/xml/1.2/bom_with_full_metadata.xml @@ -21,8 +21,147 @@ - cyclonedx-python-lib - 1.0.0 + + CycloneDX + https://cyclonedx.org + + Paul Horton + paul.horton@owasp.org + + + A N Other + someone@somewhere.tld + +44 (0)1234 567890 + + + Test Author + CycloneDX + setuptools + 50.3.2 + This component is awesome + required + + MIT License + + Apache 2.0 baby! + cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:* + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg== + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + Test Author + setuptools + + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + + + Test Author + setuptools + + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + + + + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + + + a-random-uid + A commit message + + + + + + Some notes here please + + + + https://cyclonedx.org + No comment + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + + + CycloneDX diff --git a/tests/fixtures/xml/1.3/bom_issue_275_components.xml b/tests/fixtures/xml/1.3/bom_issue_275_components.xml new file mode 100644 index 00000000..25d31646 --- /dev/null +++ b/tests/fixtures/xml/1.3/bom_issue_275_components.xml @@ -0,0 +1,43 @@ + + + + 2021-09-01T10:50:42.051979+00:00 + + + CycloneDX + cyclonedx-python-lib + VERSION + + + + app + 1.0.0 + + + + + comp_a + 1.0.0 + + + comp_b + 1.0.0 + + + comp_c + 1.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/fixtures/xml/1.3/bom_setuptools_complete.xml b/tests/fixtures/xml/1.3/bom_setuptools_complete.xml index 9d318bd1..8a2e1274 100644 --- a/tests/fixtures/xml/1.3/bom_setuptools_complete.xml +++ b/tests/fixtures/xml/1.3/bom_setuptools_complete.xml @@ -11,7 +11,7 @@ - + CycloneDX https://cyclonedx.org @@ -178,6 +178,6 @@ - + \ No newline at end of file diff --git a/tests/fixtures/xml/1.3/bom_with_full_metadata.xml b/tests/fixtures/xml/1.3/bom_with_full_metadata.xml index 6c72aea7..e1b0b356 100644 --- a/tests/fixtures/xml/1.3/bom_with_full_metadata.xml +++ b/tests/fixtures/xml/1.3/bom_with_full_metadata.xml @@ -21,8 +21,169 @@ - cyclonedx-python-lib - 1.0.0 + + CycloneDX + https://cyclonedx.org + + Paul Horton + paul.horton@owasp.org + + + A N Other + someone@somewhere.tld + +44 (0)1234 567890 + + + Test Author + CycloneDX + setuptools + 50.3.2 + This component is awesome + required + + MIT License + + Apache 2.0 baby! + cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:* + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg== + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + Test Author + setuptools + + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + + + Test Author + setuptools + + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + + + a-random-uid + A commit message + + + + + + Some notes here please + + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + val1 + val2 + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + + + Commercial + Commercial 2 + + CycloneDX diff --git a/tests/fixtures/xml/1.4/bom_issue_275_components.xml b/tests/fixtures/xml/1.4/bom_issue_275_components.xml new file mode 100644 index 00000000..67e58b1e --- /dev/null +++ b/tests/fixtures/xml/1.4/bom_issue_275_components.xml @@ -0,0 +1,69 @@ + + + + 2021-09-01T10:50:42.051979+00:00 + + + CycloneDX + cyclonedx-python-lib + VERSION + + + https://github.com/CycloneDX/cyclonedx-python-lib/actions + + + https://pypi.org/project/cyclonedx-python-lib/ + + + https://cyclonedx.github.io/cyclonedx-python-lib/ + + + https://github.com/CycloneDX/cyclonedx-python-lib/issues + + + https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE + + + https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md + + + https://github.com/CycloneDX/cyclonedx-python-lib + + + https://cyclonedx.org + + + + + + app + 1.0.0 + + + + + comp_a + 1.0.0 + + + comp_b + 1.0.0 + + + comp_c + 1.0.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/fixtures/xml/1.4/bom_setuptools_complete.xml b/tests/fixtures/xml/1.4/bom_setuptools_complete.xml index 41bbc6e4..a90e3108 100644 --- a/tests/fixtures/xml/1.4/bom_setuptools_complete.xml +++ b/tests/fixtures/xml/1.4/bom_setuptools_complete.xml @@ -37,7 +37,7 @@ - + CycloneDX https://cyclonedx.org @@ -246,6 +246,6 @@ - + \ No newline at end of file diff --git a/tests/fixtures/xml/1.4/bom_with_full_metadata.xml b/tests/fixtures/xml/1.4/bom_with_full_metadata.xml index 39cd8b8a..1d8022af 100644 --- a/tests/fixtures/xml/1.4/bom_with_full_metadata.xml +++ b/tests/fixtures/xml/1.4/bom_with_full_metadata.xml @@ -47,8 +47,211 @@ - cyclonedx-python-lib - 1.0.0 + + CycloneDX + https://cyclonedx.org + + Paul Horton + paul.horton@owasp.org + + + A N Other + someone@somewhere.tld + +44 (0)1234 567890 + + + Test Author + CycloneDX + setuptools + 50.3.2 + This component is awesome + required + + MIT License + + Apache 2.0 baby! + cpe:2.3:a:python:setuptools:50.3.2:*:*:*:*:*:*:* + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg== + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + Test Author + setuptools + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + + + Test Author + setuptools + + MIT License + + pkg:pypi/setuptools?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + + + a-random-uid + A commit message + + + + + + Some notes here please + + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + val1 + val2 + + + + Test Author + setuptools + 50.3.2 + + MIT License + + pkg:pypi/setuptools@50.3.2?extension=tar.gz + + + toml + 0.10.2 + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + pkg:pypi/toml@0.10.2?extension=tar.gz + + + https://cyclonedx.org + No comment + + 806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b + + + + + + + + Commercial + Commercial 2 + + + + major + Release Notes Title + https://cyclonedx.org/theme/assets/images/CycloneDX-Twitter-Card.png + https://cyclonedx.org/cyclonedx-icon.png + This release is a test release + 2021-12-31T10:00:00+00:00 + + First Test Release + + + test + alpha + + + + CVE-2021-44228 + Apache Log3Shell + Apache Log4j2 2.0-beta9 through 2.12.1 and 2.13.0 through 2.15.0 JNDI features... + + NVD + https://nvd.nist.gov/vuln/detail/CVE-2021-44228 + + + https://logging.apache.org/log4j/2.x/security.html + https://central.sonatype.org/news/20211213_log4shell_help + + + + + + en-GB + U29tZSBzaW1wbGUgcGxhaW4gdGV4dA== + + + en-US + U29tZSBzaW1wbGUgcGxhaW4gdGV4dA== + + + + val1 + val2 + + CycloneDX diff --git a/tests/test_component.py b/tests/test_component.py index 2a0c676e..f9d1648e 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -20,14 +20,13 @@ from os.path import dirname, join from unittest import TestCase -from data import get_component_setuptools_simple, get_component_setuptools_simple_no_version - # See https://github.com/package-url/packageurl-python/issues/65 from packageurl import PackageURL # type: ignore from cyclonedx.model import sha1sum from cyclonedx.model.bom import Bom from cyclonedx.model.component import Component +from data import get_component_setuptools_simple, get_component_setuptools_simple_no_version FIXTURES_DIRECTORY = 'fixtures/xml/1.4' diff --git a/tests/test_model_bom.py b/tests/test_model_bom.py index 868baf48..6636d863 100644 --- a/tests/test_model_bom.py +++ b/tests/test_model_bom.py @@ -19,11 +19,10 @@ from unittest import TestCase -from data import get_bom_with_component_setuptools_with_vulnerability - from cyclonedx.model import License, LicenseChoice, OrganizationalContact, OrganizationalEntity, Property from cyclonedx.model.bom import Bom, BomMetaData, ThisTool, Tool from cyclonedx.model.component import Component, ComponentType +from data import get_bom_for_issue_275_components, get_bom_with_component_setuptools_with_vulnerability class TestBomMetaData(TestCase): @@ -116,3 +115,15 @@ def test_empty_bom(self) -> None: def test_bom_with_vulnerabilities(self) -> None: bom = get_bom_with_component_setuptools_with_vulnerability() self.assertTrue(bom.has_vulnerabilities()) + + def test_bom_nested_components_issue_275(self) -> None: + bom = get_bom_for_issue_275_components() + self.assertIsInstance(bom.metadata.component, Component) + self.assertEqual(2, len(bom.components)) + bom.validate() + + # def test_bom_nested_services_issue_275(self) -> None: + # bom = get_bom_for_issue_275_services() + # self.assertIsInstance(bom.metadata.component, Component) + # self.assertEqual(2, len(bom.services)) + # bom.validate() diff --git a/tests/test_model_component.py b/tests/test_model_component.py index fb695d53..78e6c4c0 100644 --- a/tests/test_model_component.py +++ b/tests/test_model_component.py @@ -22,17 +22,6 @@ from unittest import TestCase from unittest.mock import Mock, patch -from data import ( - get_component_setuptools_simple, - get_component_setuptools_simple_no_version, - get_component_toml_with_hashes_with_references, - get_issue_1, - get_issue_2, - get_pedigree_1, - get_swid_1, - get_swid_2, -) - from cyclonedx.exception.model import NoPropertiesProvidedException from cyclonedx.model import ( AttachedText, @@ -55,6 +44,16 @@ Pedigree, ) from cyclonedx.model.issue import IssueClassification, IssueType +from data import ( + get_component_setuptools_simple, + get_component_setuptools_simple_no_version, + get_component_toml_with_hashes_with_references, + get_issue_1, + get_issue_2, + get_pedigree_1, + get_swid_1, + get_swid_2, +) from tests.data import reorder @@ -131,7 +130,8 @@ def test_empty_basic_component(self, mock_uuid: Mock) -> None: self.assertSetEqual(c.external_references, set()) self.assertFalse(c.properties) self.assertIsNone(c.release_notes) - + self.assertEqual(0, len(c.components)) + self.assertEqual(0, len(c.get_all_nested_components())) self.assertEqual(len(c.get_vulnerabilities()), 0) @patch('cyclonedx.model.bom_ref.uuid4', return_value='6f266d1c-760f-4552-ae3b-41a9b74232fa') @@ -318,6 +318,28 @@ def test_sort(self) -> None: 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", version="1.0.0") + comp_c = Component(name="comp_c", version="1.0.0") + comp_b.components.add(comp_c) + comp_b.dependencies.add(comp_c.bom_ref) + + self.assertEqual(1, len(comp_b.components)) + self.assertEqual(2, len(comp_b.get_all_nested_components(include_self=True))) + self.assertEqual(1, len(comp_b.get_all_nested_components(include_self=False))) + + def test_nested_components_2(self) -> None: + comp_a = Component(name="comp_a", version="1.2.3") + comp_b = Component(name="comp_b", version="1.0.0") + comp_c = Component(name="comp_c", version="1.0.0") + comp_b.components.add(comp_c) + comp_b.dependencies.add(comp_c.bom_ref) + comp_b.components.add(comp_a) + + self.assertEqual(2, len(comp_b.components)) + self.assertEqual(3, len(comp_b.get_all_nested_components(include_self=True))) + self.assertEqual(2, len(comp_b.get_all_nested_components(include_self=False))) + class TestModelComponentEvidence(TestCase): diff --git a/tests/test_model_issue.py b/tests/test_model_issue.py index 96bca6bd..c98cbf87 100644 --- a/tests/test_model_issue.py +++ b/tests/test_model_issue.py @@ -19,11 +19,10 @@ from unittest import TestCase -from data import get_issue_1, get_issue_2 - from cyclonedx.exception.model import NoPropertiesProvidedException from cyclonedx.model import XsUri from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource +from data import get_issue_1, get_issue_2 from tests.data import reorder diff --git a/tests/test_output_json.py b/tests/test_output_json.py index 24469cbe..18ffbb89 100644 --- a/tests/test_output_json.py +++ b/tests/test_output_json.py @@ -20,10 +20,15 @@ from os.path import dirname, join from unittest.mock import Mock, patch +from cyclonedx.exception.model import UnknownComponentDependencyException +from cyclonedx.exception.output import FormatNotSupportedException +from cyclonedx.model.bom import Bom +from cyclonedx.output import OutputFormat, SchemaVersion, get_instance from data import ( MOCK_UUID_1, MOCK_UUID_2, MOCK_UUID_3, + MOCK_UUID_6, TEST_UUIDS, get_bom_just_complete_metadata, get_bom_with_component_setuptools_basic, @@ -41,12 +46,8 @@ get_bom_with_services_complex, get_bom_with_services_simple, ) - -from cyclonedx.exception.model import UnknownComponentDependencyException -from cyclonedx.exception.output import FormatNotSupportedException -from cyclonedx.model.bom import Bom -from cyclonedx.output import OutputFormat, SchemaVersion, get_instance from tests.base import BaseJsonTestCase +from tests.data import get_bom_for_issue_275_components class TestOutputJson(BaseJsonTestCase): @@ -115,24 +116,30 @@ def test_simple_bom_v1_2_with_cpe(self) -> None: fixture='bom_setuptools_with_cpe.json' ) - def test_bom_v1_4_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_6) + def test_bom_v1_4_full_component(self, mock: Mock) -> None: self.maxDiff = None self._validate_json_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4, fixture='bom_setuptools_complete.json' ) + mock.assert_called() - def test_bom_v1_3_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_6) + def test_bom_v1_3_full_component(self, mock: Mock) -> None: self._validate_json_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3, fixture='bom_setuptools_complete.json' ) + mock.assert_called() - def test_bom_v1_2_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_6) + def test_bom_v1_2_full_component(self, mock: Mock) -> None: self._validate_json_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2, fixture='bom_setuptools_complete.json' ) + mock.assert_called() def test_bom_v1_4_component_hashes_external_references(self) -> None: self._validate_json_bom( @@ -197,99 +204,111 @@ def test_bom_v1_3_component_with_vulnerability(self) -> None: @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_1) def test_bom_v1_4_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4, - fixture='bom_with_full_metadata.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4, + fixture='bom_with_full_metadata.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_2) def test_bom_v1_3_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3, - fixture='bom_with_full_metadata.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3, + fixture='bom_with_full_metadata.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_3) def test_bom_v1_2_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2, - fixture='bom_with_full_metadata.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2, + fixture='bom_with_full_metadata.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_simple(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_simple.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_simple.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_simple(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_simple.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_simple.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_simple(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_simple.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_simple.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_complex(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_complex.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_complex.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_complex(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_complex.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_complex.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_complex(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_complex.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_complex.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_nested(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_nested.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_nested.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_nested(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_nested.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_nested.json' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_nested(self, mock_uuid: Mock) -> None: - self._validate_json_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_nested.json' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_json_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_nested.json' + ) + mock_uuid.assert_called() def test_bom_v1_4_dependencies(self) -> None: self._validate_json_bom( @@ -334,6 +353,24 @@ def test_bom_v1_4_dependencies_invalid(self) -> None: fixture='bom_dependencies.json' ) + def test_bom_v1_4_issue_275_components(self) -> None: + self._validate_json_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_4, + fixture='bom_issue_275_components.json' + ) + + def test_bom_v1_3_issue_275_components(self) -> None: + self._validate_json_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_3, + fixture='bom_issue_275_components.json' + ) + + def test_bom_v1_2_issue_275_components(self) -> None: + self._validate_json_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_2, + fixture='bom_issue_275_components.json' + ) + # Helper methods def _validate_json_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None: outputter = get_instance(bom=bom, output_format=OutputFormat.JSON, schema_version=schema_version) diff --git a/tests/test_output_xml.py b/tests/test_output_xml.py index deffe5e8..487f15e7 100644 --- a/tests/test_output_xml.py +++ b/tests/test_output_xml.py @@ -20,8 +20,13 @@ from os.path import dirname, join from unittest.mock import Mock, patch +from cyclonedx.exception.model import UnknownComponentDependencyException +from cyclonedx.model.bom import Bom +from cyclonedx.output import SchemaVersion, get_instance from data import ( MOCK_UUID_1, + MOCK_UUID_2, + MOCK_UUID_3, MOCK_UUID_4, MOCK_UUID_5, MOCK_UUID_6, @@ -42,11 +47,8 @@ get_bom_with_services_complex, get_bom_with_services_simple, ) - -from cyclonedx.exception.model import UnknownComponentDependencyException -from cyclonedx.model.bom import Bom -from cyclonedx.output import SchemaVersion, get_instance from tests.base import BaseXmlTestCase +from tests.data import get_bom_for_issue_275_components class TestOutputXml(BaseXmlTestCase): @@ -141,29 +143,37 @@ def test_simple_bom_v1_0_with_cpe(self) -> None: fixture='bom_setuptools_with_cpe.xml' ) - def test_bom_v1_4_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_4) + def test_bom_v1_4_full_component(self, mock_uuid: Mock) -> None: self._validate_xml_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_4, fixture='bom_setuptools_complete.xml' ) + mock_uuid.assert_called() - def test_bom_v1_3_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_3) + def test_bom_v1_3_full_component(self, mock_uuid: Mock) -> None: self._validate_xml_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_3, fixture='bom_setuptools_complete.xml' ) + mock_uuid.assert_called() - def test_bom_v1_2_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_2) + def test_bom_v1_2_full_component(self, mock_uuid: Mock) -> None: self._validate_xml_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_2, fixture='bom_setuptools_complete.xml' ) + mock_uuid.assert_called() - def test_bom_v1_1_full_component(self) -> None: + @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_1) + def test_bom_v1_1_full_component(self, mock_uuid: Mock) -> None: self._validate_xml_bom( bom=get_bom_with_component_setuptools_complete(), schema_version=SchemaVersion.V1_1, fixture='bom_setuptools_complete.xml' ) + mock_uuid.assert_called() def test_bom_v1_0_full_component(self) -> None: self._validate_xml_bom( @@ -275,139 +285,156 @@ def test_bom_v1_0_component_with_vulnerability(self) -> None: @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_6) def test_bom_v1_4_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4, - fixture='bom_with_full_metadata.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_4, + fixture='bom_with_full_metadata.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_5) def test_bom_v1_3_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3, - fixture='bom_with_full_metadata.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_3, + fixture='bom_with_full_metadata.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_4) def test_bom_v1_2_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2, - fixture='bom_with_full_metadata.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_2, + fixture='bom_with_full_metadata.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_1) def test_bom_v1_1_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_1, - fixture='bom_empty.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_1, + fixture='bom_empty.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', return_value=MOCK_UUID_1) def test_bom_v1_0_with_metadata_component(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_0, - fixture='bom_empty.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_just_complete_metadata(), schema_version=SchemaVersion.V1_0, + fixture='bom_empty.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_simple(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_simple.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_simple.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_simple(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_simple.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_simple.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_simple(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_simple.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_simple.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_1_services_simple(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_1, - fixture='bom_empty.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_1, + fixture='bom_empty.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_0_services_simple(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_0, - fixture='bom_empty.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_simple(), schema_version=SchemaVersion.V1_0, + fixture='bom_empty.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_complex(self, mock_uuid4: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_complex.xml' - ) - mock_uuid4.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_complex.xml' + ) + mock_uuid4.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_complex(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_complex.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_complex.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_complex(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_complex.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_complex.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_1_services_complex(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_1, - fixture='bom_empty.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_services_complex(), schema_version=SchemaVersion.V1_1, + fixture='bom_empty.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_4_services_nested(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4, - fixture='bom_services_nested.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_4, + fixture='bom_services_nested.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_3_services_nested(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3, - fixture='bom_services_nested.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_3, + fixture='bom_services_nested.xml' + ) + mock_uuid.assert_called() @patch('cyclonedx.model.bom_ref.uuid4', side_effect=TEST_UUIDS) def test_bom_v1_2_services_nested(self, mock_uuid: Mock) -> None: - self._validate_xml_bom( - bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2, - fixture='bom_services_nested.xml' - ) - mock_uuid.assert_called() + with self.assertWarns(UserWarning): + self._validate_xml_bom( + bom=get_bom_with_nested_services(), schema_version=SchemaVersion.V1_2, + fixture='bom_services_nested.xml' + ) + mock_uuid.assert_called() def test_bom_v1_4_dependencies(self) -> None: self._validate_xml_bom( @@ -458,6 +485,36 @@ def test_bom_v1_4_dependencies_invalid(self) -> None: fixture='bom_dependencies.xml' ) + def test_bom_v1_4_issue_275_components(self) -> None: + self._validate_xml_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_4, + fixture='bom_issue_275_components.xml' + ) + + def test_bom_v1_3_issue_275_components(self) -> None: + self._validate_xml_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_3, + fixture='bom_issue_275_components.xml' + ) + + def test_bom_v1_2_issue_275_components(self) -> None: + self._validate_xml_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_2, + fixture='bom_issue_275_components.xml' + ) + + def test_bom_v1_1_issue_275_components(self) -> None: + self._validate_xml_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_1, + fixture='bom_issue_275_components.xml' + ) + + def test_bom_v1_0_issue_275_components(self) -> None: + self._validate_xml_bom( + bom=get_bom_for_issue_275_components(), schema_version=SchemaVersion.V1_0, + fixture='bom_issue_275_components.xml' + ) + # Helper methods def _validate_xml_bom(self, bom: Bom, schema_version: SchemaVersion, fixture: str) -> None: outputter = get_instance(bom=bom, schema_version=schema_version)