CycloneDX / cyclonedx-python-lib

Python implementation of OWASP CycloneDX
https://cyclonedx.org/
Apache License 2.0
61 stars 34 forks source link

Components not properly in dep tree nor BOM #540

Open jkugler opened 5 months ago

jkugler commented 5 months ago

This is version 6.4.0

Components with unique bom_refs, but the same name, will generate an error when trying to render a dependency tree. Given this script:

#!/usr/bin/env python3

from cyclonedx.model.bom import Bom
from cyclonedx.model.component import Component, ComponentType
from cyclonedx.output.json import JsonV1Dot5

bom = Bom()
bom.metadata.component = root_component = Component(
    name='myApp',
    type=ComponentType.APPLICATION,
    bom_ref="myApp"
)

component1 = Component(
    type=ComponentType.LIBRARY,
    name='some-component',
    bom_ref="some-component"
)
bom.components.add(component1)
bom.register_dependency(root_component, [component1])

component2 = Component(
    type=ComponentType.LIBRARY,
    name='some-library',
    bom_ref="some-library1"
)
bom.components.add(component2)
bom.register_dependency(component1, [component2])

component3 = Component(
    type=ComponentType.LIBRARY,
    name='some-library',
    bom_ref="some-library2"
)
bom.components.add(component3)
bom.register_dependency(component1, [component3])

print(JsonV1Dot5(bom).output_as_string(indent=2))

I get this error when I run it:

Traceback (most recent call last):
  File "/Users/tek30584/programming/cdx_lib_bugs/./duplicate_name_bug.py", line 38, in <module>
    print(JsonV1Dot5(bom).output_as_string(indent=2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/tek30584/programming/cdx_lib_bugs/.venv/lib/python3.11/site-packages/cyclonedx/output/json.py", line 82, in output_as_string
    self.generate()
  File "/Users/tek30584/programming/cdx_lib_bugs/.venv/lib/python3.11/site-packages/cyclonedx/output/json.py", line 70, in generate
    bom.validate()
  File "/Users/tek30584/programming/cdx_lib_bugs/.venv/lib/python3.11/site-packages/cyclonedx/model/bom.py", line 600, in validate
    raise UnknownComponentDependencyException(
cyclonedx.exception.model.UnknownComponentDependencyException: One or more Components have Dependency references to Components/Services that are not known in this BOM. They are: {<BomRef 'some-library2'>}
jkowalleck commented 5 months ago

will add test cases to older versions, for regression and showcasing-purposes, and then forward-port those and add fixes.

I am planning to have all affected major versions fixed.

++++

the issue does not rely on same name of components, but the fact that both component have an equal (not identical) bom_ref - with a None value. Need to showcase this in tests.

jkugler commented 5 months ago

the issue does not rely on same name of components, but the fact that both component have an equal (not identical) bom_ref - with a None value.

I'm not understanding this. All the components in the example script have unique bom_ref values.

jkowalleck commented 5 months ago

did some research and found, that component3 was not added to the BOM. This is an expected behavior, as the properties relevant for equality of component2 are the same as of component3.

Per CycloneDX Specification, the minimal set of equality-properties of Components are: type, name` Bom-ref is not an identity-property nor an equality property. Bom-ref's purpose is linking elements, it does not have any meaning besides this purpose.

As all is ass expected, I'll close this issue. This Issue is not locked, so further discussion may take place here, instead of opening another issue.

jkugler commented 5 months ago

Ah, that is interesting. I would expect a "guaranteed unique" property would be used for testing "unique-ness." But I understand. I guess I'm drawing too much on my database experience. :) Thanks for digging in to this and doing the research!

eugenhoffmann commented 3 months ago

I encountered a similar issue with a different component tree. One of the features of CycloneDX is the ability to declare nested components, which is helpful when merging multiple BOM files into a single one. In some cases, these BOM files may contain identical components. However, depending on the resulting component tree, I observed inconsistent behavior - either receiving an exception or no exception.

models

In my opinion, the component equality validation should be performed within the context of a parent component, rather than within the context of a root component. Am I misunderstanding something?

jkowalleck commented 3 months ago

@madpah FYI

jkowalleck commented 3 months ago

this issue should have been closed via https://github.com/CycloneDX/cyclonedx-python-lib/pull/587 or so

eugenhoffmann commented 2 months ago

From my perspective, it seems that this issue does not specifically address the same problem.

To reproduce the second case mentioned here, you can use the provided example BOM file UnkCompDepEx.json.

Here is a code example that reads the BOM file and writes it to a string:

import json
from cyclonedx.model.bom import Bom
from cyclonedx.output.json import JsonV1Dot5

with open("UnkCompDepEx.json") as input_json:
    deserialized_bom = Bom.from_json(data=json.loads(input_json.read()))

print(JsonV1Dot5(deserialized_bom).output_as_string(indent=2))

When running this code, I get the 'UnknownComponentDependencyException' error message:

File "F:\Git\rsb-sbom\venv\lib\site-packages\cyclonedx\output\json.py", line 83, in output_as_string
  self.generate()
File "F:\Git\rsb-sbom\venv\lib\site-packages\cyclonedx\output\json.py", line 71, in generate
  bom.validate()
File "F:\Git\rsb-sbom\venv\lib\site-packages\cyclonedx\model\bom.py", line 658, in validate
  raise UnknownComponentDependencyException(
cyclonedx.exception.model.UnknownComponentDependencyException: One or more Components have Dependency references to Components/Services that are not known in this BOM. They are: {<BomRef 'y2' id=2229836430400>, <BomRef 'x2' id=2229836429824>}

Feel free to reach out if you need further assistance