|
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