Skip to content

Commit

Permalink
Added XML serializations decorators, enum test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
wahl-sec committed Aug 4, 2024
1 parent 072f4f5 commit 2c0d5ba
Show file tree
Hide file tree
Showing 16 changed files with 561 additions and 132 deletions.
37 changes: 23 additions & 14 deletions cyclonedx/model/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ class ComponentIdentityEvidenceField(str, Enum):
VERSION = 'version'
PURL = 'purl'
CPE = 'cpe'
OMNIBOR_ID = 'omniborId'
SWHID = 'swhid'
OMNIBOR_ID = 'omniborId' # Only supported in >= 1.6
SWHID = 'swhid' # Only supported in >= 1.6
SWID = 'swid'
HASH = 'hash'

Expand Down Expand Up @@ -307,9 +307,11 @@ def __normalize(
cs: ComponentIdentityEvidenceMethodTechnique,
view: Type[serializable.ViewType]
) -> Optional[str]:
return cs.value \
if cs in cls.__CASES.get(view, ()) \
else None
return (
cs
if cs in cls.__CASES.get(view, ())
else ComponentIdentityEvidenceMethodTechnique.OTHER
).value

@classmethod
def json_normalize(cls, o: Any, *,
Expand Down Expand Up @@ -354,6 +356,7 @@ def __init__(

@property
@serializable.type_mapping(_ComponentIdentityEvidenceMethodTechniqueSerializationHelper)
@serializable.xml_sequence(1)
def technique(self) -> Optional[ComponentIdentityEvidenceMethodTechnique]:
"""
The evidence technique used by the method of the component which the evidence describes.
Expand All @@ -368,6 +371,7 @@ def technique(self, technique: Optional[ComponentIdentityEvidenceMethodTechnique
self._technique = technique

@property
@serializable.xml_sequence(2)
def confidence(self) -> float:
"""
The overall confidence of the evidence from 0 - 1, where 1 is 100% confidence.
Expand All @@ -389,6 +393,7 @@ def confidence(self, confidence: float) -> None:
self._confidence = confidence

@property
@serializable.xml_sequence(3)
def value(self) -> Optional[str]:
"""
The value or contents of the evidence.
Expand Down Expand Up @@ -452,6 +457,7 @@ def __init__(

@property
@serializable.type_mapping(_ComponentIdentityEvidenceFieldSerializationHelper)
@serializable.xml_sequence(1)
def field(self) -> Optional[ComponentIdentityEvidenceField]:
"""
The identity field of the component which the evidence describes.
Expand All @@ -466,6 +472,7 @@ def field(self, field: Optional[ComponentIdentityEvidenceField]) -> None:
self._field = field

@property
@serializable.xml_sequence(2)
def confidence(self) -> Optional[float]:
"""
The overall confidence of the evidence from 0 - 1, where 1 is 100% confidence.
Expand All @@ -486,6 +493,7 @@ def confidence(self, confidence: Optional[float]) -> None:

@property
@serializable.type_mapping(ComponentIdentityEvidenceMethod)
@serializable.xml_sequence(3)
def methods(self) -> 'SortedSet[ComponentIdentityEvidenceMethod]':
"""
Optional list of methods used to extract and/or analyze the evidence.
Expand All @@ -500,6 +508,7 @@ def methods(self, methods: Iterable[ComponentIdentityEvidenceMethod]) -> None:
self._methods = SortedSet(methods)

@property
@serializable.xml_sequence(4)
def tools(self) -> 'SortedSet[str]':
"""
Optional list of tools used to extract and/or analyze the evidence.
Expand Down Expand Up @@ -547,36 +556,36 @@ class ComponentEvidence:

def __init__(
self, *,
identity: Optional[ComponentIdentityEvidence] = None,
identity: Optional[Iterable[ComponentIdentityEvidence]] = None,
licenses: Optional[Iterable[License]] = None,
copyright: Optional[Iterable[Copyright]] = None,
) -> None:
if not licenses and not copyright and not identity:
raise NoPropertiesProvidedException(
'At least one of `licenses` or `copyright` must be supplied for a `ComponentEvidence`.'
'At least one of `licenses`, `copyright` or `identity` must be supplied for a `ComponentEvidence`.'
)

self.identity = identity
self.identity = identity or [] # type:ignore[assignment]
self.licenses = licenses or [] # type:ignore[assignment]
self.copyright = copyright or [] # type:ignore[assignment]

@property
@serializable.view(SchemaVersion1Dot5)
@serializable.view(SchemaVersion1Dot6)
@serializable.xml_array(serializable.XmlArraySerializationType.NESTED, 'identity')
@serializable.xml_sequence(1)
def identity(self) -> Optional[ComponentIdentityEvidence]:
def identity(self) -> 'SortedSet[ComponentIdentityEvidence]':
"""
Optional list of evidence that substantiates the identity of a component.
Returns:
`ComponentIdentityEvidence` or `None`
Set of `ComponentIdentityEvidence`
"""

return self._identity

@identity.setter
def identity(self, identity: Optional[ComponentIdentityEvidence]) -> None:
self._identity = identity
def identity(self, identity: Iterable[ComponentIdentityEvidence]) -> None:
self._identity = SortedSet(identity)

# @property
# ...
Expand Down Expand Up @@ -647,7 +656,7 @@ def __lt__(self, other: Any) -> bool:
return NotImplemented

def __hash__(self) -> int:
return hash((self.identity, tuple(self.licenses), tuple(self.copyright)))
return hash((tuple(self.identity), tuple(self.licenses), tuple(self.copyright)))

def __repr__(self) -> str:
return f'<ComponentEvidence id={id(self)}>'
Expand Down
13 changes: 0 additions & 13 deletions tests/_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@
Commit,
Component,
ComponentEvidence,
ComponentIdentityEvidence,
ComponentIdentityEvidenceField,
ComponentIdentityEvidenceMethod,
ComponentIdentityEvidenceMethodTechnique,
ComponentScope,
ComponentType,
Diff,
Expand Down Expand Up @@ -934,15 +930,6 @@ def get_swid_2() -> Swid:
)


def get_evidence_identity() -> ComponentIdentityEvidence:
return ComponentIdentityEvidence(
field=ComponentIdentityEvidenceField.NAME, confidence=0.5, methods=[
ComponentIdentityEvidenceMethod(technique=ComponentIdentityEvidenceMethodTechnique.FILENAME, confidence=0.5)
],
tools=['cyclonedx-python-lib']
)


def get_vulnerability_source_nvd() -> VulnerabilitySource:
return VulnerabilitySource(name='NVD', url=XsUri('https://nvd.nist.gov/vuln/detail/CVE-2018-7489'))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.0" version="1">
<components/>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.1" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
<components/>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"metadata": {
"timestamp": "2023-01-07T13:44:32.312678+00:00",
"tools": [
{
"name": "cyclonedx-python-lib",
"vendor": "CycloneDX",
"version": "TESTING"
}
]
},
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
"version": 1,
"$schema": "http://cyclonedx.org/schema/bom-1.2b.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.2"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
<metadata>
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
<tools>
<tool>
<vendor>CycloneDX</vendor>
<name>cyclonedx-python-lib</name>
<version>TESTING</version>
</tool>
</tools>
</metadata>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"metadata": {
"timestamp": "2023-01-07T13:44:32.312678+00:00",
"tools": [
{
"name": "cyclonedx-python-lib",
"vendor": "CycloneDX",
"version": "TESTING"
}
]
},
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
"version": 1,
"$schema": "http://cyclonedx.org/schema/bom-1.3a.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
<metadata>
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
<tools>
<tool>
<vendor>CycloneDX</vendor>
<name>cyclonedx-python-lib</name>
<version>TESTING</version>
</tool>
</tools>
</metadata>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"metadata": {
"timestamp": "2023-01-07T13:44:32.312678+00:00",
"tools": [
{
"name": "cyclonedx-python-lib",
"vendor": "CycloneDX",
"version": "TESTING"
}
]
},
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
"version": 1,
"$schema": "http://cyclonedx.org/schema/bom-1.4.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.4"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
<metadata>
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
<tools>
<tool>
<vendor>CycloneDX</vendor>
<name>cyclonedx-python-lib</name>
<version>TESTING</version>
</tool>
</tools>
</metadata>
</bom>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"components": [
{
"bom-ref": "dummy",
"name": "dummy",
"type": "application",
"evidence": {
"identity": {
"field": "group"
}
}
}
],
"metadata": {
"timestamp": "2023-01-07T13:44:32.312678+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-python-library.readthedocs.io/"
},
{
"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://github.com/CycloneDX/cyclonedx-python-lib/#readme"
}
],
"name": "cyclonedx-python-lib",
"vendor": "CycloneDX",
"version": "TESTING"
}
]
},
"properties": [
{
"name": "key1",
"value": "val1"
},
{
"name": "key2",
"value": "val2"
}
],
"serialNumber": "urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac",
"version": 1,
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" ?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.5" serialNumber="urn:uuid:1441d33a-e0fc-45b5-af3b-61ee52a88bac" version="1">
<metadata>
<timestamp>2023-01-07T13:44:32.312678+00:00</timestamp>
<tools>
<tool>
<vendor>CycloneDX</vendor>
<name>cyclonedx-python-lib</name>
<version>TESTING</version>
<externalReferences>
<reference type="build-system">
<url>https://github.com/CycloneDX/cyclonedx-python-lib/actions</url>
</reference>
<reference type="distribution">
<url>https://pypi.org/project/cyclonedx-python-lib/</url>
</reference>
<reference type="documentation">
<url>https://cyclonedx-python-library.readthedocs.io/</url>
</reference>
<reference type="issue-tracker">
<url>https://github.com/CycloneDX/cyclonedx-python-lib/issues</url>
</reference>
<reference type="license">
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/LICENSE</url>
</reference>
<reference type="release-notes">
<url>https://github.com/CycloneDX/cyclonedx-python-lib/blob/main/CHANGELOG.md</url>
</reference>
<reference type="vcs">
<url>https://github.com/CycloneDX/cyclonedx-python-lib</url>
</reference>
<reference type="website">
<url>https://github.com/CycloneDX/cyclonedx-python-lib/#readme</url>
</reference>
</externalReferences>
</tool>
</tools>
</metadata>
<components>
<component type="application" bom-ref="scoped">
<name>dummy</name>
<evidence>
<identity>
<field>group</field>
</identity>
</evidence>
</component>
</components>
<properties>
<property name="key1">val1</property>
<property name="key2">val2</property>
</properties>
</bom>
Loading

0 comments on commit 2c0d5ba

Please sign in to comment.