@@ -15,6 +15,19 @@ class ProwlerParser:
15
15
Supports both CSV and OCSF JSON for AWS, Azure, GCP, and Kubernetes.
16
16
"""
17
17
18
+ # Severity mapping from Prowler to DefectDojo
19
+ SEVERITY_MAP = {
20
+ "critical" : "Critical" ,
21
+ "high" : "High" ,
22
+ "medium" : "Medium" ,
23
+ "low" : "Low" ,
24
+ "informational" : "Info" ,
25
+ "info" : "Info" ,
26
+ }
27
+
28
+ # Statuses that indicate inactive findings
29
+ INACTIVE_STATUSES = {"pass" , "manual" , "not_available" , "skipped" }
30
+
18
31
def get_scan_types (self ):
19
32
return ["Prowler Scan" ]
20
33
@@ -70,27 +83,16 @@ def _parse_csv(self, content):
70
83
71
84
def _determine_severity (self , severity_str ):
72
85
"""Maps Prowler severity to DefectDojo severity"""
73
- severity_map = {
74
- "critical" : "Critical" ,
75
- "high" : "High" ,
76
- "medium" : "Medium" ,
77
- "low" : "Low" ,
78
- "informational" : "Info" ,
79
- "info" : "Info" ,
80
- }
81
-
82
86
# Convert to lowercase for case-insensitive matching
83
87
severity_str = severity_str .lower () if severity_str else ""
84
- return severity_map . get (severity_str , "Medium " )
88
+ return self . SEVERITY_MAP . get (severity_str , "Info " )
85
89
86
90
def _determine_active_status (self , status_code ):
87
91
"""Determine if the finding is active based on its status"""
88
92
if not status_code :
89
93
return True
90
94
91
- # Using a set for O(1) lookup performance
92
- inactive_statuses = {"pass" , "manual" , "not_available" , "skipped" }
93
- return status_code .lower () not in inactive_statuses
95
+ return status_code .lower () not in self .INACTIVE_STATUSES
94
96
95
97
def _parse_json_findings (self , data , test , * , file_name = "" ):
96
98
"""Parse findings from the OCSF JSON format"""
@@ -238,19 +240,21 @@ def _parse_json_findings(self, data, test, *, file_name=""):
238
240
if check_id :
239
241
finding .vuln_id_from_tool = check_id
240
242
241
- # Add resource information to mitigation if available
242
- mitigation_parts = []
243
+ # Add resource information to impact field
244
+ impact_parts = []
243
245
if resource_type :
244
- mitigation_parts .append (f"Resource Type: { resource_type } " )
246
+ impact_parts .append (f"Resource Type: { resource_type } " )
245
247
if resource_name :
246
- mitigation_parts .append (f"Resource Name: { resource_name } " )
248
+ impact_parts .append (f"Resource Name: { resource_name } " )
247
249
if region :
248
- mitigation_parts .append (f"Region: { region } " )
249
- if remediation :
250
- mitigation_parts .append (f"Remediation: { remediation } " )
250
+ impact_parts .append (f"Region: { region } " )
251
251
252
- if mitigation_parts :
253
- finding .mitigation = "\n " .join (mitigation_parts )
252
+ if impact_parts :
253
+ finding .impact = "\n " .join (impact_parts )
254
+
255
+ # Add remediation information to mitigation field
256
+ if remediation :
257
+ finding .mitigation = f"Remediation: { remediation } "
254
258
255
259
findings .append (finding )
256
260
@@ -266,23 +270,8 @@ def _parse_csv_findings(self, csv_data, test, *, file_name=""):
266
270
check_title = row .get ("CHECK_TITLE" , "" )
267
271
provider = row .get ("PROVIDER" , "" ).lower ()
268
272
269
- # Original check ID before any standardization (for titles)
270
- original_check_id = check_id
271
-
272
- # Standardize check IDs for consistent test results
273
- if provider == "gcp" and ("compute_firewall" in check_id .lower () or "rdp" in check_title .lower ()):
274
- check_id = "bc_gcp_networking_2"
275
- elif provider == "kubernetes" and "alwayspullimages" in check_id .lower ():
276
- check_id = "bc_k8s_pod_security_1"
277
- # Special handling for AWS Hardware MFA check
278
- elif provider == "aws" and "hardware_mfa" in check_id .lower ():
279
- check_id = "iam_root_hardware_mfa_enabled"
280
- # Special handling for Azure AKS network policy
281
- elif provider == "azure" and "aks_network_policy" in check_id .lower ():
282
- check_id = "aks_network_policy_enabled"
283
-
284
273
# Construct title
285
- if original_check_id and check_title :
274
+ if check_id and check_title :
286
275
title = f"{ check_id } : { check_title } "
287
276
elif check_id :
288
277
title = check_id
@@ -387,16 +376,22 @@ def _parse_csv_findings(self, csv_data, test, *, file_name=""):
387
376
if service_name :
388
377
finding .unsaved_tags .append (service_name )
389
378
390
- # Build mitigation from resource info and remediation
391
- mitigation_parts = []
379
+ # Build impact from resource info
380
+ impact_parts = []
392
381
if resource_type :
393
- mitigation_parts .append (f"Resource Type: { resource_type } " )
382
+ impact_parts .append (f"Resource Type: { resource_type } " )
394
383
if resource_name :
395
- mitigation_parts .append (f"Resource Name: { resource_name } " )
384
+ impact_parts .append (f"Resource Name: { resource_name } " )
396
385
if resource_uid :
397
- mitigation_parts .append (f"Resource ID: { resource_uid } " )
386
+ impact_parts .append (f"Resource ID: { resource_uid } " )
398
387
if region :
399
- mitigation_parts .append (f"Region: { region } " )
388
+ impact_parts .append (f"Region: { region } " )
389
+
390
+ if impact_parts :
391
+ finding .impact = "\n " .join (impact_parts )
392
+
393
+ # Build mitigation from remediation info
394
+ mitigation_parts = []
400
395
if remediation_text :
401
396
mitigation_parts .append (f"Remediation: { remediation_text } " )
402
397
if remediation_url :
0 commit comments