diff --git a/util/compliance_report/assets/fonts/FiraCode-Regular.ttf b/util/compliance_report/assets/fonts/FiraCode-Regular.ttf
new file mode 100644
index 0000000000..3a57209a97
Binary files /dev/null and b/util/compliance_report/assets/fonts/FiraCode-Regular.ttf differ
diff --git a/util/compliance_report/assets/fonts/PlusJakartaSans-Regular.ttf b/util/compliance_report/assets/fonts/PlusJakartaSans-Regular.ttf
new file mode 100644
index 0000000000..f43b5f4356
Binary files /dev/null and b/util/compliance_report/assets/fonts/PlusJakartaSans-Regular.ttf differ
diff --git a/util/compliance_report/threatscore_report_generator.py b/util/compliance_report/threatscore_report_generator.py
index d9dc002e58..a6b670b18a 100644
--- a/util/compliance_report/threatscore_report_generator.py
+++ b/util/compliance_report/threatscore_report_generator.py
@@ -1,4 +1,5 @@
import io
+import os
import matplotlib.pyplot as plt
import requests
@@ -7,6 +8,9 @@ from reportlab.lib.enums import TA_CENTER
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import inch
+from reportlab.pdfbase import pdfmetrics
+from reportlab.pdfbase.ttfonts import TTFont
+from reportlab.pdfgen import canvas
from reportlab.platypus import (
Image,
PageBreak,
@@ -17,6 +21,22 @@ from reportlab.platypus import (
TableStyle,
)
+pdfmetrics.registerFont(
+ TTFont(
+ "PlusJakartaSans",
+ os.path.join(
+ os.path.dirname(__file__), "assets/fonts/PlusJakartaSans-Regular.ttf"
+ ),
+ )
+)
+
+pdfmetrics.registerFont(
+ TTFont(
+ "FiraCode",
+ os.path.join(os.path.dirname(__file__), "assets/fonts/FiraCode-Regular.ttf"),
+ )
+)
+
def generate_threatscore_report(
scan_id: str,
@@ -51,7 +71,7 @@ def generate_threatscore_report(
fontSize=24,
textColor=prowler_dark_green,
spaceAfter=20,
- fontName="Helvetica-Bold",
+ fontName="PlusJakartaSans",
alignment=TA_CENTER,
)
@@ -62,7 +82,7 @@ def generate_threatscore_report(
textColor=colors.Color(0.2, 0.4, 0.6),
spaceBefore=20,
spaceAfter=12,
- fontName="Helvetica-Bold",
+ fontName="PlusJakartaSans",
leftIndent=0,
borderWidth=2,
borderColor=colors.Color(0.2, 0.4, 0.6),
@@ -77,7 +97,7 @@ def generate_threatscore_report(
textColor=colors.Color(0.3, 0.5, 0.7),
spaceBefore=15,
spaceAfter=8,
- fontName="Helvetica-Bold",
+ fontName="PlusJakartaSans",
leftIndent=10,
borderWidth=1,
borderColor=colors.Color(0.7, 0.8, 0.9),
@@ -92,7 +112,7 @@ def generate_threatscore_report(
textColor=colors.Color(0.4, 0.6, 0.8),
spaceBefore=10,
spaceAfter=6,
- fontName="Helvetica-Bold",
+ fontName="PlusJakartaSans",
leftIndent=20,
)
@@ -104,7 +124,7 @@ def generate_threatscore_report(
spaceBefore=4,
spaceAfter=4,
leftIndent=30,
- fontName="Helvetica",
+ fontName="PlusJakartaSans",
)
normal_center = ParagraphStyle(
@@ -112,7 +132,7 @@ def generate_threatscore_report(
parent=styles["Normal"],
fontSize=10,
textColor=colors.Color(0.2, 0.2, 0.2),
- fontName="Helvetica",
+ fontName="PlusJakartaSans",
)
url_credentials = f"{base_url}/api/v1/tokens"
@@ -204,15 +224,15 @@ def generate_threatscore_report(
("BACKGROUND", (0, 0), (0, 0), colors.Color(0.9, 0.9, 0.9)),
("BACKGROUND", (1, 0), (1, 0), risk_color),
("TEXTCOLOR", (1, 0), (1, 0), colors.white),
- ("FONTNAME", (1, 0), (1, 0), "Helvetica-Bold"),
+ ("FONTNAME", (1, 0), (1, 0), "FiraCode"),
("BACKGROUND", (2, 0), (2, 0), colors.Color(0.9, 0.9, 0.9)),
("BACKGROUND", (3, 0), (3, 0), weight_color),
("TEXTCOLOR", (3, 0), (3, 0), colors.white),
- ("FONTNAME", (3, 0), (3, 0), "Helvetica-Bold"),
+ ("FONTNAME", (3, 0), (3, 0), "FiraCode"),
("BACKGROUND", (4, 0), (4, 0), colors.Color(0.9, 0.9, 0.9)),
("BACKGROUND", (5, 0), (5, 0), score_color),
("TEXTCOLOR", (5, 0), (5, 0), colors.white),
- ("FONTNAME", (5, 0), (5, 0), "Helvetica-Bold"),
+ ("FONTNAME", (5, 0), (5, 0), "FiraCode"),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("FONTSIZE", (0, 0), (-1, -1), 10),
@@ -246,10 +266,10 @@ def generate_threatscore_report(
TableStyle(
[
("BACKGROUND", (0, 0), (0, 0), colors.Color(0.9, 0.9, 0.9)),
- ("FONTNAME", (0, 0), (0, 0), "Helvetica"),
+ ("FONTNAME", (0, 0), (0, 0), "PlusJakartaSans"),
("BACKGROUND", (1, 0), (1, 0), status_color),
("TEXTCOLOR", (1, 0), (1, 0), colors.white),
- ("FONTNAME", (1, 0), (1, 0), "Helvetica-Bold"),
+ ("FONTNAME", (1, 0), (1, 0), "FiraCode"),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("FONTSIZE", (0, 0), (-1, -1), 12),
@@ -330,7 +350,6 @@ def generate_threatscore_report(
ax.set_ylabel("Compliance Score (%)", fontsize=12)
ax.set_xlabel("Section", fontsize=12)
- ax.set_title("COMPLIANCE SCORE BY SECTIONS", fontsize=14, fontweight="bold")
ax.set_ylim(0, 100)
for bar, percentage in zip(bars, compliance_percentages):
@@ -369,7 +388,7 @@ def generate_threatscore_report(
doc = SimpleDocTemplate(
output_path,
pagesize=letter,
- title=f"Compliance Report - {compliance_name}",
+ title=f"Prowler ThreatScore Report - {compliance_name}",
author="Prowler",
subject=f"Compliance Report for {compliance_name}",
creator="Prowler Compliance Generator",
@@ -387,28 +406,15 @@ def generate_threatscore_report(
except Exception:
pass
elements.append(Spacer(1, 0.5 * inch))
- elements.append(Paragraph("Compliance Report - Prowler", title_style))
+ elements.append(Paragraph("Prowler ThreatScore Report", title_style))
elements.append(Spacer(1, 0.5 * inch))
- pretty_description = (
- (
- "Prowler ThreatScore Compliance Framework for Azure ensures that the Azure subscription is compliant, "
- "taking into account four main pillars:
"
- "- Identity and Access Management
"
- "- Attack Surface
"
- "- Forensic Readiness
"
- "- Encryption"
- )
- if compliance_id == "prowler_threatscore_azure"
- else compliance_description
- )
-
info_data = [
["Compliance Framework:", compliance_name],
["Compliance ID:", compliance_id],
["Version:", compliance_version],
["Scan ID:", scan_id],
- ["Description:", Paragraph(pretty_description, normal_center)],
+ ["Description:", Paragraph(compliance_description, normal_center)],
]
info_table = Table(info_data, colWidths=[2 * inch, 4 * inch])
info_table.setStyle(
@@ -416,10 +422,10 @@ def generate_threatscore_report(
[
("BACKGROUND", (0, 0), (0, 4), colors.Color(0.2, 0.4, 0.6)),
("TEXTCOLOR", (0, 0), (0, 4), colors.white),
- ("FONTNAME", (0, 0), (0, 4), "Helvetica-Bold"),
+ ("FONTNAME", (0, 0), (0, 4), "FiraCode"),
("BACKGROUND", (1, 0), (1, 4), colors.Color(0.95, 0.97, 1.0)),
("TEXTCOLOR", (1, 0), (1, 4), colors.Color(0.2, 0.2, 0.2)),
- ("FONTNAME", (1, 0), (1, 4), "Helvetica"),
+ ("FONTNAME", (1, 0), (1, 4), "PlusJakartaSans"),
("ALIGN", (0, 0), (-1, -1), "LEFT"),
("VALIGN", (0, 0), (-1, -1), "TOP"),
("FONTSIZE", (0, 0), (-1, -1), 11),
@@ -433,43 +439,6 @@ def generate_threatscore_report(
)
elements.append(info_table)
- elements.append(Spacer(1, 0.2 * inch))
- elements.append(PageBreak())
-
- elements.append(Paragraph("Requirements Index", h1))
-
- sections = {}
- for req in resp_attrs:
- meta = req["attributes"]["attributes"]["metadata"][0]
- section = meta["Section"]
- subsection = meta["SubSection"]
- req_id = req["id"]
- title = meta["Title"]
-
- if section not in sections:
- sections[section] = {}
- if subsection not in sections[section]:
- sections[section][subsection] = []
-
- sections[section][subsection].append({"id": req_id, "title": title})
-
- section_num = 1
- for section_name, subsections in sections.items():
- elements.append(Paragraph(f"{section_num}. {section_name}", h2))
-
- subsection_num = 1
- for subsection_name, requirements in subsections.items():
- elements.append(Paragraph(f"{subsection_name}", h3))
-
- req_num = 1
- for req in requirements:
- elements.append(Paragraph(f"{req['id']} - {req['title']}", normal))
- req_num += 1
-
- subsection_num += 1
-
- section_num += 1
- elements.append(Spacer(1, 0.1 * inch))
elements.append(PageBreak())
@@ -524,17 +493,17 @@ def generate_threatscore_report(
[
("BACKGROUND", (0, 0), (0, 1), colors.Color(0.3, 0.5, 0.7)),
("TEXTCOLOR", (0, 0), (0, 1), colors.white),
- ("FONTNAME", (0, 0), (0, 1), "Helvetica-Bold"),
+ ("FONTNAME", (0, 0), (0, 1), "FiraCode"),
("BACKGROUND", (0, 2), (0, 2), colors.Color(0.1, 0.3, 0.5)),
("TEXTCOLOR", (0, 2), (0, 2), colors.white),
- ("FONTNAME", (0, 2), (0, 2), "Helvetica-Bold"),
+ ("FONTNAME", (0, 2), (0, 2), "FiraCode"),
("FONTSIZE", (0, 2), (0, 2), 12),
("BACKGROUND", (1, 0), (1, 1), colors.Color(0.95, 0.97, 1.0)),
("TEXTCOLOR", (1, 0), (1, 1), colors.Color(0.2, 0.2, 0.2)),
- ("FONTNAME", (1, 0), (1, 1), "Helvetica"),
+ ("FONTNAME", (1, 0), (1, 1), "PlusJakartaSans"),
("BACKGROUND", (1, 2), (1, 2), compliance_color),
("TEXTCOLOR", (1, 2), (1, 2), colors.white),
- ("FONTNAME", (1, 2), (1, 2), "Helvetica-Bold"),
+ ("FONTNAME", (1, 2), (1, 2), "FiraCode"),
("FONTSIZE", (1, 2), (1, 2), 14),
("ALIGN", (0, 0), (-1, -1), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
@@ -552,6 +521,43 @@ def generate_threatscore_report(
elements.append(PageBreak())
+ elements.append(Paragraph("Requirements Index", h1))
+
+ sections = {}
+ for req in resp_attrs:
+ meta = req["attributes"]["attributes"]["metadata"][0]
+ section = meta["Section"]
+ subsection = meta["SubSection"]
+ req_id = req["id"]
+ title = meta["Title"]
+
+ if section not in sections:
+ sections[section] = {}
+ if subsection not in sections[section]:
+ sections[section][subsection] = []
+
+ sections[section][subsection].append({"id": req_id, "title": title})
+
+ section_num = 1
+ for section_name, subsections in sections.items():
+ elements.append(Paragraph(f"{section_num}. {section_name}", h2))
+
+ subsection_num = 1
+ for subsection_name, requirements in subsections.items():
+ elements.append(Paragraph(f"{subsection_name}", h3))
+
+ req_num = 1
+ for req in requirements:
+ elements.append(Paragraph(f"{req['id']} - {req['title']}", normal))
+ req_num += 1
+
+ subsection_num += 1
+
+ section_num += 1
+ elements.append(Spacer(1, 0.1 * inch))
+
+ elements.append(PageBreak())
+
elements.append(Paragraph("Top Requirements by Level of Risk", h1))
elements.append(Spacer(1, 0.1 * inch))
elements.append(
@@ -622,18 +628,18 @@ def generate_threatscore_report(
[
("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"),
+ ("FONTNAME", (0, 0), (-1, 0), "FiraCode"),
("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"),
+ ("FONTNAME", (0, 1), (0, -1), "FiraCode"),
("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"),
+ ("FONTNAME", (1, 1), (1, -1), "FiraCode"),
+ ("FONTNAME", (2, 1), (2, -1), "FiraCode"),
("FONTSIZE", (2, 1), (2, -1), 9),
- ("FONTNAME", (3, 1), (-1, -1), "Helvetica"),
+ ("FONTNAME", (3, 1), (-1, -1), "PlusJakartaSans"),
("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)),
@@ -684,7 +690,7 @@ def generate_threatscore_report(
spaceAfter=10,
leftIndent=20,
rightIndent=20,
- fontName="Helvetica",
+ fontName="PlusJakartaSans",
backColor=colors.Color(1.0, 0.95, 0.95),
borderWidth=2,
borderColor=colors.Color(0.8, 0.2, 0.2),
@@ -816,7 +822,7 @@ def generate_threatscore_report(
colors.Color(0.2, 0.4, 0.6),
),
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
- ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
+ ("FONTNAME", (0, 0), (-1, 0), "FiraCode"),
("ALIGN", (0, 0), (0, 0), "CENTER"),
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
("FONTSIZE", (0, 0), (-1, -1), 9),
@@ -839,7 +845,17 @@ def generate_threatscore_report(
elements.append(PageBreak())
- doc.build(elements)
+ def add_footer(canvas: canvas.Canvas, doc):
+ width, height = doc.pagesize
+ page_num_text = f"Page {doc.page}"
+ canvas.setFont("PlusJakartaSans", 9)
+ canvas.setFillColorRGB(0.4, 0.4, 0.4)
+ canvas.drawString(30, 20, page_num_text)
+ powered_text = "Powered by Prowler"
+ text_width = canvas.stringWidth(powered_text, "PlusJakartaSans", 9)
+ canvas.drawString(width - text_width - 30, 20, powered_text)
+
+ doc.build(elements, onFirstPage=add_footer, onLaterPages=add_footer)
if __name__ == "__main__":