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
50 changes: 50 additions & 0 deletions cve_bin_tool/sbom_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@


class SBOMManager:
"""
SBOMManager is a class that manages the Software Bill of Materials (SBOM) data.
It provides methods for scanning SBOM files, parsing them, and retrieving vendor information.
"""

SBOMtype = ["spdx", "cyclonedx", "swid"]

sbom_data: defaultdict[ProductInfo, TriageData]
Expand All @@ -44,6 +49,51 @@ def __init__(
# Connect to the database
self.cvedb = CVEDB(version_check=False)

def common_prefix_split(self, product, version) -> list[ProductInfo]:
"""If the product have '-' in name try splitting it and try common prefixes.
currently not being used, proposed to be used in future"""
parsed_data: list[ProductInfo] = []
found_common_prefix = False
common_prefix = (
"perl-",
"golang-",
"rubygem-",
"python-",
"py3-",
"python3-",
"python2-",
"rust-",
"nodejs-",
)
for prefix in common_prefix:
if product.startswith(prefix):
common_prefix_product = product[len(prefix) :]
common_prefix_vendor = self.get_vendor(common_prefix_product)
if len(common_prefix_vendor) > 1 or (
len(common_prefix_vendor) == 1
and common_prefix_vendor[0] != "UNKNOWN"
):
found_common_prefix = True
for vendor in common_prefix_vendor:
parsed_data.append(
ProductInfo(vendor, common_prefix_product, version)
)
break
if not found_common_prefix:
# if vendor not found after removing common prefix try splitting it
LOGGER.debug(
f"No Vendor found for {product}, trying splitted product. "
"Some results may be inaccurate due to vendor identification limitations."
)
splitted_product = product.split("-")
for sp in splitted_product:
temp = self.get_vendor(sp)
if len(temp) > 1 or (len(temp) == 1 and temp[0] != "UNKNOWN"):
for vendor in temp:
# if vendor is not None:
parsed_data.append(ProductInfo(vendor, sp, version))
return parsed_data

def scan_file(self) -> dict[ProductInfo, TriageData]:
self.logger.debug(
f"Processing SBOM {self.filename} of type {self.type.upper()}"
Expand Down
19 changes: 19 additions & 0 deletions test/test_sbom.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ class TestSBOM:
"paths": {""},
},
}
SPLIT_DATA = [
ProductInfo(vendor="openzeppelin", product="contracts", version="4.8.1"),
ProductInfo(vendor="downline_goldmine", product="builder", version="3.2.4"),
]

@pytest.mark.parametrize(
"filepath",
Expand Down Expand Up @@ -118,6 +122,21 @@ def test_valid_swid_file(
for p in swid_parsed_data:
assert p in scan_result

@pytest.mark.parametrize(
"product, version, productinfo, no_existent_file",
[
("openzeppelin-contracts", "4.8.1", SPLIT_DATA[0], "no_existent_file"),
("rubygem-builder", "3.2.4", SPLIT_DATA[1], "no_existent_file"),
],
)
def test_common_prefix_split(self, product, version, productinfo, no_existent_file):
"""Unit Test for common_prefix_split that try to split on hyphen if no vendors are
are found and the product has hyphen, here a no_existent_file is used
with sole purpose for creating a SBOMManager instance"""
sbom_engine = SBOMManager(no_existent_file)
scanned_list = sbom_engine.common_prefix_split(product, version)
assert productinfo in scanned_list

@pytest.mark.parametrize(
"filename, sbom_type, validate",
(
Expand Down