File size: 5,182 Bytes
214209a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""
PDF Report Generator — Generates LUMINA Mitigation Reports as PDF.

Uses fpdf2 (pure Python, no system dependencies) to produce
professional, branded PDF reports from mitigation report data.
"""

from fpdf import FPDF
from datetime import datetime
from typing import Dict, Any
import logging

logger = logging.getLogger(__name__)


class LuminaPDF(FPDF):
    """Custom PDF class with LUMINA branding."""

    def header(self):
        self.set_font("Helvetica", "B", 22)
        self.set_text_color(30, 41, 59)
        self.cell(0, 15, "LUMINA", new_x="LMARGIN", new_y="NEXT")
        self.set_font("Helvetica", "", 10)
        self.set_text_color(100, 116, 139)
        self.cell(0, 6, "Cyber Defense Platform  |  Mitigation Report", new_x="LMARGIN", new_y="NEXT")
        self.set_draw_color(59, 130, 246)
        self.set_line_width(0.5)
        self.line(10, self.get_y() + 3, 200, self.get_y() + 3)
        self.ln(10)

    def footer(self):
        self.set_y(-20)
        self.set_font("Helvetica", "I", 8)
        self.set_text_color(148, 163, 184)
        self.cell(
            0, 10,
            f"Generated on {datetime.utcnow().strftime('%Y-%m-%d %H:%M UTC')}  |  Page {self.page_no()}/{{nb}}  |  CONFIDENTIAL",
            align="C",
        )

    def section_title(self, title: str):
        self.ln(4)
        self.set_font("Helvetica", "B", 13)
        self.set_text_color(30, 41, 59)
        self.cell(0, 10, title, new_x="LMARGIN", new_y="NEXT")
        self.set_draw_color(226, 232, 240)
        self.line(10, self.get_y(), 200, self.get_y())
        self.ln(4)

    def body_text(self, text: str):
        self.set_font("Helvetica", "", 10)
        self.set_text_color(51, 65, 85)
        self.multi_cell(0, 6, text)
        self.ln(3)


def generate_mitigation_pdf(data: Dict[str, Any]) -> bytes:
    """Generate a PDF report from mitigation report data. Returns raw PDF bytes."""
    pdf = LuminaPDF()
    pdf.alias_nb_pages()
    pdf.add_page()
    pdf.set_auto_page_break(auto=True, margin=25)

    # Risk level colors
    risk_colors = {
        "CRITICAL": (239, 68, 68),
        "HIGH": (249, 115, 22),
        "MODERATE": (245, 158, 11),
        "LOW": (34, 197, 94),
    }

    # 1. Overall Risk Score
    risk_score = data.get("overall_risk_score", 0)
    risk_level = data.get("overall_risk_level", "UNKNOWN")
    color = risk_colors.get(risk_level, (100, 116, 139))

    pdf.set_font("Helvetica", "B", 16)
    pdf.set_text_color(*color)
    pdf.cell(0, 12, f"Overall Risk: {risk_score}/100  [{risk_level}]", new_x="LMARGIN", new_y="NEXT")
    pdf.ln(2)

    generated = data.get("generated_at", datetime.utcnow().isoformat())
    pdf.set_font("Helvetica", "", 9)
    pdf.set_text_color(148, 163, 184)
    pdf.cell(0, 6, f"Report generated: {generated}", new_x="LMARGIN", new_y="NEXT")
    pdf.ln(4)

    # 2. Executive Summary
    pdf.section_title("Executive Summary")
    pdf.body_text(data.get("executive_summary", "No summary available."))

    # 3. Threat Breakdown Table
    pdf.section_title("Threat Breakdown by Category")
    pdf.set_font("Helvetica", "B", 9)
    pdf.set_fill_color(241, 245, 249)
    pdf.set_text_color(51, 65, 85)

    col_widths = [35, 28, 28, 30, 28, 35]
    headers = ["Category", "Total", "High Risk", "Medium Risk", "Low Risk", "Trend"]
    for i, h in enumerate(headers):
        pdf.cell(col_widths[i], 8, h, border=1, fill=True, align="C")
    pdf.ln()

    pdf.set_font("Helvetica", "", 9)
    for row in data.get("threat_breakdown", []):
        pdf.cell(col_widths[0], 8, str(row.get("category", "")).title(), border=1)
        pdf.cell(col_widths[1], 8, str(row.get("total_incidents", 0)), border=1, align="C")
        pdf.cell(col_widths[2], 8, str(row.get("high_risk_count", 0)), border=1, align="C")
        pdf.cell(col_widths[3], 8, str(row.get("medium_risk_count", 0)), border=1, align="C")
        pdf.cell(col_widths[4], 8, str(row.get("low_risk_count", 0)), border=1, align="C")
        trend = str(row.get("trend", "stable")).title()
        pdf.cell(col_widths[5], 8, trend, border=1, align="C")
        pdf.ln()
    pdf.ln(4)

    # 4. Mitigation Recommendations
    pdf.section_title("Mitigation Recommendations")
    priority_colors = {
        "critical": (239, 68, 68),
        "high": (249, 115, 22),
        "medium": (245, 158, 11),
        "low": (34, 197, 94),
    }

    for i, rec in enumerate(data.get("recommendations", []), 1):
        priority = rec.get("priority", "medium")
        p_color = priority_colors.get(priority, (100, 116, 139))

        pdf.set_font("Helvetica", "B", 10)
        pdf.set_text_color(*p_color)
        pdf.cell(0, 8, f"{i}. [{priority.upper()}] {rec.get('title', '')}", new_x="LMARGIN", new_y="NEXT")

        pdf.set_font("Helvetica", "", 9)
        pdf.set_text_color(71, 85, 105)
        category = rec.get("category", "")
        desc = rec.get("description", "")
        pdf.multi_cell(0, 5, f"    Category: {category}  |  {desc}")
        pdf.ln(3)

    # 5. Risk Trend Analysis
    pdf.section_title("Risk Trend Analysis")
    pdf.body_text(data.get("risk_trend_analysis", "Insufficient data for trend analysis."))

    return pdf.output()