Skip to main content

agentox_core/report/
text.rs

1//! Colored terminal text report renderer.
2
3use crate::checks::types::Severity;
4use crate::report::types::AuditReport;
5use colored::*;
6
7/// Render an audit report as colored terminal text.
8pub fn render(report: &AuditReport) -> String {
9    let mut out = String::new();
10
11    // Header
12    out.push_str(&format!("\n{}\n", "AgentOx Audit Report".bold()));
13    out.push_str(&format!("Target: {}\n", report.target));
14    if let Some(info) = &report.server_info {
15        out.push_str(&format!(
16            "Server: {} v{}\n",
17            info.name,
18            info.version.as_deref().unwrap_or("?")
19        ));
20    }
21    out.push_str(&format!(
22        "Protocol: {}\n\n",
23        report.protocol_version.as_deref().unwrap_or("?")
24    ));
25
26    // Results
27    for result in &report.results {
28        let badge = if result.passed {
29            format!("[{}]", "PASS".green())
30        } else {
31            match result.severity {
32                Severity::Critical => format!("[{}]", "CRIT".red().bold()),
33                Severity::High => format!("[{}]", "HIGH".red()),
34                Severity::Medium => format!("[{}]", " MED".yellow()),
35                Severity::Low => format!("[{}]", " LOW".blue()),
36                Severity::Info => format!("[{}]", "INFO".dimmed()),
37                Severity::Pass => format!("[{}]", "PASS".green()),
38            }
39        };
40        out.push_str(&format!(
41            "{} {} {}\n",
42            badge,
43            result.check_id.dimmed(),
44            result.name
45        ));
46        if !result.passed {
47            out.push_str(&format!("      {}\n", result.message));
48        }
49    }
50
51    // Summary
52    out.push_str(&format!("\n{}\n", "Summary".bold()));
53    out.push_str(&format!(
54        "  Total: {}, Passed: {}, Failed: {}\n",
55        report.summary.total_checks,
56        report.summary.passed.to_string().green(),
57        if report.summary.failed > 0 {
58            report.summary.failed.to_string().red().to_string()
59        } else {
60            "0".to_string()
61        }
62    ));
63    out.push_str(&format!("  Duration: {}ms\n", report.summary.duration_ms));
64
65    out
66}