Files
talos/backend/app/export.py
T
ilia 12a6e2b6bc
CI / skip-ci-check (push) Successful in 8s
CI / secret-scan (push) Successful in 7s
CI / python-ci (push) Failing after 19s
Initial commit: Talos edge-facing scan orchestrator.
FastAPI + Kali tools UI for authorized scans of levkin.ca / LAN targets.
Gitignore local data/.env; add pytest + gitleaks CI.
2026-07-12 11:46:54 -04:00

149 lines
5.2 KiB
Python

"""Bulk scan report rendering for Cursor and other consumers."""
from __future__ import annotations
from typing import Any
_SEVERITY_ORDER = ("critical", "high", "medium", "low", "info")
_PHASE_OUTPUT_MAX = 4000
def _sort_findings(findings: list[dict[str, Any]]) -> list[dict[str, Any]]:
order = {s: i for i, s in enumerate(_SEVERITY_ORDER)}
return sorted(findings, key=lambda f: order.get(str(f.get("severity", "")).lower(), 99))
def _truncate(text: str, limit: int = _PHASE_OUTPUT_MAX) -> str:
text = (text or "").strip()
if len(text) <= limit:
return text
return text[: limit - 40] + "\n\n… (truncated)"
def render_bulk_markdown(payload: dict[str, Any], *, for_cursor: bool = False) -> str:
bulk = payload["bulk"]
scans = payload["scans"]
lines: list[str] = []
if for_cursor:
lines.extend(
[
"<!-- Talos bulk report — paste into Cursor for triage / remediation -->",
"",
"You are reviewing authorized security scan results from Talos.",
"Prioritize critical/high findings, then failed phases that may hide issues.",
"",
]
)
lines.extend(
[
f"# Talos bulk report",
"",
f"- **Bulk ID:** `{bulk['id']}`",
f"- **Profile:** {bulk['profile']}",
f"- **Status:** {bulk['status']}",
f"- **Progress:** {bulk['complete']}/{bulk['total']} complete"
+ (f", {bulk['failed']} failed" if bulk.get("failed") else "")
+ (f", {bulk['running']} running" if bulk.get("running") else "")
+ (f", {bulk['queued']} queued" if bulk.get("queued") else ""),
"",
]
)
# Cross-target finding rollup (severity >= low with issues)
all_findings: list[tuple[str, dict[str, Any]]] = []
for entry in scans:
target = entry["scan"]["target"]
for f in entry.get("findings") or []:
if f.get("severity") in ("critical", "high", "medium", "low"):
all_findings.append((target, f))
if all_findings:
lines.append("## Findings rollup (all targets)")
lines.append("")
for target, f in sorted(
all_findings,
key=lambda x: _SEVERITY_ORDER.index(x[1]["severity"])
if x[1]["severity"] in _SEVERITY_ORDER
else 99,
):
sev = f["severity"].upper()
lines.append(f"- **[{sev}]** `{target}` — {f['title']}")
lines.append("")
for entry in scans:
scan = entry["scan"]
phases = entry.get("phases") or []
findings = _sort_findings(entry.get("findings") or [])
lines.append(f"## {scan['target']}")
lines.append("")
lines.append(f"- Scan ID: `{scan['id']}`")
lines.append(f"- Status: **{scan['status']}**")
if scan.get("llm_unavailable"):
lines.append("- LLM analysis was unavailable for some phases")
lines.append("")
lines.append("### Phases")
lines.append("")
lines.append("| Phase | Status | Tool |")
lines.append("|-------|--------|------|")
for p in phases:
lines.append(f"| {p['name']} | {p['status']} | {p.get('tool', '')} |")
lines.append("")
failed_phases = [p for p in phases if p["status"] in ("failed", "blocked", "inconclusive")]
if failed_phases:
lines.append("### Phase notes (non-complete)")
lines.append("")
for p in failed_phases:
snippet = _truncate(p.get("raw_output") or "", 800)
lines.append(f"**{p['name']}** ({p['status']})")
if snippet:
lines.append("")
lines.append("```")
lines.append(snippet)
lines.append("```")
lines.append("")
if findings:
lines.append("### Findings")
lines.append("")
for f in findings:
sev = str(f["severity"]).upper()
lines.append(f"#### [{sev}] {f['title']}")
lines.append("")
lines.append(f["description"])
lines.append("")
if f.get("evidence"):
lines.append(f"**Evidence:** `{_truncate(str(f['evidence']), 500)}`")
lines.append("")
lines.append(f"**Recommendation:** {f['recommendation']}")
lines.append("")
else:
lines.append("_No LLM findings recorded._")
lines.append("")
lines.append("---")
lines.append("")
return "\n".join(lines).rstrip() + "\n"
def render_bulk_json(payload: dict[str, Any]) -> dict[str, Any]:
"""JSON export with truncated phase output to keep size reasonable."""
out = dict(payload)
scans_out: list[dict[str, Any]] = []
for entry in payload.get("scans") or []:
entry = dict(entry)
phases = []
for p in entry.get("phases") or []:
p = dict(p)
if p.get("raw_output"):
p["raw_output"] = _truncate(str(p["raw_output"]))
phases.append(p)
entry["phases"] = phases
scans_out.append(entry)
out["scans"] = scans_out
return out