Skip to main content

cc_audit/reporter/
json.rs

1use crate::reporter::Reporter;
2use crate::rules::ScanResult;
3
4pub struct JsonReporter;
5
6impl JsonReporter {
7    pub fn new() -> Self {
8        Self
9    }
10}
11
12impl Default for JsonReporter {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl Reporter for JsonReporter {
19    fn report(&self, result: &ScanResult) -> String {
20        serde_json::to_string_pretty(result)
21            .unwrap_or_else(|e| format!(r#"{{"error": "Failed to serialize result: {}"}}"#, e))
22    }
23}
24
25#[cfg(test)]
26mod tests {
27    use super::*;
28    use crate::rules::{Category, Severity};
29    use crate::test_utils::fixtures::{create_finding, create_test_result};
30
31    #[test]
32    fn test_json_output_structure() {
33        let reporter = JsonReporter::new();
34        let result = create_test_result(vec![]);
35        let output = reporter.report(&result);
36
37        let parsed: serde_json::Value = serde_json::from_str(&output).unwrap();
38        assert_eq!(parsed["version"], "0.2.0");
39        assert_eq!(parsed["target"], "./test-skill/");
40        assert!(parsed["summary"]["passed"].as_bool().unwrap());
41    }
42
43    #[test]
44    fn test_json_output_with_findings() {
45        let reporter = JsonReporter::new();
46        let mut finding = create_finding(
47            "EX-001",
48            Severity::Critical,
49            Category::Exfiltration,
50            "Test finding",
51            "test.sh",
52            10,
53        );
54        finding.code = "curl $SECRET".to_string();
55        let result = create_test_result(vec![finding]);
56        let output = reporter.report(&result);
57
58        let parsed: serde_json::Value = serde_json::from_str(&output).unwrap();
59        assert_eq!(parsed["findings"][0]["id"], "EX-001");
60        assert_eq!(parsed["findings"][0]["severity"], "critical");
61        assert_eq!(parsed["summary"]["critical"], 1);
62        assert!(!parsed["summary"]["passed"].as_bool().unwrap());
63    }
64
65    #[test]
66    #[allow(clippy::default_constructed_unit_structs)]
67    fn test_json_default_trait() {
68        let reporter = JsonReporter::default();
69        let result = create_test_result(vec![]);
70        let output = reporter.report(&result);
71        assert!(output.contains("\"passed\": true"));
72    }
73}