diff --git a/cve_bin_tool/cli.py b/cve_bin_tool/cli.py index 451783ec01..95074e65cc 100644 --- a/cve_bin_tool/cli.py +++ b/cve_bin_tool/cli.py @@ -1169,8 +1169,8 @@ def main(argv=None): else: # In no-scan mode, still populate all_product_data for display if product_info not in cve_scanner.all_product_data: - cve_scanner.all_product_data[product_info] = 0 - cve_scanner.all_product_data[product_info] = 0 + cve_scanner.all_product_data[product_info]["cves_total"] = 0 + cve_scanner.all_product_data[product_info]["cves_total"] = 0 total_files = version_scanner.total_scanned_files LOGGER.info(f"Total files: {total_files}") diff --git a/cve_bin_tool/cve_scanner.py b/cve_bin_tool/cve_scanner.py index f353dc2b09..3669058bb4 100644 --- a/cve_bin_tool/cve_scanner.py +++ b/cve_bin_tool/cve_scanner.py @@ -62,7 +62,7 @@ def __init__( self.products_without_cve = 0 self.all_cve_data = defaultdict(lambda: {"cves": [], "paths": set()}) self.all_cve_version_info = dict() - self.all_product_data = dict() + self.all_product_data = defaultdict(lambda: {"cves_total": 0, "paths": set()}) def get_cves(self, product_info: ProductInfo, triage_data: TriageData): """Get CVEs against a specific version of a product. @@ -81,7 +81,7 @@ def get_cves(self, product_info: ProductInfo, triage_data: TriageData): # In no-scan mode, just populate the product data without CVE scanning if product_info not in self.all_product_data: self.logger.debug(f"Add product {product_info} (no-scan mode)") - self.all_product_data[product_info] = 0 + self.all_product_data[product_info]["cves_total"] = 0 # Also populate all_cve_data with empty CVE list and paths if product_info not in self.all_cve_data: @@ -89,6 +89,7 @@ def get_cves(self, product_info: ProductInfo, triage_data: TriageData): # Update paths self.all_cve_data[product_info]["paths"] |= set(triage_data["paths"]) + self.all_product_data[product_info]["paths"] |= set(triage_data["paths"]) return if product_info.vendor == "UNKNOWN": @@ -96,7 +97,7 @@ def get_cves(self, product_info: ProductInfo, triage_data: TriageData): if product_info not in self.all_product_data: self.logger.debug(f"Add product {product_info}") # Number of CVEs is 0 - self.all_product_data[product_info] = 0 + self.all_product_data[product_info]["cves_total"] = 0 return if product_info in self.all_cve_data: @@ -396,7 +397,10 @@ def get_cves(self, product_info: ProductInfo, triage_data: TriageData): ) if product_info not in self.all_product_data: - self.all_product_data[product_info] = len(cves) + self.all_product_data[product_info]["cves_total"] = len(cves) + + # Update paths + self.all_product_data[product_info]["paths"] |= set(triage_data["paths"]) def filter_triage_data(self): """ diff --git a/cve_bin_tool/output_engine/__init__.py b/cve_bin_tool/output_engine/__init__.py index 432fc461fc..5493250989 100644 --- a/cve_bin_tool/output_engine/__init__.py +++ b/cve_bin_tool/output_engine/__init__.py @@ -601,7 +601,7 @@ def output_pdf( products_with_cves = list(map(lambda x: x[1], all_cve_data)) for product_data in all_product_data: if ( - all_product_data[product_data] == 0 + all_product_data[product_data]["cves_total"] == 0 and product_data.product not in products_with_cves ): product_entry = [ diff --git a/cve_bin_tool/output_engine/console.py b/cve_bin_tool/output_engine/console.py index 9a6df122a4..0f66e6db07 100644 --- a/cve_bin_tool/output_engine/console.py +++ b/cve_bin_tool/output_engine/console.py @@ -158,7 +158,7 @@ def _output_console_nowrap( if color is None and count > 0: color = summary_color[severity.split("-")[0]] - if all_product_data[product_data] != 0 or no_scan: + if all_product_data[product_data]["cves_total"] != 0 or no_scan: if no_scan: latest_stable_version = "NA" elif offline: @@ -185,7 +185,9 @@ def _output_console_nowrap( Text.styled(str(count), color), ] cells += [ - Text.styled(str(all_product_data[product_data]), color), + Text.styled( + str(all_product_data[product_data]["cves_total"]), color + ), ] table.add_row(*cells) # Print the table to the console @@ -373,7 +375,7 @@ def validate_cell_length(cell_name, cell_type): for product_data in all_product_data: if ( - all_product_data[product_data] == 0 + all_product_data[product_data]["cves_total"] == 0 and product_data.product not in products_with_cves ): cells = [ diff --git a/cve_bin_tool/sbom_manager/generate.py b/cve_bin_tool/sbom_manager/generate.py index fea94c3a87..f9aaa0f3e3 100644 --- a/cve_bin_tool/sbom_manager/generate.py +++ b/cve_bin_tool/sbom_manager/generate.py @@ -110,14 +110,19 @@ def generate_sbom(self) -> None: and product_data.vendor == "unknown" ): # In no-scan mode, we still want to include path information if available - if self.all_cve_data.get(product_data) and self.all_cve_data[ + if self.all_product_data.get(product_data) and self.all_product_data[ product_data ].get("paths"): - for path in self.all_cve_data[product_data]["paths"]: - with open(path.split()[0], "rb") as f: - file_data = f.read() - sha256_hash = hashlib.sha256(file_data) - my_package.set_checksum("SHA256", sha256_hash.hexdigest()) + for path in self.all_product_data[product_data]["paths"]: + try: + with open(path.split()[0], "rb") as f: + file_data = f.read() + sha256_hash = hashlib.sha256(file_data) + my_package.set_checksum("SHA256", sha256_hash.hexdigest()) + except FileNotFoundError: + self.logger.debug( + f"{path} not found, no checksum added to SBOM" + ) if self.strip_scan_dir: evidence = strip_path(path, self.sbom_root) else: diff --git a/test/test_output_engine.py b/test/test_output_engine.py index c29375f7ce..4355bd7a7f 100644 --- a/test/test_output_engine.py +++ b/test/test_output_engine.py @@ -940,18 +940,18 @@ class TestOutputEngine(unittest.TestCase): ) def setUp(self) -> None: - self.all_product_data = [ + self.all_product_data = { ProductInfo( product="product1", version="1.0", vendor="VendorA", - ), + ): {"cves_total": 0, "paths": {"/path/to/test"}}, ProductInfo( product="product2", version="2.0", vendor="unknown", - ), - ] + ): {"cves_total": 0, "paths": {"/path/to/test"}}, + } self.output_engine = OutputEngine( all_cve_data=self.MOCK_OUTPUT, scanned_dir="", @@ -1070,7 +1070,7 @@ def test_console_output_no_scan_mode_latest_version(self): all_product_data = { ProductInfo( vendor="test_vendor", product="test_product", version="1.0.0" - ): 0, + ): {"cves_total": 0, "paths": {"/path/to/test"}} } all_cve_data = {