|
1 | | -# Copyright (C) 2024 Intel Corporation |
| 1 | +# Copyright (C) 2025 Intel Corporation |
2 | 2 | # SPDX-License-Identifier: GPL-3.0-or-later |
3 | 3 |
|
4 | 4 | from logging import Logger |
5 | 5 | from pathlib import Path |
6 | 6 | from typing import Dict, List, Optional |
7 | 7 |
|
8 | | -from lib4sbom.data.vulnerability import Vulnerability |
9 | | -from lib4vex.generator import VEXGenerator |
10 | | - |
11 | 8 | from cve_bin_tool.log import LOGGER |
12 | 9 | from cve_bin_tool.util import CVEData, ProductInfo, Remarks |
| 10 | +from cve_bin_tool.vex_manager.handler import VexHandler |
13 | 11 |
|
14 | 12 |
|
15 | 13 | class VEXGenerate: |
@@ -103,40 +101,50 @@ def __init__( |
103 | 101 | self.all_cve_data = all_cve_data |
104 | 102 | self.sbom_serial_number = sbom_serial_number |
105 | 103 |
|
| 104 | + # Initialize the VexHandler for generation operations |
| 105 | + self.vex_handler = VexHandler(self.logger) |
| 106 | + |
106 | 107 | def generate_vex(self) -> None: |
107 | 108 | """ |
108 | 109 | Generates a VEX (Vulnerability Exploitability eXchange) document based on the specified VEX type |
109 | 110 | and stores it in the given filename. |
110 | 111 |
|
111 | | - This method sets up a VEX generator instance with the product name, release version, and other |
112 | | - metadata. It automatically assigns a filename if none is provided, logs the update status if the |
113 | | - file already exists, and generates the VEX document with product vulnerability data. |
| 112 | + This method delegates to the VexHandler for the actual generation, after preparing the data |
| 113 | + structure with product, vulnerabilities and metadata. It automatically assigns a filename if |
| 114 | + none is provided and logs update status if the file already exists. |
114 | 115 |
|
115 | 116 | Returns: |
116 | 117 | None |
117 | 118 | """ |
118 | | - author = "Unknown Author" |
119 | | - if self.vendor: |
120 | | - author = self.vendor |
121 | | - vexgen = VEXGenerator(vex_type=self.vextype, author=author) |
122 | | - kwargs = {"name": self.product, "release": self.release} |
123 | | - if self.sbom: |
124 | | - kwargs["sbom"] = self.sbom |
125 | | - vexgen.set_product(**kwargs) |
126 | 119 | if not self.filename: |
127 | | - self.logger.info( |
| 120 | + self.logger.debug( |
128 | 121 | "No filename defined, generating a new filename with default naming convention." |
129 | 122 | ) |
130 | 123 | self.filename = self.__generate_vex_filename() |
| 124 | + |
131 | 125 | if Path(self.filename).is_file(): |
132 | | - self.logger.info(f"Updating the VEX file: {self.filename}") |
| 126 | + self.logger.debug(f"Updating the VEX file: {self.filename}") |
| 127 | + |
| 128 | + # Prepare data structure for VexHandler |
| 129 | + vex_data = { |
| 130 | + "product": { |
| 131 | + "name": self.product, |
| 132 | + "release": self.release, |
| 133 | + "vendor": self.vendor, |
| 134 | + }, |
| 135 | + "project_name": self.product, |
| 136 | + "vulnerabilities": self.__get_vulnerabilities(), |
| 137 | + "metadata": self.__get_metadata(), |
| 138 | + } |
| 139 | + |
| 140 | + # Add SBOM if available |
| 141 | + if self.sbom: |
| 142 | + vex_data["sbom"] = self.sbom |
133 | 143 |
|
134 | | - vexgen.generate( |
135 | | - project_name=self.product, |
136 | | - vex_data=self.__get_vulnerabilities(), |
137 | | - metadata=self.__get_metadata(), |
138 | | - filename=self.filename, |
139 | | - ) |
| 144 | + # Generate VEX document using the handler |
| 145 | + success = self.vex_handler.generate(vex_data, self.filename, self.vextype) |
| 146 | + if not success: |
| 147 | + self.logger.error(f"Failed to generate VEX file: {self.filename}") |
140 | 148 |
|
141 | 149 | def __generate_vex_filename(self) -> str: |
142 | 150 | """ |
@@ -183,56 +191,62 @@ def __get_metadata(self) -> Dict: |
183 | 191 |
|
184 | 192 | return metadata |
185 | 193 |
|
186 | | - def __get_vulnerabilities(self) -> List[Vulnerability]: |
| 194 | + def __get_vulnerabilities(self) -> List[Dict]: |
187 | 195 | """ |
188 | | - Retrieves and constructs a list of vulnerability objects based on the current CVE data. |
| 196 | + Prepares a list of vulnerability dictionaries for the VEX document based on the current CVE data. |
189 | 197 |
|
190 | 198 | This method iterates through all CVE data associated with the product and vendor, |
191 | | - creating and configuring `Vulnerability` objects for each entry. It sets attributes |
192 | | - like name, release, ID, description, status, and additional metadata such as package |
193 | | - URLs (purl) and bill of materials (BOM) links. If a vulnerability includes comments |
194 | | - or justification, these are added to the vulnerability details. |
| 199 | + creating vulnerability dictionaries for each entry with attributes like ID, description, |
| 200 | + status, and additional metadata such as package URLs (purl) and bill of materials (BOM) links. |
195 | 201 |
|
196 | 202 | Returns: |
197 | | - List[Vulnerability]: A list of `Vulnerability` objects representing the identified |
198 | | - vulnerabilities, enriched with metadata and details. |
| 203 | + List[Dict]: A list of vulnerability dictionaries ready for VexHandler to process. |
199 | 204 | """ |
200 | 205 | vulnerabilities = [] |
201 | 206 | for product_info, cve_data in self.all_cve_data.items(): |
202 | 207 | vendor, product, version, _, purl = product_info |
203 | 208 | for cve in cve_data["cves"]: |
204 | 209 | if isinstance(cve, str): |
205 | 210 | continue |
206 | | - vulnerability = Vulnerability(validation=self.vextype) |
207 | | - vulnerability.initialise() |
208 | | - vulnerability.set_name(product) |
209 | | - vulnerability.set_release(version) |
210 | | - vulnerability.set_id(cve.cve_number) |
211 | | - vulnerability.set_description(cve.description) |
212 | | - vulnerability.set_comment(cve.comments) |
213 | | - vulnerability.set_status(self.analysis_state[self.vextype][cve.remarks]) |
| 211 | + |
| 212 | + # Create a vulnerability dictionary in the format expected by VexHandler |
| 213 | + vulnerability = { |
| 214 | + "name": product, |
| 215 | + "release": version, |
| 216 | + "id": cve.cve_number, |
| 217 | + "description": cve.description, |
| 218 | + "comment": cve.comments, |
| 219 | + "status": self.analysis_state[self.vextype][cve.remarks], |
| 220 | + } |
| 221 | + |
214 | 222 | if cve.justification: |
215 | | - vulnerability.set_justification(cve.justification) |
216 | | - if cve.response: |
217 | | - vulnerability.set_value("remediation", cve.response[0]) |
| 223 | + vulnerability["justification"] = cve.justification |
| 224 | + |
| 225 | + if cve.response and len(cve.response) > 0: |
| 226 | + vulnerability["remediation"] = cve.response[0] |
| 227 | + |
218 | 228 | detail = ( |
219 | 229 | f"{cve.remarks.name}: {cve.comments}" |
220 | 230 | if cve.comments |
221 | 231 | else cve.remarks.name |
222 | 232 | ) |
| 233 | + |
223 | 234 | if purl is None: |
224 | 235 | purl = f"pkg:generic/{vendor}/{product}@{version}" |
| 236 | + |
225 | 237 | bom_version = 1 |
226 | 238 | if self.sbom_serial_number != "": |
227 | 239 | ref = f"urn:cdx:{self.sbom_serial_number}/{bom_version}#{purl}" |
228 | 240 | else: |
229 | 241 | ref = f"urn:cbt:{bom_version}/{vendor}#{product}:{version}" |
230 | 242 |
|
231 | | - vulnerability.set_value("purl", str(purl)) |
232 | | - vulnerability.set_value("bom_link", ref) |
233 | | - vulnerability.set_value("action", detail) |
234 | | - vulnerability.set_value("source", cve.data_source) |
235 | | - vulnerability.set_value("updated", cve.last_modified) |
236 | | - vulnerabilities.append(vulnerability.get_vulnerability()) |
| 243 | + vulnerability["purl"] = str(purl) |
| 244 | + vulnerability["bom_link"] = ref |
| 245 | + vulnerability["action"] = detail |
| 246 | + vulnerability["source"] = cve.data_source |
| 247 | + vulnerability["updated"] = cve.last_modified |
| 248 | + |
| 249 | + vulnerabilities.append(vulnerability) |
| 250 | + |
237 | 251 | self.logger.debug(f"Vulnerabilities: {vulnerabilities}") |
238 | 252 | return vulnerabilities |
0 commit comments