Skip to content

Commit 54cf48f

Browse files
committed
feat: add bom_ref to OrganizationalEntity
Signed-off-by: yowgf <[email protected]>
1 parent 694cfd2 commit 54cf48f

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

cyclonedx/model/contact.py

+17
Original file line numberDiff line numberDiff line change
@@ -288,16 +288,33 @@ class OrganizationalEntity:
288288

289289
def __init__(
290290
self, *,
291+
bom_ref: Optional[Union[str, BomRef]] = None,
291292
name: Optional[str] = None,
292293
urls: Optional[Iterable[XsUri]] = None,
293294
contacts: Optional[Iterable[OrganizationalContact]] = None,
294295
address: Optional[PostalAddress] = None,
295296
) -> None:
297+
self._bom_ref = bom_ref
296298
self.name = name
297299
self.address = address
298300
self.urls = urls or [] # type:ignore[assignment]
299301
self.contacts = contacts or [] # type:ignore[assignment]
300302

303+
@property
304+
@serializable.json_name('bom-ref')
305+
@serializable.type_mapping(BomRef)
306+
@serializable.xml_attribute()
307+
@serializable.xml_name('bom-ref')
308+
def bom_ref(self) -> Optional[BomRef]:
309+
"""
310+
An optional identifier which can be used to reference the component elsewhere in the BOM. Every bom-ref MUST be
311+
unique within the BOM.
312+
313+
Returns:
314+
`BomRef`
315+
"""
316+
return self._bom_ref
317+
301318
@property
302319
@serializable.xml_sequence(10)
303320
@serializable.xml_string(serializable.XmlStringSerializationType.NORMALIZED_STRING)

tests/test_model.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from uuid import UUID
2323

2424
from ddt import ddt, named_data
25+
from sortedcontainers import SortedSet
2526

2627
from cyclonedx._internal.compare import ComparableTuple
2728
from cyclonedx.exception.model import InvalidLocaleTypeException, InvalidUriException, UnknownHashTypeException
@@ -39,7 +40,7 @@
3940
XsUri,
4041
)
4142
from cyclonedx.model.bom_ref import BomRef
42-
from cyclonedx.model.contact import OrganizationalContact
43+
from cyclonedx.model.contact import OrganizationalContact, OrganizationalEntity, PostalAddress
4344
from cyclonedx.model.issue import IssueClassification, IssueType, IssueTypeSource
4445
from tests import reorder
4546

@@ -463,6 +464,53 @@ def test_sort(self) -> None:
463464
self.assertListEqual(sorted_contacts, expected_contacts)
464465

465466

467+
class TestModelOrganizationalEntity(TestCase):
468+
def test_init_with_bom_ref(self) -> None:
469+
contacts = [
470+
OrganizationalContact(name='a', email='a', phone='a'),
471+
OrganizationalContact(name='b', email='a', phone='a'),
472+
]
473+
OrganizationalEntity(
474+
bom_ref=BomRef('dummy-bom-ref'),
475+
name='dummy-organizational-entity',
476+
contacts=contacts,
477+
address=PostalAddress(
478+
country='dummy-country',
479+
region='dummy-region',
480+
),
481+
)
482+
483+
def test_init_without_bom_ref(self) -> None:
484+
contacts = [
485+
OrganizationalContact(name='a', email='a', phone='a'),
486+
OrganizationalContact(name='b', email='a', phone='a'),
487+
]
488+
OrganizationalEntity(
489+
name='dummy-organizational-entity',
490+
contacts=contacts,
491+
address=PostalAddress(
492+
country='dummy-country',
493+
region='dummy-region',
494+
),
495+
)
496+
497+
def test_init_from_json(self) -> None:
498+
bom_ref = 'Example'
499+
name = 'Example'
500+
urls = [
501+
'https://example.com/'
502+
]
503+
specification = {
504+
'name': name,
505+
'url': urls,
506+
'bom-ref': bom_ref
507+
}
508+
entity = OrganizationalEntity.from_json(specification)
509+
assert entity.name == name
510+
assert entity.urls == SortedSet([XsUri(url) for url in urls])
511+
assert entity.bom_ref == BomRef(bom_ref)
512+
513+
466514
class TestModelXsUri(TestCase):
467515

468516
# URI samples taken from http://www.datypic.com/sc/xsd/t-xsd_anyURI.html

0 commit comments

Comments
 (0)