Skip to content

Commit 62278e8

Browse files
author
Carlos
committed
Remove dead HTML branches from report generator, expose public API in reports/__init__.py
- Strip 5 dead HTML else-branches from _render_* functions (Jinja2 now handles all HTML rendering) - Expose generate_report, IncidentReport, check_compliance, and evidence functions in reports/__init__.py - Clean up import sorting
1 parent ee1a827 commit 62278e8

2 files changed

Lines changed: 68 additions & 103 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
11
"""Report generation module for AgentForensics."""
2+
3+
from agentforensics.reports.compliance import check_compliance
4+
from agentforensics.reports.evidence import compute_evidence_hash, create_chain_entry, get_chain, verify_chain
5+
from agentforensics.reports.generator import generate_report
6+
from agentforensics.reports.incident import IncidentReport
7+
8+
__all__ = [
9+
"generate_report",
10+
"IncidentReport",
11+
"check_compliance",
12+
"compute_evidence_hash",
13+
"create_chain_entry",
14+
"get_chain",
15+
"verify_chain",
16+
]

src/agentforensics/reports/generator.py

Lines changed: 53 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -136,128 +136,78 @@ def _render_html(**ctx: Any) -> str:
136136

137137

138138
def _render_timeline_table(events: list[dict[str, Any]], fmt: str) -> str:
139+
"""Render a timeline table in markdown format (HTML uses Jinja2)."""
139140
if not events:
140-
return "No events recorded.\n" if fmt == "markdown" else "<p>No events recorded.</p>"
141-
142-
lines: list[str] = []
143-
if fmt == "markdown":
144-
lines.append("| # | Source | Severity | Event | Timestamp | Risk |")
145-
lines.append("|---|---|---|---|---|---|")
146-
for i, ev in enumerate(events[:50], 1):
147-
sev = ev.get("severity", "?")
148-
title = (ev.get("title") or ev.get("event_type") or "?")[:60]
149-
ts = ev.get("timestamp", "?")[:19]
150-
risk = f"{float(ev.get('risk_score', 0)):.1f}"
151-
src = ev.get("source", "?")
152-
lines.append(f"| {i} | {src} | {sev} | {title} | {ts} | {risk} |")
153-
if len(events) > 50:
154-
lines.append(f"| ... | *{len(events) - 50} more events* | | | | |")
155-
else:
156-
lines.append(
157-
"<table><tr><th>#</th><th>Source</th><th>Severity</th><th>Event</th><th>Timestamp</th><th>Risk</th></tr>"
158-
)
159-
for i, ev in enumerate(events[:50], 1):
160-
sev = ev.get("severity", "?")
161-
css = f" severity-{sev}" if sev in ("critical", "high", "medium", "low") else ""
162-
title = (ev.get("title") or ev.get("event_type") or "?")[:60]
163-
ts = ev.get("timestamp", "?")[:19]
164-
risk = f"{float(ev.get('risk_score', 0)):.1f}"
165-
src = ev.get("source", "?")
166-
lines.append(
167-
f'<tr><td>{i}</td><td>{src}</td><td class="{css.strip()}">{sev}</td><td>{title}</td><td>{ts}</td><td>{risk}</td></tr>'
168-
)
169-
if len(events) > 50:
170-
lines.append(f"<tr><td colspan='6'><em>… {len(events) - 50} more events</em></td></tr>")
171-
lines.append("</table>")
141+
return "No events recorded.\n"
142+
143+
lines: list[str] = [
144+
"| # | Source | Severity | Event | Timestamp | Risk |",
145+
"|---|---|---|---|---|---|",
146+
]
147+
for i, ev in enumerate(events[:50], 1):
148+
title = (ev.get("title") or ev.get("event_type") or "?")[:60]
149+
ts = ev.get("timestamp", "?")[:19]
150+
risk = f"{float(ev.get('risk_score', 0)):.1f}"
151+
lines.append(f"| {i} | {ev.get('source', '?')} | {ev.get('severity', '?')} | {title} | {ts} | {risk} |")
152+
if len(events) > 50:
153+
lines.append(f"| ... | *{len(events) - 50} more events* | | | | |")
172154
return "\n".join(lines)
173155

174156

175157
def _render_correlation_summary(groups: list[dict[str, Any]], fmt: str) -> str:
158+
"""Render correlation summary in markdown format (HTML uses Jinja2)."""
176159
if not groups:
177-
return "No correlated event groups.\n" if fmt == "markdown" else "<p>No correlated event groups.</p>"
178-
179-
lines: list[str] = []
180-
if fmt == "markdown":
181-
lines.append(f"**{len(groups)} correlated group(s) found**\n")
182-
for g in groups[:10]:
183-
lines.append(
184-
f"- Window: {g['window_start'][:19]}{g['window_end'][:19]} | "
185-
f"{g['event_count']} events | Risk: {g['max_risk']:.1f} | "
186-
f"Sources: {', '.join(g['sources'])}"
187-
)
188-
if len(groups) > 10:
189-
lines.append(f"- … {len(groups) - 10} more groups")
190-
else:
191-
lines.append(f"<p><strong>{len(groups)} correlated group(s) found</strong></p><ul>")
192-
for g in groups[:10]:
193-
lines.append(
194-
f"<li>{g['window_start'][:19]}{g['window_end'][:19]} — "
195-
f"{g['event_count']} events, risk {g['max_risk']:.1f} "
196-
f"({', '.join(g['sources'])})</li>"
197-
)
198-
if len(groups) > 10:
199-
lines.append(f"<li>… {len(groups) - 10} more groups</li>")
200-
lines.append("</ul>")
160+
return "No correlated event groups.\n"
161+
162+
lines: list[str] = [f"**{len(groups)} correlated group(s) found**\n"]
163+
for g in groups[:10]:
164+
lines.append(
165+
f"- Window: {g['window_start'][:19]}{g['window_end'][:19]} | "
166+
f"{g['event_count']} events | Risk: {g['max_risk']:.1f} | "
167+
f"Sources: {', '.join(g['sources'])}"
168+
)
169+
if len(groups) > 10:
170+
lines.append(f"- … {len(groups) - 10} more groups")
201171
return "\n".join(lines)
202172

