@@ -110,14 +110,17 @@ def parse(
110
110
111
111
# Get the detected type if auto was specified
112
112
if vextype == "auto" :
113
- vextype = vexparser .get_type ()
113
+ detected_type = vexparser .get_type ()
114
+ if detected_type :
115
+ vextype = detected_type
114
116
115
117
self .logger .debug (f"Parsed VEX file: { filename } of type: { vextype } " )
116
118
117
119
return self ._process_parsed_data (vexparser , vextype )
118
120
119
121
except Exception as e :
120
122
self .logger .error (f"Error parsing VEX file { filename } : { str (e )} " )
123
+ self .logger .debug (f"Exception details: { type (e ).__name__ } : { e } " )
121
124
return defaultdict (dict )
122
125
123
126
def validate (self , filename : str , vextype : str = "auto" ) -> bool :
@@ -238,60 +241,87 @@ def _process_parsed_data(
238
241
"""
239
242
parsed_data = defaultdict (dict )
240
243
serialNumbers = set ()
241
- vulnerabilities = vexparser .get_vulnerabilities ()
242
- metadata = vexparser .get_metadata ()
243
- product = vexparser .get_product ()
244
+
245
+ try :
246
+ vulnerabilities = vexparser .get_vulnerabilities ()
247
+ metadata = vexparser .get_metadata ()
248
+ product = vexparser .get_product ()
249
+ except Exception as e :
250
+ self .logger .error (f"Error extracting data from VEX parser: { e } " )
251
+ return defaultdict (dict )
244
252
245
253
# Extract product info based on VEX type but not used directly in this method
246
254
# Just stored for future extensions or reference
247
255
_ = self ._extract_product_info (vextype , metadata , product )
248
256
249
257
# Process vulnerabilities
250
258
for vuln in vulnerabilities :
251
- # Extract necessary fields from the vulnerability
252
- cve_id = vuln .get ("id" )
253
- remarks = self .analysis_state [vextype ][vuln .get ("status" )]
254
- justification = vuln .get ("justification" )
255
- response = vuln .get ("remediation" )
256
- comments = vuln .get ("comment" )
257
-
258
- # If the comment doesn't already have the justification prepended, add it
259
- if comments and justification and not comments .startswith (justification ):
260
- comments = f"{ justification } : { comments } "
261
-
262
- severity = vuln .get ("severity" )
263
-
264
- # Decode the bom reference or purl based on VEX type
265
- product_info = None
266
- serialNumber = ""
267
- if vextype == "cyclonedx" :
268
- decoded_result = decode_bom_ref (vuln .get ("bom_link" ))
269
- if isinstance (decoded_result , tuple ):
270
- # Handle tuple return (ProductInfo, serialNumber)
271
- product_info , serialNumber = decoded_result
272
- serialNumbers .add (serialNumber )
273
- else :
274
- # Handle single ProductInfo return
275
- product_info = decoded_result
276
- elif vextype in ["openvex" , "csaf" ]:
277
- product_info = decode_purl (vuln .get ("purl" ))
278
-
279
- if product_info :
280
- cve_data = {
281
- "remarks" : remarks ,
282
- "comments" : comments if comments else "" ,
283
- "response" : response if response else [],
284
- }
285
- if justification :
286
- cve_data ["justification" ] = justification .strip ()
287
-
288
- if severity :
289
- cve_data ["severity" ] = severity .strip ()
290
-
291
- parsed_data [product_info ][cve_id .strip ()] = cve_data
292
-
293
- if "paths" not in parsed_data [product_info ]:
294
- parsed_data [product_info ]["paths" ] = {}
259
+ try :
260
+ # Extract necessary fields from the vulnerability
261
+ cve_id = vuln .get ("id" )
262
+ if not cve_id :
263
+ continue
264
+
265
+ vulnerability_status = vuln .get ("status" )
266
+ if vulnerability_status not in self .analysis_state .get (vextype , {}):
267
+ self .logger .warning (f"Unknown status '{ vulnerability_status } ' for VEX type '{ vextype } ', skipping CVE { cve_id } " )
268
+ continue
269
+
270
+ remarks = self .analysis_state [vextype ][vulnerability_status ]
271
+ justification = vuln .get ("justification" )
272
+ response = vuln .get ("remediation" )
273
+ comments = vuln .get ("comment" )
274
+
275
+ # If the comment doesn't already have the justification prepended, add it
276
+ if comments and justification and not comments .startswith (justification ):
277
+ comments = f"{ justification } : { comments } "
278
+
279
+ severity = vuln .get ("severity" )
280
+
281
+ # Decode the bom reference or purl based on VEX type
282
+ product_info = None
283
+ serialNumber = ""
284
+ if vextype == "cyclonedx" :
285
+ bom_link = vuln .get ("bom_link" )
286
+ if bom_link :
287
+ decoded_result = decode_bom_ref (bom_link )
288
+ if decoded_result is None :
289
+ continue
290
+ elif isinstance (decoded_result , tuple ) and len (decoded_result ) == 2 :
291
+ # Handle tuple return (ProductInfo, serialNumber)
292
+ product_info , serialNumber = decoded_result
293
+ serialNumbers .add (serialNumber )
294
+ elif isinstance (decoded_result , ProductInfo ):
295
+ # Handle single ProductInfo return
296
+ product_info = decoded_result
297
+ else :
298
+ self .logger .warning (f"Unexpected return type from decode_bom_ref: { type (decoded_result )} " )
299
+ continue
300
+ elif vextype in ["openvex" , "csaf" ]:
301
+ purl = vuln .get ("purl" )
302
+ if purl :
303
+ product_info = decode_purl (purl )
304
+
305
+ if product_info :
306
+ cve_data = {
307
+ "remarks" : remarks ,
308
+ "comments" : comments if comments else "" ,
309
+ "response" : response if response else [],
310
+ }
311
+ if justification :
312
+ cve_data ["justification" ] = justification .strip ()
313
+
314
+ if severity :
315
+ cve_data ["severity" ] = severity .strip ()
316
+
317
+ parsed_data [product_info ][cve_id .strip ()] = cve_data
318
+
319
+ if "paths" not in parsed_data [product_info ]:
320
+ parsed_data [product_info ]["paths" ] = {}
321
+
322
+ except Exception as e :
323
+ self .logger .error (f"Error processing vulnerability { vuln } : { e } " )
324
+ continue
295
325
296
326
self .logger .debug (f"Parsed VEX data: { parsed_data } " )
297
327
return parsed_data
0 commit comments