Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions cdxev/auxiliary/sbomFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,21 +188,34 @@ def get_bom_refs_from_dependencies(dependencies: Sequence[dict]) -> list[str]:

def get_ref_from_components(list_of_components: Sequence[dict]) -> list[str]:
"""
Function that returns a list of bom-refs from a list of components
Function that returns a list of bom-refs from a list of components.
This also includes nested components.

Input:
list_of_components: list with dicts of components

Output:
list_of_bom_refs: List of bom-refs from the components in the submitted list
"""
list_of_all_components = extract_components(list_of_components)
list_of_bom_refs = []
for component in list_of_components:
for component in list_of_all_components:
bom_ref = component.get("bom-ref", "")
list_of_bom_refs.append(bom_ref)
return list_of_bom_refs


def extract_components(list_of_components: Sequence[dict]) -> Sequence[dict]:
extracted_components = []
for component in list_of_components:
if component.get("components", []) == []:
extracted_components.append(component)
else:
extracted_components.append(component)
extracted_components += extract_components(component.get("components", []))
return extracted_components


def compare_vulnerabilities(
first_vulnerability: dict, second_vulnerability: dict
) -> bool:
Expand Down
11 changes: 6 additions & 5 deletions cdxev/build_public_bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

from jsonschema import Draft7Validator, FormatChecker

from cdxev.auxiliary.sbomFunctions import get_ref_from_components


