Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8df488c

Browse files
jkowalleckmadpah
andauthoredApr 26, 2024··
fix: properly sort components based on all properties (#599)
reverts #587 - as this one introduced errors fixes #598 fixes #586 --------- Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> Signed-off-by: Paul Horton <paul.horton@owasp.org> Co-authored-by: Paul Horton <paul.horton@owasp.org>
1 parent 25ea611 commit 8df488c

27 files changed

+835
-23
lines changed
 

‎.github/workflows/python.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ jobs:
115115
strategy:
116116
fail-fast: false
117117
matrix:
118-
os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
118+
os: ['ubuntu-latest', 'windows-latest', 'macos-13']
119119
python-version:
120120
- "3.12" # highest supported
121121
- "3.11"

‎cyclonedx/_internal/compare.py

+43-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
Everything might change without any notice.
2020
"""
2121

22-
2322
from itertools import zip_longest
24-
from typing import Any, Optional, Tuple
23+
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple
24+
25+
if TYPE_CHECKING: # pragma: no cover
26+
from packageurl import PackageURL
2527

2628

2729
class ComparableTuple(Tuple[Optional[Any], ...]):
@@ -52,3 +54,42 @@ def __gt__(self, other: Any) -> bool:
5254
return False
5355
return True if s > o else False
5456
return False
57+
58+
59+
class ComparableDict:
60+
"""
61+
Allows comparison of dictionaries, allowing for missing/None values.
62+
"""
63+
64+
def __init__(self, dict_: Dict[Any, Any]) -> None:
65+
self._dict = dict_
66+
67+
def __lt__(self, other: Any) -> bool:
68+
if not isinstance(other, ComparableDict):
69+
return True
70+
keys = sorted(self._dict.keys() | other._dict.keys())
71+
return ComparableTuple(self._dict.get(k) for k in keys) \
72+
< ComparableTuple(other._dict.get(k) for k in keys)
73+
74+
def __gt__(self, other: Any) -> bool:
75+
if not isinstance(other, ComparableDict):
76+
return False
77+
keys = sorted(self._dict.keys() | other._dict.keys())
78+
return ComparableTuple(self._dict.get(k) for k in keys) \
79+
> ComparableTuple(other._dict.get(k) for k in keys)
80+
81+
82+
class ComparablePackageURL(ComparableTuple):
83+
"""
84+
Allows comparison of PackageURL, allowing for qualifiers.
85+
"""
86+
87+
def __new__(cls, purl: 'PackageURL') -> 'ComparablePackageURL':
88+
return super().__new__(
89+
ComparablePackageURL, (
90+
purl.type,
91+
purl.namespace,
92+
purl.version,
93+
ComparableDict(purl.qualifiers) if isinstance(purl.qualifiers, dict) else purl.qualifiers,
94+
purl.subpath
95+
))

‎cyclonedx/model/component.py

+30-16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#
1515
# SPDX-License-Identifier: Apache-2.0
1616
# Copyright (c) OWASP Foundation. All Rights Reserved.
17+
1718
import re
1819
from enum import Enum
1920
from os.path import exists
@@ -25,7 +26,7 @@
2526
from packageurl import PackageURL
2627
from sortedcontainers import SortedSet
2728

28-
from .._internal.compare import ComparableTuple as _ComparableTuple
29+
from .._internal.compare import ComparablePackageURL as _ComparablePackageURL, ComparableTuple as _ComparableTuple
2930
from .._internal.hash import file_sha1sum as _file_sha1sum
3031
from ..exception.model import InvalidOmniBorIdException, InvalidSwhidException, NoPropertiesProvidedException
3132
from ..exception.serialization import (
@@ -42,7 +43,7 @@
4243
SchemaVersion1Dot5,
4344
SchemaVersion1Dot6,
4445
)
45-
from ..serialization import BomRefHelper, LicenseRepositoryHelper, PackageUrl
46+
from ..serialization import BomRefHelper, LicenseRepositoryHelper, PackageUrl as PackageUrlSH
4647
from . import (
4748
AttachedText,
4849
Copyright,
@@ -1406,7 +1407,7 @@ def cpe(self, cpe: Optional[str]) -> None:
14061407
self._cpe = cpe
14071408

14081409
@property
1409-
@serializable.type_mapping(PackageUrl)
1410+
@serializable.type_mapping(PackageUrlSH)
14101411
@serializable.xml_sequence(15)
14111412
def purl(self) -> Optional[PackageURL]:
14121413
"""
@@ -1699,29 +1700,42 @@ def __eq__(self, other: object) -> bool:
16991700
def __lt__(self, other: Any) -> bool:
17001701
if isinstance(other, Component):
17011702
return _ComparableTuple((
1702-
self.type, self.mime_type, self.supplier, self.author, self.publisher, self.group, self.name,
1703-
self.version, self.description, self.scope, _ComparableTuple(self.hashes),
1704-
_ComparableTuple(self.licenses), self.copyright, self.cpe, self.purl, self.swid, self.pedigree,
1703+
self.type, self.group, self.name, self.version,
1704+
self.mime_type, self.supplier, self.author, self.publisher,
1705+
self.description, self.scope, _ComparableTuple(self.hashes),
1706+
_ComparableTuple(self.licenses), self.copyright, self.cpe,
1707+
None if self.purl is None else _ComparablePackageURL(self.purl),
1708+
self.swid, self.pedigree,
17051709
_ComparableTuple(self.external_references), _ComparableTuple(self.properties),
17061710
_ComparableTuple(self.components), self.evidence, self.release_notes, self.modified,
1707-
_ComparableTuple(self.authors), _ComparableTuple(self.omnibor_ids),
1711+
_ComparableTuple(self.authors), _ComparableTuple(self.omnibor_ids), self.manufacturer,
1712+
_ComparableTuple(self.swhids), self.crypto_properties, _ComparableTuple(self.tags)
17081713
)) < _ComparableTuple((
1709-
other.type, other.mime_type, other.supplier, other.author, other.publisher, other.group, other.name,
1710-
other.version, other.description, other.scope, _ComparableTuple(other.hashes),
1711-
_ComparableTuple(other.licenses), other.copyright, other.cpe, other.purl, other.swid, other.pedigree,
1714+
other.type, other.group, other.name, other.version,
1715+
other.mime_type, other.supplier, other.author, other.publisher,
1716+
other.description, other.scope, _ComparableTuple(other.hashes),
1717+
_ComparableTuple(other.licenses), other.copyright, other.cpe,
1718+
None if other.purl is None else _ComparablePackageURL(other.purl),
1719+
other.swid, other.pedigree,
17121720
_ComparableTuple(other.external_references), _ComparableTuple(other.properties),
17131721
_ComparableTuple(other.components), other.evidence, other.release_notes, other.modified,
1714-
_ComparableTuple(other.authors), _ComparableTuple(other.omnibor_ids),
1722+
_ComparableTuple(other.authors), _ComparableTuple(other.omnibor_ids), other.manufacturer,
1723+
_ComparableTuple(other.swhids), other.crypto_properties, _ComparableTuple(other.tags)
17151724
))
17161725
return NotImplemented
17171726

17181727
def __hash__(self) -> int:
17191728
return hash((
1720-
self.type, self.mime_type, self.supplier, self.author, self.publisher, self.group, self.name,
1721-
self.version, self.description, self.scope, tuple(self.hashes), tuple(self.licenses), self.copyright,
1722-
self.cpe, self.purl, self.swid, self.pedigree, tuple(self.external_references), tuple(self.properties),
1723-
tuple(self.components), self.evidence, self.release_notes, self.modified, tuple(self.authors),
1724-
tuple(self.omnibor_ids),
1729+
self.type, self.group, self.name, self.version,
1730+
self.mime_type, self.supplier, self.author, self.publisher,
1731+
self.description, self.scope, tuple(self.hashes),
1732+
tuple(self.licenses), self.copyright, self.cpe,
1733+
self.purl,
1734+
self.swid, self.pedigree,
1735+
tuple(self.external_references), tuple(self.properties),
1736+
tuple(self.components), self.evidence, self.release_notes, self.modified,
1737+
tuple(self.authors), tuple(self.omnibor_ids), self.manufacturer,
1738+
tuple(self.swhids), self.crypto_properties, tuple(self.tags)
17251739
))
17261740

17271741
def __repr__(self) -> str:

‎tests/_data/models.py

+37-4
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,12 @@ def get_bom_with_licenses() -> Bom:
954954
url=XsUri('https://www.apache.org/licenses/LICENSE-2.0.html'),
955955
acknowledgement=LicenseAcknowledgement.CONCLUDED)]),
956956
Component(name='c-with-name', type=ComponentType.LIBRARY, bom_ref='C3',
957-
licenses=[DisjunctiveLicense(name='some commercial license',
958-
text=AttachedText(content='this is a license text'))]),
957+
licenses=[
958+
DisjunctiveLicense(name='some commercial license',
959+
text=AttachedText(content='this is a license text')),
960+
DisjunctiveLicense(name='some additional',
961+
text=AttachedText(content='this is additional license text')),
962+
]),
959963
],
960964
services=[
961965
Service(name='s-with-expression', bom_ref='S1',
@@ -966,8 +970,12 @@ def get_bom_with_licenses() -> Bom:
966970
url=XsUri('https://www.apache.org/licenses/LICENSE-2.0.html'),
967971
acknowledgement=LicenseAcknowledgement.DECLARED)]),
968972
Service(name='s-with-name', bom_ref='S3',
969-
licenses=[DisjunctiveLicense(name='some commercial license',
970-
text=AttachedText(content='this is a license text'))]),
973+
licenses=[
974+
DisjunctiveLicense(name='some commercial license',
975+
text=AttachedText(content='this is a license text')),
976+
DisjunctiveLicense(name='some additional',
977+
text=AttachedText(content='this is additional license text')),
978+
]),
971979
])
972980

