1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
10#[serde(rename_all = "snake_case")]
11pub enum Severity {
12 Critical,
13 #[default]
14 Warning,
15 Info,
16}
17
18impl std::fmt::Display for Severity {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 let s = match self {
21 Severity::Critical => "critical",
22 Severity::Warning => "warning",
23 Severity::Info => "info",
24 };
25 f.pad(s)
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31pub struct RuleInfo {
32 pub id: String,
34 pub severity: Severity,
36 pub description: String,
38}
39
40#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct Finding {
43 pub rule_id: String,
45 pub severity: Severity,
46 pub message: String,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub file: Option<String>,
50 pub location: Option<String>,
52}
53
54#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
56pub struct AuditSummary {
57 pub critical: usize,
58 pub warning: usize,
59 pub info: usize,
60 pub total: usize,
61}
62
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
65pub struct AuditReport {
66 pub findings: Vec<Finding>,
67 pub summary: AuditSummary,
68}
69
70impl AuditReport {
71 pub fn add(&mut self, f: Finding) {
73 match f.severity {
74 Severity::Critical => self.summary.critical += 1,
75 Severity::Warning => self.summary.warning += 1,
76 Severity::Info => self.summary.info += 1,
77 }
78 self.summary.total += 1;
79 self.findings.push(f);
80 }
81
82 pub fn is_clean(&self) -> bool {
84 self.findings.is_empty()
85 }
86}