cc_audit/reporter/
json.rs1use 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}