973981

@@ -1064,6 +1072,30 @@ def get_bom_for_issue_497_urls() -> Bom:
10641072
])
10651073

10661074

1075+
def get_bom_for_issue_598_multiple_components_with_purl_qualifiers() -> Bom:
1076+
"""regression test for issue #598
1077+
see https://github.com/CycloneDX/cyclonedx-python-lib/issues/598
1078+
"""
1079+
return _make_bom(components=[
1080+
Component(
1081+
name='dummy', version='2.3.5', bom_ref='dummy-a',
1082+
purl=PackageURL(
1083+
type='pypi', namespace=None, name='pathlib2', version='2.3.5', subpath=None,
1084+
qualifiers={}
1085+
)
1086+
),
1087+
Component(
1088+
name='dummy', version='2.3.5', bom_ref='dummy-b',
1089+
purl=PackageURL(
1090+
type='pypi', namespace=None, name='pathlib2', version='2.3.5', subpath=None,
1091+
qualifiers={
1092+
'vcs_url': 'git+https://github.com/jazzband/pathlib2.git@5a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6'
1093+
}
1094+
)
1095+
)
1096+
])
1097+
1098+
10671099
def bom_all_same_bomref() -> Tuple[Bom, int]:
10681100
bom = Bom()
10691101
bom.metadata.component = Component(name='root', bom_ref='foo', components=[
@@ -1113,5 +1145,6 @@ def bom_all_same_bomref() -> Tuple[Bom, int]:
11131145
get_bom_with_licenses,
11141146
get_bom_with_multiple_licenses,
11151147
get_bom_for_issue_497_urls,
1148+
get_bom_for_issue_598_multiple_components_with_purl_qualifiers,
11161149
get_bom_with_component_setuptools_with_v16_fields,
11171150
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
3+
<components>
4+
<component type="library">
5+
<name>dummy</name>
6+
<version>2.3.5</version>
7+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
8+
<modified>false</modified>
9+
</component>
10+
<component type="library">
11+
<name>dummy</name>
12+
<version>2.3.5</version>
13+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
14+
<modified>false</modified>
15+
</component>
16+
</components>
17+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<components>
4+
<component type="library" bom-ref="dummy-b">
5+
<name>dummy</name>
6+
<version>2.3.5</version>
7+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
8+
</component>
9+
<component type="library" bom-ref="dummy-a">
10+
<name>dummy</name>
11+
<version>2.3.5</version>
12+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
13+
</component>
14+
</components>
15+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"components": [
3+
{
4+
"bom-ref": "dummy-b",
5+
"name": "dummy",
6+
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
7+
"type": "library",
8+
"version": "2.3.5"
9+
},
10+
{
11+
"bom-ref": "dummy-a",
12+
"name": "dummy",
13+
"purl": "pkg:pypi/pathlib2@2.3.5",
14+
"type": "library",
15+
"version": "2.3.5"
16+
}
17+
],
18+
"dependencies": [
19+
{
20+
"ref": "dummy-a"
21+
},
22+
{
23+
"ref": "dummy-b"
24+
}
25+
],
26+
"metadata": {
27+
"timestamp": "2023-01-07T13:44:32.312678+00:00",
28+
"tools": [
29+
{
30+
"name": "cyclonedx-python-lib",
31+
"vendor": "CycloneDX",
32+
"version": "TESTING"
33+
}
34+
]
35+
},
36+
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
37+
"version": 1,
38+
"$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
39+
"bomFormat": "CycloneDX",
40+
"specVersion": "1.2"
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<metadata>
4+
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
5+
<tools>
6+
<tool>
7+
<vendor>CycloneDX</vendor>
8+
<name>cyclonedx-python-lib</name>
9+
<version>TESTING</version>
10+
</tool>
11+
</tools>
12+
</metadata>
13+
<components>
14+
<component type="library" bom-ref="dummy-b">
15+
<name>dummy</name>
16+
<version>2.3.5</version>
17+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
18+
</component>
19+
<component type="library" bom-ref="dummy-a">
20+
<name>dummy</name>
21+
<version>2.3.5</version>
22+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
23+
</component>
24+
</components>
25+
<dependencies>
26+
<dependency ref="dummy-a"/>
27+
<dependency ref="dummy-b"/>
28+
</dependencies>
29+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"components": [
3+
{
4+
"bom-ref": "dummy-b",
5+
"name": "dummy",
6+
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
7+
"type": "library",
8+
"version": "2.3.5"
9+
},
10+
{
11+
"bom-ref": "dummy-a",
12+
"name": "dummy",
13+
"purl": "pkg:pypi/pathlib2@2.3.5",
14+
"type": "library",
15+
"version": "2.3.5"
16+
}
17+
],
18+
"dependencies": [
19+
{
20+
"ref": "dummy-a"
21+
},
22+
{
23+
"ref": "dummy-b"
24+
}
25+
],
26+
"metadata": {
27+
"timestamp": "2023-01-07T13:44:32.312678+00:00",
28+
"tools": [
29+
{
30+
"name": "cyclonedx-python-lib",
31+
"vendor": "CycloneDX",
32+
"version": "TESTING"
33+
}
34+
]
35+
},
36+
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
37+
"version": 1,
38+
"$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
39+
"bomFormat": "CycloneDX",
40+
"specVersion": "1.3"
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<metadata>
4+
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
5+
<tools>
6+
<tool>
7+
<vendor>CycloneDX</vendor>
8+
<name>cyclonedx-python-lib</name>
9+
<version>TESTING</version>
10+
</tool>
11+
</tools>
12+
</metadata>
13+
<components>
14+
<component type="library" bom-ref="dummy-b">
15+
<name>dummy</name>
16+
<version>2.3.5</version>
17+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
18+
</component>
19+
<component type="library" bom-ref="dummy-a">
20+
<name>dummy</name>
21+
<version>2.3.5</version>
22+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
23+
</component>
24+
</components>
25+
<dependencies>
26+
<dependency ref="dummy-a"/>
27+
<dependency ref="dummy-b"/>
28+
</dependencies>
29+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
{
2+
"components": [
3+
{
4+
"bom-ref": "dummy-b",
5+
"name": "dummy",
6+
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
7+
"type": "library",
8+
"version": "2.3.5"
9+
},
10+
{
11+
"bom-ref": "dummy-a",
12+
"name": "dummy",
13+
"purl": "pkg:pypi/pathlib2@2.3.5",
14+
"type": "library",
15+
"version": "2.3.5"
16+
}
17+
],
18+
"dependencies": [
19+
{
20+
"ref": "dummy-a"
21+
},
22+
{
23+
"ref": "dummy-b"
24+
}
25+
],
26+
"metadata": {
27+
"timestamp": "2023-01-07T13:44:32.312678+00:00",
28+
"tools": [
29+
{
30+
"externalReferences": [
31+
{
32+
"type": "build-system",
33+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
34+
},
35+
{
36+
"type": "distribution",
37+
"url": "https://pypi.org/project/cyclonedx-python-lib/"
38+
},
39+
{
40+
"type": "documentation",
41+
"url": "https://cyclonedx-python-library.readthedocs.io/"
42+
},
43+
{
44+
"type": "issue-tracker",
45+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
46+
},
47+
{
48+
"type": "license",
49+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
50+
},
51+
{
52+
"type": "release-notes",
53+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
54+
},
55+
{
56+
"type": "vcs",
57+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
58+
},
59+
{
60+
"type": "website",
61+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme"
62+
}
63+
],
64+
"name": "cyclonedx-python-lib",
65+
"vendor": "CycloneDX",
66+
"version": "TESTING"
67+
}
68+
]
69+
},
70+
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
71+
"version": 1,
72+
"$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
73+
"bomFormat": "CycloneDX",
74+
"specVersion": "1.4"
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<metadata>
4+
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
5+
<tools>
6+
<tool>
7+
<vendor>CycloneDX</vendor>
8+
<name>cyclonedx-python-lib</name>
9+
<version>TESTING</version>
10+
<externalReferences>
11+
<reference type="build-system">
12+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
13+
</reference>
14+
<reference type="distribution">
15+
<url>https://pypi.org/project/cyclonedx-python-lib/</url>
16+
</reference>
17+
<reference type="documentation">
18+
<url>https://cyclonedx-python-library.readthedocs.io/</url>
19+
</reference>
20+
<reference type="issue-tracker">
21+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
22+
</reference>
23+
<reference type="license">
24+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
25+
</reference>
26+
<reference type="release-notes">
27+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
28+
</reference>
29+
<reference type="vcs">
30+
<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
31+
</reference>
32+
<reference type="website">
33+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/#readme</url>
34+
</reference>
35+
</externalReferences>
36+
</tool>
37+
</tools>
38+
</metadata>
39+
<components>
40+
<component type="library" bom-ref="dummy-b">
41+
<name>dummy</name>
42+
<version>2.3.5</version>
43+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
44+
</component>
45+
<component type="library" bom-ref="dummy-a">
46+
<name>dummy</name>
47+
<version>2.3.5</version>
48+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
49+
</component>
50+
</components>
51+
<dependencies>
52+
<dependency ref="dummy-a"/>
53+
<dependency ref="dummy-b"/>
54+
</dependencies>
55+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"components": [
3+
{
4+
"bom-ref": "dummy-b",
5+
"name": "dummy",
6+
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
7+
"type": "library",
8+
"version": "2.3.5"
9+
},
10+
{
11+
"bom-ref": "dummy-a",
12+
"name": "dummy",
13+
"purl": "pkg:pypi/pathlib2@2.3.5",
14+
"type": "library",
15+
"version": "2.3.5"
16+
}
17+
],
18+
"dependencies": [
19+
{
20+
"ref": "dummy-a"
21+
},
22+
{
23+
"ref": "dummy-b"
24+
}
25+
],
26+
"metadata": {
27+
"timestamp": "2023-01-07T13:44:32.312678+00:00",
28+
"tools": [
29+
{
30+
"externalReferences": [
31+
{
32+
"type": "build-system",
33+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
34+
},
35+
{
36+
"type": "distribution",
37+
"url": "https://pypi.org/project/cyclonedx-python-lib/"
38+
},
39+
{
40+
"type": "documentation",
41+
"url": "https://cyclonedx-python-library.readthedocs.io/"
42+
},
43+
{
44+
"type": "issue-tracker",
45+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
46+
},
47+
{
48+
"type": "license",
49+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
50+
},
51+
{
52+
"type": "release-notes",
53+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
54+
},
55+
{
56+
"type": "vcs",
57+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
58+
},
59+
{
60+
"type": "website",
61+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme"
62+
}
63+
],
64+
"name": "cyclonedx-python-lib",
65+
"vendor": "CycloneDX",
66+
"version": "TESTING"
67+
}
68+
]
69+
},
70+
"properties": [
71+
{
72+
"name": "key1",
73+
"value": "val1"
74+
},
75+
{
76+
"name": "key2",
77+
"value": "val2"
78+
}
79+
],
80+
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
81+
"version": 1,
82+
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
83+
"bomFormat": "CycloneDX",
84+
"specVersion": "1.5"
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<metadata>
4+
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
5+
<tools>
6+
<tool>
7+
<vendor>CycloneDX</vendor>
8+
<name>cyclonedx-python-lib</name>
9+
<version>TESTING</version>
10+
<externalReferences>
11+
<reference type="build-system">
12+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
13+
</reference>
14+
<reference type="distribution">
15+
<url>https://pypi.org/project/cyclonedx-python-lib/</url>
16+
</reference>
17+
<reference type="documentation">
18+
<url>https://cyclonedx-python-library.readthedocs.io/</url>
19+
</reference>
20+
<reference type="issue-tracker">
21+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
22+
</reference>
23+
<reference type="license">
24+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
25+
</reference>
26+
<reference type="release-notes">
27+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
28+
</reference>
29+
<reference type="vcs">
30+
<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
31+
</reference>
32+
<reference type="website">
33+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/#readme</url>
34+
</reference>
35+
</externalReferences>
36+
</tool>
37+
</tools>
38+
</metadata>
39+
<components>
40+
<component type="library" bom-ref="dummy-b">
41+
<name>dummy</name>
42+
<version>2.3.5</version>
43+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
44+
</component>
45+
<component type="library" bom-ref="dummy-a">
46+
<name>dummy</name>
47+
<version>2.3.5</version>
48+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
49+
</component>
50+
</components>
51+
<dependencies>
52+
<dependency ref="dummy-a"/>
53+
<dependency ref="dummy-b"/>
54+
</dependencies>
55+
<properties>
56+
<property name="key1">val1</property>
57+
<property name="key2">val2</property>
58+
</properties>
59+
</bom>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"components": [
3+
{
4+
"bom-ref": "dummy-b",
5+
"name": "dummy",
6+
"purl": "pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6",
7+
"type": "library",
8+
"version": "2.3.5"
9+
},
10+
{
11+
"bom-ref": "dummy-a",
12+
"name": "dummy",
13+
"purl": "pkg:pypi/pathlib2@2.3.5",
14+
"type": "library",
15+
"version": "2.3.5"
16+
}
17+
],
18+
"dependencies": [
19+
{
20+
"ref": "dummy-a"
21+
},
22+
{
23+
"ref": "dummy-b"
24+
}
25+
],
26+
"metadata": {
27+
"timestamp": "2023-01-07T13:44:32.312678+00:00",
28+
"tools": [
29+
{
30+
"externalReferences": [
31+
{
32+
"type": "build-system",
33+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/actions"
34+
},
35+
{
36+
"type": "distribution",
37+
"url": "https://pypi.org/project/cyclonedx-python-lib/"
38+
},
39+
{
40+
"type": "documentation",
41+
"url": "https://cyclonedx-python-library.readthedocs.io/"
42+
},
43+
{
44+
"type": "issue-tracker",
45+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/issues"
46+
},
47+
{
48+
"type": "license",
49+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE"
50+
},
51+
{
52+
"type": "release-notes",
53+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md"
54+
},
55+
{
56+
"type": "vcs",
57+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib"
58+
},
59+
{
60+
"type": "website",
61+
"url": "https://github.com/CycloneDX/cyclonedx-python-lib/#readme"
62+
}
63+
],
64+
"name": "cyclonedx-python-lib",
65+
"vendor": "CycloneDX",
66+
"version": "TESTING"
67+
}
68+
]
69+
},
70+
"properties": [
71+
{
72+
"name": "key1",
73+
"value": "val1"
74+
},
75+
{
76+
"name": "key2",
77+
"value": "val2"
78+
}
79+
],
80+
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
81+
"version": 1,
82+
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
83+
"bomFormat": "CycloneDX",
84+
"specVersion": "1.6"
85+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" ?>
2+
<bom xmlns="http://cyclonedx.org/schema/bom/1.6" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
3+
<metadata>
4+
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
5+
<tools>
6+
<tool>
7+
<vendor>CycloneDX</vendor>
8+
<name>cyclonedx-python-lib</name>
9+
<version>TESTING</version>
10+
<externalReferences>
11+
<reference type="build-system">
12+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
13+
</reference>
14+
<reference type="distribution">
15+
<url>https://pypi.org/project/cyclonedx-python-lib/</url>
16+
</reference>
17+
<reference type="documentation">
18+
<url>https://cyclonedx-python-library.readthedocs.io/</url>
19+
</reference>
20+
<reference type="issue-tracker">
21+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
22+
</reference>
23+
<reference type="license">
24+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
25+
</reference>
26+
<reference type="release-notes">
27+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
28+
</reference>
29+
<reference type="vcs">
30+
<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
31+
</reference>
32+
<reference type="website">
33+
<url>https://github.com/CycloneDX/cyclonedx-python-lib/#readme</url>
34+
</reference>
35+
</externalReferences>
36+
</tool>
37+
</tools>
38+
</metadata>
39+
<components>
40+
<component type="library" bom-ref="dummy-b">
41+
<name>dummy</name>
42+
<version>2.3.5</version>
43+
<purl>pkg:pypi/pathlib2@2.3.5?vcs_url=git%2Bhttps://github.com/jazzband/pathlib2.git%405a6a88db3cc1d08dbc86fbe15edfb69fb5f5a3d6</purl>
44+
</component>
45+
<component type="library" bom-ref="dummy-a">
46+
<name>dummy</name>
47+
<version>2.3.5</version>
48+
<purl>pkg:pypi/pathlib2@2.3.5</purl>
49+
</component>
50+
</components>
51+
<dependencies>
52+
<dependency ref="dummy-a"/>
53+
<dependency ref="dummy-b"/>
54+
</dependencies>
55+
<properties>
56+
<property name="key1">val1</property>
57+
<property name="key2">val2</property>
58+
</properties>
59+
</bom>

‎tests/_data/snapshots/get_bom_with_licenses-1.1.xml.bin

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@
2222
<name>c-with-name</name>
2323
<version/>
2424
<licenses>
25+
<license>
26+
<name>some additional</name>
27+
<text content-type="text/plain">this is additional license text</text>
28+
</license>
2529
<license>
2630
<name>some commercial license</name>
2731
<text content-type="text/plain">this is a license text</text>

‎tests/_data/snapshots/get_bom_with_licenses-1.2.json.bin

+18
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
{
2929
"bom-ref": "C3",
3030
"licenses": [
31+
{
32+
"license": {
33+
"name": "some additional",
34+
"text": {
35+
"content": "this is additional license text",
36+
"contentType": "text/plain"
37+
}
38+
}
39+
},
3140
{
3241
"license": {
3342
"name": "some commercial license",
@@ -115,6 +124,15 @@
115124
{
116125
"bom-ref": "S3",
117126
"licenses": [
127+
{
128+
"license": {
129+
"name": "some additional",
130+
"text": {
131+
"content": "this is additional license text",
132+
"contentType": "text/plain"
133+
}
134+
}
135+
},
118136
{
119137
"license": {
120138
"name": "some commercial license",

‎tests/_data/snapshots/get_bom_with_licenses-1.2.xml.bin

+8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
<name>c-with-name</name>
4242
<version/>
4343
<licenses>
44+
<license>
45+
<name>some additional</name>
46+
<text content-type="text/plain">this is additional license text</text>
47+
</license>
4448
<license>
4549
<name>some commercial license</name>
4650
<text content-type="text/plain">this is a license text</text>
@@ -67,6 +71,10 @@
6771
<service bom-ref="S3">
6872
<name>s-with-name</name>
6973
<licenses>
74+
<license>
75+
<name>some additional</name>
76+
<text content-type="text/plain">this is additional license text</text>
77+
</license>
7078
<license>
7179
<name>some commercial license</name>
7280
<text content-type="text/plain">this is a license text</text>

‎tests/_data/snapshots/get_bom_with_licenses-1.3.json.bin

+18
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
{
2929
"bom-ref": "C3",
3030
"licenses": [
31+
{
32+
"license": {
33+
"name": "some additional",
34+
"text": {
35+
"content": "this is additional license text",
36+
"contentType": "text/plain"
37+
}
38+
}
39+
},
3140
{
3241
"license": {
3342
"name": "some commercial license",
@@ -122,6 +131,15 @@
122131
{
123132
"bom-ref": "S3",
124133
"licenses": [
134+
{
135+
"license": {
136+
"name": "some additional",
137+
"text": {
138+
"content": "this is additional license text",
139+
"contentType": "text/plain"
140+
}
141+
}
142+
},
125143
{
126144
"license": {
127145
"name": "some commercial license",

‎tests/_data/snapshots/get_bom_with_licenses-1.3.xml.bin

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
<name>c-with-name</name>
4747
<version/>
4848
<licenses>
49+
<license>
50+
<name>some additional</name>
51+
<text content-type="text/plain">this is additional license text</text>
52+
</license>
4953
<license>
5054
<name>some commercial license</name>
5155
<text content-type="text/plain">this is a license text</text>
@@ -72,6 +76,10 @@
7276
<service bom-ref="S3">
7377
<name>s-with-name</name>
7478
<licenses>
79+
<license>
80+
<name>some additional</name>
81+
<text content-type="text/plain">this is additional license text</text>
82+
</license>
7583
<license>
7684
<name>some commercial license</name>
7785
<text content-type="text/plain">this is a license text</text>

‎tests/_data/snapshots/get_bom_with_licenses-1.4.json.bin

+18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@
2626
{
2727
"bom-ref": "C3",
2828
"licenses": [
29+
{
30+
"license": {
31+
"name": "some additional",
32+
"text": {
33+
"content": "this is additional license text",
34+
"contentType": "text/plain"
35+
}
36+
}
37+
},
2938
{
3039
"license": {
3140
"name": "some commercial license",
@@ -152,6 +161,15 @@
152161
{
153162
"bom-ref": "S3",
154163
"licenses": [
164+
{
165+
"license": {
166+
"name": "some additional",
167+
"text": {
168+
"content": "this is additional license text",
169+
"contentType": "text/plain"
170+
}
171+
}
172+
},
155173
{
156174
"license": {
157175
"name": "some commercial license",

‎tests/_data/snapshots/get_bom_with_licenses-1.4.xml.bin

+8
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<component type="library" bom-ref="C3">
6969
<name>c-with-name</name>
7070
<licenses>
71+
<license>
72+
<name>some additional</name>
73+
<text content-type="text/plain">this is additional license text</text>
74+
</license>
7175
<license>
7276
<name>some commercial license</name>
7377
<text content-type="text/plain">this is a license text</text>
@@ -94,6 +98,10 @@
9498
<service bom-ref="S3">
9599
<name>s-with-name</name>
96100
<licenses>
101+
<license>
102+
<name>some additional</name>
103+
<text content-type="text/plain">this is additional license text</text>
104+
</license>
97105
<license>
98106
<name>some commercial license</name>
99107
<text content-type="text/plain">this is a license text</text>

‎tests/_data/snapshots/get_bom_with_licenses-1.5.json.bin

+18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@
2626
{
2727
"bom-ref": "C3",
2828
"licenses": [
29+
{
30+
"license": {
31+
"name": "some additional",
32+
"text": {
33+
"content": "this is additional license text",
34+
"contentType": "text/plain"
35+
}
36+
}
37+
},
2938
{
3039
"license": {
3140
"name": "some commercial license",
@@ -162,6 +171,15 @@
162171
{
163172
"bom-ref": "S3",
164173
"licenses": [
174+
{
175+
"license": {
176+
"name": "some additional",
177+
"text": {
178+
"content": "this is additional license text",
179+
"contentType": "text/plain"
180+
}
181+
}
182+
},
165183
{
166184
"license": {
167185
"name": "some commercial license",

‎tests/_data/snapshots/get_bom_with_licenses-1.5.xml.bin

+8
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<component type="library" bom-ref="C3">
6969
<name>c-with-name</name>
7070
<licenses>
71+
<license>
72+
<name>some additional</name>
73+
<text content-type="text/plain">this is additional license text</text>
74+
</license>
7175
<license>
7276
<name>some commercial license</name>
7377
<text content-type="text/plain">this is a license text</text>
@@ -94,6 +98,10 @@
9498
<service bom-ref="S3">
9599
<name>s-with-name</name>
96100
<licenses>
101+
<license>
102+
<name>some additional</name>
103+
<text content-type="text/plain">this is additional license text</text>
104+
</license>
97105
<license>
98106
<name>some commercial license</name>
99107
<text content-type="text/plain">this is a license text</text>

‎tests/_data/snapshots/get_bom_with_licenses-1.6.json.bin

+18
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
{
2929
"bom-ref": "C3",
3030
"licenses": [
31+
{
32+
"license": {
33+
"name": "some additional",
34+
"text": {
35+
"content": "this is additional license text",
36+
"contentType": "text/plain"
37+
}
38+
}
39+
},
3140
{
3241
"license": {
3342
"name": "some commercial license",
@@ -166,6 +175,15 @@
166175
{
167176
"bom-ref": "S3",
168177
"licenses": [
178+
{
179+
"license": {
180+
"name": "some additional",
181+
"text": {
182+
"content": "this is additional license text",
183+
"contentType": "text/plain"
184+
}
185+
}
186+
},
169187
{
170188
"license": {
171189
"name": "some commercial license",

‎tests/_data/snapshots/get_bom_with_licenses-1.6.xml.bin

+8
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@
6868
<component type="library" bom-ref="C3">
6969
<name>c-with-name</name>
7070
<licenses>
71+
<license>
72+
<name>some additional</name>
73+
<text content-type="text/plain">this is additional license text</text>
74+
</license>
7175
<license>
7276
<name>some commercial license</name>
7377
<text content-type="text/plain">this is a license text</text>
@@ -94,6 +98,10 @@
9498
<service bom-ref="S3">
9599
<name>s-with-name</name>
96100
<licenses>
101+
<license>
102+
<name>some additional</name>
103+
<text content-type="text/plain">this is additional license text</text>
104+
</license>
97105
<license>
98106
<name>some commercial license</name>
99107
<text content-type="text/plain">this is a license text</text>

0 commit comments

Comments
 (0)
Please sign in to comment.