Skip to content

Commit

Permalink
BomRef.value default None (#505)
Browse files Browse the repository at this point in the history
---------

Signed-off-by: Jan Kowalleck <[email protected]>
  • Loading branch information
jkowalleck authored Dec 4, 2023
1 parent ef76c49 commit b9193a2
Show file tree
Hide file tree
Showing 20 changed files with 43 additions and 68 deletions.
19 changes: 9 additions & 10 deletions cyclonedx/model/bom_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# Copyright (c) OWASP Foundation. All Rights Reserved.

from typing import Any, Optional
from uuid import uuid4


class BomRef:
Expand All @@ -30,31 +29,31 @@ class BomRef:
"""

def __init__(self, value: Optional[str] = None) -> None:
self.value = value or str(uuid4())
self.value = value

@property
def value(self) -> str:
def value(self) -> Optional[str]:
return self._value

@value.setter
def value(self, value: str) -> None:
self._value = value
def value(self, value: Optional[str]) -> None:
self._value = value or None

def __eq__(self, other: object) -> bool:
if isinstance(other, BomRef):
return other.value == self.value
return str(other) == str(self)
return False

def __lt__(self, other: Any) -> bool:
if isinstance(other, BomRef):
return self.value < other.value
return str(self) < str(other)
return NotImplemented

def __hash__(self) -> int:
return hash(self.value)
return hash(str(self))

def __repr__(self) -> str:
return f'<BomRef {self.value}>'
return f'<BomRef {self._value!r}>'

def __str__(self) -> str:
return self.value
return self.value or ''
6 changes: 3 additions & 3 deletions cyclonedx/output/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,13 @@ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
self.reset()

def discriminate(self) -> None:
known_values = set()
known_values = []
for bomref, _ in self._bomrefs:
value = bomref.value
if value in known_values:
if value is None or value in known_values:
value = self._make_unique()
bomref.value = value
known_values.add(value)
known_values.append(value)

def reset(self) -> None:
for bomref, original_value in self._bomrefs:
Expand Down
2 changes: 1 addition & 1 deletion cyclonedx/serialization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
class BomRefHelper(BaseHelper):

@classmethod
def serialize(cls, o: Any) -> str:
def serialize(cls, o: Any) -> Optional[str]:
if isinstance(o, BomRef):
return o.value
raise SerializationOfUnexpectedValueException(
Expand Down
4 changes: 3 additions & 1 deletion tests/_data/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,9 @@ def get_bom_with_nested_services() -> Bom:
bom_ref='my-specific-bom-ref-for-my-second-service',
services=[
Service(
name='yet-another-nested-service', provider=get_org_entity_1(), group='what-group', version='6.5.4'
name='yet-another-nested-service',
bom_ref='yet-another-nested-service',
provider=get_org_entity_1(), group='what-group', version='6.5.4'
),
Service(
name='another-nested-service',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
"name": "my-second-service",
"services": [
{
"bom-ref": "00000000-0000-4000-8000-000000000004",
"bom-ref": "yet-another-nested-service",
"group": "what-group",
"name": "yet-another-nested-service",
"provider": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
<service bom-ref="my-specific-bom-ref-for-my-second-service">
<name>my-second-service</name>
<services>
<service bom-ref="00000000-0000-4000-8000-000000000004">
<service bom-ref="yet-another-nested-service">
<provider>
<name>CycloneDX</name>
<url>https://cyclonedx.org</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
"name": "my-second-service",
"services": [
{
"bom-ref": "00000000-0000-4000-8000-000000000003",
"bom-ref": "yet-another-nested-service",
"group": "what-group",
"name": "yet-another-nested-service",
"provider": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<service bom-ref="my-specific-bom-ref-for-my-second-service">
<name>my-second-service</name>
<services>
<service bom-ref="00000000-0000-4000-8000-000000000003">
<service bom-ref="yet-another-nested-service">
<provider>
<name>CycloneDX</name>
<url>https://cyclonedx.org</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
"name": "my-second-service",
"services": [
{
"bom-ref": "00000000-0000-4000-8000-000000000002",
"bom-ref": "yet-another-nested-service",
"group": "what-group",
"name": "yet-another-nested-service",
"provider": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
<service bom-ref="my-specific-bom-ref-for-my-second-service">
<name>my-second-service</name>
<services>
<service bom-ref="00000000-0000-4000-8000-000000000002">
<service bom-ref="yet-another-nested-service">
<provider>
<name>CycloneDX</name>
<url>https://cyclonedx.org</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@
"name": "my-second-service",
"services": [
{
"bom-ref": "00000000-0000-4000-8000-000000000001",
"bom-ref": "yet-another-nested-service",
"group": "what-group",
"name": "yet-another-nested-service",
"provider": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
<service bom-ref="my-specific-bom-ref-for-my-second-service">
<name>my-second-service</name>
<services>
<service bom-ref="00000000-0000-4000-8000-000000000001">
<service bom-ref="yet-another-nested-service">
<provider>
<name>CycloneDX</name>
<url>https://cyclonedx.org</url>
Expand Down
3 changes: 1 addition & 2 deletions tests/test_deserialize_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from cyclonedx.model.bom import Bom
from cyclonedx.model.license import DisjunctiveLicense, LicenseExpression, LicenseRepository
from cyclonedx.schema import OutputFormat, SchemaVersion
from tests import OWN_DATA_DIRECTORY, DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
from tests import OWN_DATA_DIRECTORY, DeepCompareMixin, SnapshotMixin, mksname
from tests._data.models import all_get_bom_funct_valid_immut, all_get_bom_funct_with_incomplete_deps


Expand All @@ -36,7 +36,6 @@ class TestDeserializeJson(TestCase, SnapshotMixin, DeepCompareMixin):

@named_data(*all_get_bom_funct_valid_immut)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
# only latest schema will have all data populated in serialized form
snapshot_name = mksname(get_bom, SchemaVersion.V1_5, OutputFormat.JSON)
Expand Down
3 changes: 1 addition & 2 deletions tests/test_deserialize_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from cyclonedx.model.bom import Bom
from cyclonedx.schema import OutputFormat, SchemaVersion
from tests import DeepCompareMixin, SnapshotMixin, mksname, uuid_generator
from tests import DeepCompareMixin, SnapshotMixin, mksname
from tests._data.models import all_get_bom_funct_valid_immut, all_get_bom_funct_with_incomplete_deps


Expand All @@ -33,7 +33,6 @@ class TestDeserializeXml(TestCase, SnapshotMixin, DeepCompareMixin):

@named_data(*all_get_bom_funct_valid_immut)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_prepared(self, get_bom: Callable[[], Bom], *_: Any, **__: Any) -> None:
# only latest schema will have all data populated in serialized form
snapshot_name = mksname(get_bom, SchemaVersion.V1_5, OutputFormat.XML)
Expand Down
16 changes: 1 addition & 15 deletions tests/test_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from cyclonedx.schema import OutputFormat, SchemaVersion
from cyclonedx.schema._res import BOM_JSON as SCHEMA_JSON, BOM_XML as SCHEMA_XML
from cyclonedx.validation import make_schemabased_validator
from tests import SnapshotMixin, uuid_generator
from tests import SnapshotMixin
from tests._data.models import _make_bom

# region SUT: all the enums
Expand Down Expand Up @@ -164,7 +164,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(services=[Service(name='dummy', bom_ref='dummy', data=(
DataClassification(flow=df, classification=df.name)
Expand All @@ -185,7 +184,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=[Component(name='dummy', type=ComponentType.LIBRARY, bom_ref='dummy', licenses=(
DisjunctiveLicense(name=f'att.encoding: {encoding.name}', text=AttachedText(
Expand All @@ -207,7 +205,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=[
Component(name='dummy', type=ComponentType.LIBRARY, bom_ref='dummy', external_references=(
Expand All @@ -230,7 +227,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=[Component(name='dummy', type=ComponentType.LIBRARY, bom_ref='dummy', hashes=(
HashType(alg=alg, content='ae2b1fca515949e5d54fb22b8ed95575')
Expand All @@ -251,7 +247,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=(
Component(bom_ref=f'scoped-{scope.name}', name=f'dummy-{scope.name}',
Expand Down Expand Up @@ -291,7 +286,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
if OutputFormat.XML is of:
schema_cases = set(dp_cases_from_xml_schema(SCHEMA_XML[sv], _DP_ComponentType.XML_SCHEMA_XPATH))
Expand Down Expand Up @@ -329,7 +323,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=[
Component(name='dummy', type=ComponentType.LIBRARY, bom_ref='dummy', pedigree=Pedigree(patches=(
Expand All @@ -352,7 +345,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=[Vulnerability(
bom_ref='dummy', id='dummy', affects=[BomTarget(ref='urn:cdx:bom23/1#comp42', versions=(
Expand All @@ -375,7 +367,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=(
Vulnerability(
Expand All @@ -399,7 +390,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=[Vulnerability(
bom_ref='dummy', id='dummy',
Expand All @@ -422,7 +412,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=(
Vulnerability(
Expand All @@ -445,7 +434,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(components=[
Component(name='dummy', type=ComponentType.LIBRARY, bom_ref='dummy', pedigree=Pedigree(patches=[
Expand All @@ -470,7 +458,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=[Vulnerability(bom_ref='dummy', id='dummy', ratings=(
VulnerabilityRating(method=vss)
Expand All @@ -491,7 +478,6 @@ def test_knows_value(self, value: str) -> None:

@named_data(*NAMED_OF_SV)
@patch('cyclonedx.model.ThisTool._version', 'TESTING')
@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(0, version=4))
def test_cases_render_valid(self, of: OutputFormat, sv: SchemaVersion, *_: Any, **__: Any) -> None:
bom = _make_bom(vulnerabilities=[Vulnerability(bom_ref='dummy', id='dummy', ratings=(
VulnerabilityRating(severity=vs)
Expand Down
10 changes: 4 additions & 6 deletions tests/test_model_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
# Copyright (c) OWASP Foundation. All Rights Reserved.

import datetime
from typing import Any, List
from typing import List
from unittest import TestCase
from unittest.mock import patch

from cyclonedx.exception.model import NoPropertiesProvidedException
from cyclonedx.model import (
Expand All @@ -42,7 +41,7 @@
Pedigree,
)
from cyclonedx.model.issue import IssueClassification, IssueType
from tests import reorder, uuid_generator
from tests import reorder
from tests._data.models import (
get_component_setuptools_simple,
get_component_setuptools_simple_no_version,
Expand Down Expand Up @@ -104,13 +103,12 @@ def test_sort(self) -> None:

class TestModelComponent(TestCase):

@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
def test_empty_basic_component(self, *_: Any, **__: Any) -> None:
def test_empty_basic_component(self) -> None:
c = Component(name='test-component')
self.assertEqual(c.name, 'test-component')
self.assertEqual(c.type, ComponentType.LIBRARY)
self.assertIsNone(c.mime_type)
self.assertEqual(str(c.bom_ref), '00000000-0000-4000-8000-000000000001')
self.assertIsNone(c.bom_ref.value)
self.assertIsNone(c.supplier)
self.assertIsNone(c.author)
self.assertIsNone(c.publisher)
Expand Down
17 changes: 7 additions & 10 deletions tests/test_model_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,20 @@
#
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OWASP Foundation. All Rights Reserved.
from typing import Any


from unittest import TestCase
from unittest.mock import Mock, patch

from cyclonedx.model.service import Service
from tests import reorder, uuid_generator
from tests import reorder


class TestModelService(TestCase):

@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
def test_minimal_service(self, mock_uuid: Mock) -> None:
def test_minimal_service(self) -> None:
s = Service(name='my-test-service')
mock_uuid.assert_called()
self.assertEqual(s.name, 'my-test-service')
self.assertEqual(str(s.bom_ref), '00000000-0000-4000-8000-000000000001')
self.assertIsNone(s.bom_ref.value)
self.assertIsNone(s.provider)
self.assertIsNone(s.group)
self.assertIsNone(s.version)
Expand All @@ -44,15 +42,14 @@ def test_minimal_service(self, mock_uuid: Mock) -> None:
self.assertFalse(s.release_notes)
self.assertFalse(s.properties)

@patch('cyclonedx.model.bom_ref.uuid4', side_effect=uuid_generator(version=4))
def test_service_with_services(self, *_: Any, **__: Any) -> None:
def test_service_with_services(self) -> None:
parent_service = Service(name='parent-service')
parent_service.services = [
Service(name='child-service-1'),
Service(name='child-service-2'),
]
self.assertEqual(parent_service.name, 'parent-service')
self.assertEqual(str(parent_service.bom_ref), '00000000-0000-4000-8000-000000000001')
self.assertIsNone(parent_service.bom_ref.value)
self.assertIsNone(parent_service.provider)
self.assertIsNone(parent_service.group)
self.assertIsNone(parent_service.version)
Expand Down
Loading

0 comments on commit b9193a2

Please sign in to comment.