203173

204174
def _render_deviations(deviations: list[dict[str, Any]], fmt: str) -> str:
175+
"""Render deviations in markdown format (HTML uses Jinja2)."""
205176
if not deviations:
206-
return "No policy deviations detected.\n" if fmt == "markdown" else "<p>No policy deviations detected.</p>"
207-
208-
lines: list[str] = []
209-
if fmt == "markdown":
210-
lines.append(f"**{len(deviations)} deviation(s) found**\n")
211-
for d in deviations:
212-
lines.append(f"- **[{d['type']}]** {d['description']}")
213-
else:
214-
lines.append(f"<p><strong>{len(deviations)} deviation(s) found</strong></p>")
215-
for d in deviations:
216-
lines.append(f'<div class="deviation"><strong>[{d["type"]}]</strong> {d["description"]}</div>')
177+
return "No policy deviations detected.\n"
178+
179+
lines: list[str] = [f"**{len(deviations)} deviation(s) found**\n"]
180+
for d in deviations:
181+
lines.append(f"- **[{d['type']}]** {d['description']}")
217182
return "\n".join(lines)
218183

219184

220185
def _render_anomalies(anomalies: list[dict[str, Any]], fmt: str) -> str:
186+
"""Render anomalies in markdown format (HTML uses Jinja2)."""
221187
if not anomalies:
222-
return "No anomalies detected.\n" if fmt == "markdown" else "<p>No anomalies detected.</p>"
223-
224-
lines: list[str] = []
225-
if fmt == "markdown":
226-
lines.append(f"**{len(anomalies)} anomaly(ies) found**\n")
227-
for a in anomalies:
228-
sev = a.get("severity", "?")
229-
score = f" (score: {a.get('score', 0):.1f})"
230-
lines.append(f"- **[severity: {sev}]{score}** {a['description']}")
231-
else:
232-
lines.append(f"<p><strong>{len(anomalies)} anomaly(ies) found</strong></p>")
233-
for a in anomalies:
234-
sev = a.get("severity", "?")
235-
lines.append(f'<div class="anomaly"><strong>[{sev}]</strong> {a["description"]}</div>')
188+
return "No anomalies detected.\n"
189+
190+
lines: list[str] = [f"**{len(anomalies)} anomaly(ies) found**\n"]
191+
for a in anomalies:
192+
sev = a.get("severity", "?")
193+
score = f" (score: {a.get('score', 0):.1f})"
194+
lines.append(f"- **[severity: {sev}]{score}** {a['description']}")
236195
return "\n".join(lines)
237196

238197

239198
def _render_evidence(evidence_chain: list[dict[str, Any]], fmt: str) -> str:
199+
"""Render evidence in markdown format (HTML uses Jinja2)."""
240200
if not evidence_chain:
241-
return "No evidence collected.\n" if fmt == "markdown" else "<p>No evidence collected.</p>"
242-
243-
lines: list[str] = []
244-
if fmt == "markdown":
245-
lines.append(f"**{len(evidence_chain)} evidence entries**\n")
246-
lines.append("| ID | Hash | Collector | Timestamp |")
247-
lines.append("|---|---|---|---|")
248-
for e in evidence_chain:
249-
h = e.get("hash", "?")[:16]
250-
lines.append(
251-
f"| {e.get('evidence_id', '?')} | {h}… | {e.get('collector', '?')} | {e.get('timestamp', '?')[:19]} |"
252-
)
253-
else:
254-
lines.append(f"<p><strong>{len(evidence_chain)} evidence entries</strong></p><table>")
255-
lines.append("<tr><th>ID</th><th>Hash</th><th>Collector</th><th>Timestamp</th></tr>")
256-
for e in evidence_chain:
257-
h = e.get("hash", "?")[:16]
258-
lines.append(
259-
f"<tr><td>{e.get('evidence_id', '?')}</td><td>{h}…</td><td>{e.get('collector', '?')}</td>"
260-
f"<td>{e.get('timestamp', '?')[:19]}</td></tr>"
261-
)
262-
lines.append("</table>")
201+
return "No evidence collected.\n"
202+
203+
lines: list[str] = [
204+
f"**{len(evidence_chain)} evidence entries**\n",
205+
"| ID | Hash | Collector | Timestamp |",
206+
"|---|---|---|---|",
207+
]
208+
for e in evidence_chain:
209+
h = e.get("hash", "?")[:16]
210+
lines.append(
211+
f"| {e.get('evidence_id', '?')} | {h}… | {e.get('collector', '?')} | {e.get('timestamp', '?')[:19]} |"
212+
)
263213
return "\n".join(lines)

0 commit comments

Comments
 (0)