From 6fd5217615843ef739529cb315f9229fd675a93c Mon Sep 17 00:00:00 2001 From: pedrooot Date: Wed, 11 Jun 2025 16:20:42 +0200 Subject: [PATCH] feat(compliance): improve pdf output --- .../compliance_report/compliance_generator.py | 145 +++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/util/compliance_report/compliance_generator.py b/util/compliance_report/compliance_generator.py index cf0319d8a5..e8e59df58b 100644 --- a/util/compliance_report/compliance_generator.py +++ b/util/compliance_report/compliance_generator.py @@ -24,7 +24,7 @@ def generate_compliance_report( output_path: str, email: str, password: str, - only_failed: bool = False, + only_failed: bool = True, ): """ Generate a PDF compliance report based on Prowler endpoints. @@ -370,7 +370,7 @@ def generate_compliance_report( pass elements.append(Spacer(1, 0.3 * inch)) elements.append(Paragraph("Compliance Report - Prowler", title_style)) - elements.append(Spacer(1, 0.3 * inch)) + elements.append(Spacer(1, 5 * inch)) info_data = [ ["Compliance Framework:", compliance_name], @@ -521,6 +521,147 @@ def generate_compliance_report( elements.append(PageBreak()) + elements.append(Paragraph("Top Requirements by Level of Risk", h1)) + elements.append(Spacer(1, 0.1 * inch)) + elements.append(Paragraph("Critical Failed Requirements (Risk Level ≥ 4)", h2)) + elements.append(Spacer(1, 0.2 * inch)) + + critical_reqs = [] + for req in resp_reqs: + req_id = req["id"] + attr = attrs_map.get(req_id, {}) + status = req["attributes"]["status"] + + if status == "FAIL": + metadata = attr.get("attributes", {}).get("metadata", []) + if metadata: + m = metadata[0] + risk_level = m.get("LevelOfRisk", 0) + weight = m.get("Weight", 0) + + if risk_level >= 4: + critical_reqs.append( + { + "req": req, + "attr": attr, + "risk_level": risk_level, + "weight": weight, + "metadata": m, + } + ) + + critical_reqs.sort(key=lambda x: (x["risk_level"], x["weight"]), reverse=True) + + if not critical_reqs: + elements.append( + Paragraph("✅ No critical failed requirements found. Great job!", normal) + ) + else: + elements.append( + Paragraph( + f"Found {len(critical_reqs)} critical failed requirements that require immediate attention:", + normal, + ) + ) + elements.append(Spacer(1, 0.5 * inch)) + + table_data = [["Risk", "Weight", "Requirement ID", "Title", "Section"]] + + for idx, critical_req in enumerate(critical_reqs): + req_id = critical_req["req"]["id"] + risk_level = critical_req["risk_level"] + weight = critical_req["weight"] + title = critical_req["metadata"].get("Title", "N/A") + section = critical_req["metadata"].get("Section", "N/A") + + if len(title) > 50: + title = title[:47] + "..." + + table_data.append([str(risk_level), str(weight), req_id, title, section]) + + critical_table = Table( + table_data, + colWidths=[0.6 * inch, 0.8 * inch, 1.2 * inch, 3 * inch, 1.4 * inch], + ) + + critical_table.setStyle( + TableStyle( + [ + ("BACKGROUND", (0, 0), (-1, 0), colors.Color(0.8, 0.2, 0.2)), + ("TEXTCOLOR", (0, 0), (-1, 0), colors.white), + ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), + ("FONTSIZE", (0, 0), (-1, 0), 10), + ("BACKGROUND", (0, 1), (0, -1), colors.Color(0.8, 0.2, 0.2)), + ("TEXTCOLOR", (0, 1), (0, -1), colors.white), + ("FONTNAME", (0, 1), (0, -1), "Helvetica-Bold"), + ("ALIGN", (0, 1), (0, -1), "CENTER"), + ("FONTSIZE", (0, 1), (0, -1), 12), + ("ALIGN", (1, 1), (1, -1), "CENTER"), + ("FONTNAME", (1, 1), (1, -1), "Helvetica-Bold"), + ("FONTNAME", (2, 1), (2, -1), "Helvetica-Bold"), + ("FONTSIZE", (2, 1), (2, -1), 9), + ("FONTNAME", (3, 1), (-1, -1), "Helvetica"), + ("FONTSIZE", (3, 1), (-1, -1), 8), + ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), + ("GRID", (0, 0), (-1, -1), 1, colors.Color(0.7, 0.7, 0.7)), + ("LEFTPADDING", (0, 0), (-1, -1), 6), + ("RIGHTPADDING", (0, 0), (-1, -1), 6), + ("TOPPADDING", (0, 0), (-1, -1), 8), + ("BOTTOMPADDING", (0, 0), (-1, -1), 8), + ("BACKGROUND", (1, 1), (-1, -1), colors.Color(0.98, 0.98, 0.98)), + ] + ) + ) + + for idx, critical_req in enumerate(critical_reqs): + row_idx = idx + 1 + weight = critical_req["weight"] + + if weight >= 150: + weight_color = colors.Color(0.8, 0.2, 0.2) + elif weight >= 100: + weight_color = colors.Color(0.9, 0.6, 0.2) + else: + weight_color = colors.Color(0.9, 0.9, 0.2) + + critical_table.setStyle( + TableStyle( + [ + ("BACKGROUND", (1, row_idx), (1, row_idx), weight_color), + ("TEXTCOLOR", (1, row_idx), (1, row_idx), colors.white), + ] + ) + ) + + elements.append(critical_table) + elements.append(Spacer(1, 0.2 * inch)) + + warning_text = """ + IMMEDIATE ACTION REQUIRED:
+ These requirements have the highest risk levels and have failed compliance checks. + Please prioritize addressing these issues to improve your security posture. + """ + + warning_style = ParagraphStyle( + "Warning", + parent=styles["Normal"], + fontSize=11, + textColor=colors.Color(0.8, 0.2, 0.2), + spaceBefore=10, + spaceAfter=10, + leftIndent=20, + rightIndent=20, + fontName="Helvetica", + backColor=colors.Color(1.0, 0.95, 0.95), + borderWidth=2, + borderColor=colors.Color(0.8, 0.2, 0.2), + borderPadding=10, + ) + + elements.append(Paragraph(warning_text, warning_style)) + + elements.append(PageBreak()) + def get_weight(req): req_id = req["id"] attr = attrs_map.get(req_id, {})