def remove_internal_information_from_properties(component: dict) -> None:
"""
Expand Down Expand Up @@ -154,14 +152,17 @@ def build_public_bom(sbom: dict, path_to_schema: t.Union[Path, None]) -> dict:
) = remove_component_tagged_internal(components, path_to_schema)
for bom_ref in list_of_removed_components:
dependencies = merge_dependency_for_removed_component(bom_ref, dependencies)
new_compositions = get_ref_from_components(cleared_components)
remove_internal_information_from_properties(
sbom.get("metadata", {}).get("component", {})
)
sbom["components"] = cleared_components
sbom["dependencies"] = dependencies
compositions = [{"aggregate": "incomplete", "assemblies": new_compositions}]
sbom["compositions"] = compositions
for composition in sbom.get("compositions", []):
new_assemblies = composition.get("assemblies").copy()
for bom_ref in composition.get("assemblies"):
if bom_ref in list_of_removed_components:
new_assemblies.remove(bom_ref)
composition["assemblies"] = new_assemblies
return sbom


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,27 @@
"group": "org.acme",
"name": "web-framework",
"version": "1.0.0",
"purl": "pkg:maven/org.acme/web-framework@1.0.0"
"purl": "pkg:maven/org.acme/web-framework@1.0.0",
"components": [
{
"type": "library",
"bom-ref": "sub_comp1",
"supplier": {
"name": "Acme, Inc."
},
"licenses": [
{
"license": {
"id": "Apache-1.0"
}
}
],
"group": "org.acme",
"name": "sub_web-framework",
"version": "1.0.0",
"purl": "pkg:maven/org.acme/sub_web-framework@1.0.0"
}
]
},
{
"type": "library",
Expand Down Expand Up @@ -261,6 +281,7 @@
"aggregate": "incomplete",
"assemblies": [
"comp1",
"sub_comp1",
"comp2",
"comp3",
"comp4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,27 @@
"group": "org.acme",
"name": "web-framework",
"version": "1.0.0",
"purl": "pkg:maven/org.acme/web-framework@1.0.0"
"purl": "pkg:maven/org.acme/web-framework@1.0.0",
"components": [
{
"type": "library",
"bom-ref": "sub_comp1",
"supplier": {
"name": "Acme, Inc."
},
"licenses": [
{
"license": {
"id": "Apache-1.0"
}
}
],
"group": "org.acme",
"name": "sub_web-framework",
"version": "1.0.0",
"purl": "pkg:maven/org.acme/sub_web-framework@1.0.0"
}
]
},
{
"type": "library",
Expand Down Expand Up @@ -151,6 +171,7 @@
"aggregate": "incomplete",
"assemblies": [
"comp1",
"sub_comp1",
"comp2",
"comp3",
"comp4"
Expand Down
38 changes: 35 additions & 3 deletions tests/test_build_public_bom.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,8 @@ def test_build_public_from_documentation_4(self) -> None:
self.assertDictEqual(external_bom, public_sbom)

def test_build_public_no_schema(self) -> None:
sbom = get_test_sbom()
sbom = get_test_sbom()
public_sbom = get_test_sbom()

public_sbom["metadata"]["component"]["properties"].pop(1)
public_sbom["components"][1]["properties"].pop(1)
public_sbom["components"][1]["properties"].pop(2)
Expand All @@ -213,17 +211,51 @@ def test_build_public_no_schema(self) -> None:
public_sbom["components"][2]["properties"].pop(0)
public_sbom["components"][5]["properties"].pop(0)
external_bom = b_p_b.build_public_bom(sbom, None)

public_sbom["compositions"] = [
{
"aggregate": "incomplete",
"assemblies": [
"comp1",
"sub_comp1",
"comp2",
"internalcomp2",
"comp3",
"comp4",
"internalcomp1",
"internalcomp2",
"internalcomp3",
],
}
]
self.assertDictEqual(external_bom, public_sbom)

def test_deletion_of_orphaned_bom_refs(self) -> None:
sbom = get_test_sbom()
public_sbom = get_test_sbom()
public_sbom["metadata"]["component"]["properties"].pop(1)
public_sbom["components"][1]["properties"].pop(1)
public_sbom["components"][1]["properties"].pop(2)
public_sbom["components"][6]["properties"].pop(0)
public_sbom["components"][3]["properties"].pop(0)
public_sbom["components"][2]["properties"].pop(0)
public_sbom["components"][5]["properties"].pop(0)
sbom["compositions"][0]["assemblies"].append("orphaned bom-ref 1")
sbom["compositions"][0]["assemblies"].append("orphaned bom-ref 2")
external_bom = b_p_b.build_public_bom(sbom, None)
public_sbom["compositions"] = [
{
"aggregate": "incomplete",
"assemblies": [
"comp1",
"sub_comp1",
"comp2",
"comp3",
"comp4",
"internalcomp1",
"internalcomp2",
"internalcomp3",
"orphaned bom-ref 1",
"orphaned bom-ref 2",
],
}
]
Expand Down
82 changes: 82 additions & 0 deletions tests/test_sbom_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import unittest
from typing import Sequence

from cdxev.auxiliary import sbomFunctions as sbF


class TestComponentFunctions(unittest.TestCase):
def test_extract_components(self) -> None:
example_list: Sequence[dict] = [
{
"bom-ref": "first_level_1",
"components": [
{
"bom-ref": "second_level_1",
},
{
"bom-ref": "second_level_2",
"components": [
{
"bom-ref": "third_level_1",
},
{
"bom-ref": "third_level_2",
},
],
},
],
},
{
"bom-ref": "first_level_2",
"components": [
{
"bom-ref": "second_level_3",
"components": [
{
"bom-ref": "third_level_3",
"components": [
{
"bom-ref": "fourth_level_1",
}
],
}
],
},
{
"bom-ref": "second_level_4",
},
],
},
{
"bom-ref": "first_level_3",
"components": [
{
"bom-ref": "second_level_5",
}
],
},
]
components = sbF.extract_components(example_list)
self.assertEqual(
set(sbF.get_ref_from_components(components)),
set(
[
"first_level_1",
"first_level_2",
"first_level_3",
"second_level_1",
"second_level_2",
"second_level_3",
"second_level_4",
"second_level_5",
"third_level_1",
"third_level_2",
"third_level_3",
"fourth_level_1",
]
),
)


if __name__ == "__main__":
unittest.main()