1use crate::entry::{LogEntry, SecurityLevel};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum ComplianceFramework {
10 SOX,
12 GLBA,
14 PCIDSS,
16 HIPAA,
18 GDPR,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ComplianceReport {
25 pub framework: ComplianceFramework,
27 pub generated_at: DateTime<Utc>,
29 pub period_start: DateTime<Utc>,
31 pub period_end: DateTime<Utc>,
33 pub total_events: usize,
35 pub audit_events: usize,
37 pub security_events: usize,
39 pub critical_events: usize,
41 pub integrity_verified: bool,
43 pub integrity_failures: usize,
45 pub findings: Vec<ComplianceFinding>,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ComplianceFinding {
52 pub severity: FindingSeverity,
54 pub control_area: String,
56 pub description: String,
58 pub evidence: Vec<String>,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
63pub enum FindingSeverity {
64 Low,
65 Medium,
66 High,
67 Critical,
68}
69
70pub struct ComplianceReporter;
72
73impl ComplianceReporter {
74 pub fn generate_sox_report(
76 entries: &[LogEntry],
77 period_start: DateTime<Utc>,
78 period_end: DateTime<Utc>,
79 ) -> ComplianceReport {
80 let filtered: Vec<_> = entries
81 .iter()
82 .filter(|e| e.timestamp >= period_start && e.timestamp <= period_end)
83 .collect();
84
85 let total_events = filtered.len();
86 let audit_events = filtered
87 .iter()
88 .filter(|e| e.level == SecurityLevel::Audit)
89 .count();
90 let security_events = filtered
91 .iter()
92 .filter(|e| e.level == SecurityLevel::SecurityEvent)
93 .count();
94 let critical_events = filtered
95 .iter()
96 .filter(|e| e.level == SecurityLevel::Critical)
97 .count();
98
99 let integrity_failures = filtered.iter().filter(|e| !e.verify_integrity()).count();
100 let integrity_verified = integrity_failures == 0;
101
102 let mut findings = Vec::new();
103
104 if audit_events == 0 {
106 findings.push(ComplianceFinding {
107 severity: FindingSeverity::High,
108 control_area: "SOX Section 404 - Audit Trail".to_string(),
109 description: "No audit trail events recorded during reporting period".to_string(),
110 evidence: vec![],
111 });
112 }
113
114 if integrity_failures > 0 {
116 findings.push(ComplianceFinding {
117 severity: FindingSeverity::Critical,
118 control_area: "SOX Section 404 - Data Integrity".to_string(),
119 description: format!(
120 "{} log entries failed integrity verification",
121 integrity_failures
122 ),
123 evidence: vec![],
124 });
125 }
126
127 if critical_events > 0 {
129 findings.push(ComplianceFinding {
130 severity: FindingSeverity::High,
131 control_area: "SOX Section 302 - Management Certification".to_string(),
132 description: format!(
133 "{} critical security events require management review",
134 critical_events
135 ),
136 evidence: vec![],
137 });
138 }
139
140 ComplianceReport {
141 framework: ComplianceFramework::SOX,
142 generated_at: Utc::now(),
143 period_start,
144 period_end,
145 total_events,
146 audit_events,
147 security_events,
148 critical_events,
149 integrity_verified,
150 integrity_failures,
151 findings,
152 }
153 }
154
155 pub fn generate_pci_report(
157 entries: &[LogEntry],
158 period_start: DateTime<Utc>,
159 period_end: DateTime<Utc>,
160 ) -> ComplianceReport {
161 let filtered: Vec<_> = entries
162 .iter()
163 .filter(|e| e.timestamp >= period_start && e.timestamp <= period_end)
164 .collect();
165
166 let total_events = filtered.len();
167 let audit_events = filtered
168 .iter()
169 .filter(|e| e.level == SecurityLevel::Audit)
170 .count();
171 let security_events = filtered
172 .iter()
173 .filter(|e| e.level == SecurityLevel::SecurityEvent)
174 .count();
175 let critical_events = filtered
176 .iter()
177 .filter(|e| e.level == SecurityLevel::Critical)
178 .count();
179
180 let integrity_failures = filtered.iter().filter(|e| !e.verify_integrity()).count();
181 let integrity_verified = integrity_failures == 0;
182
183 let mut findings = Vec::new();
184
185 if audit_events == 0 {
187 findings.push(ComplianceFinding {
188 severity: FindingSeverity::Critical,
189 control_area: "PCI-DSS Requirement 10.2".to_string(),
190 description: "Audit trail requirements not met - no access events logged"
191 .to_string(),
192 evidence: vec![],
193 });
194 }
195
196 if !integrity_verified {
198 findings.push(ComplianceFinding {
199 severity: FindingSeverity::Critical,
200 control_area: "PCI-DSS Requirement 10.5".to_string(),
201 description: "Log file integrity protection failure detected".to_string(),
202 evidence: vec![],
203 });
204 }
205
206 if security_events > 0 || critical_events > 0 {
208 findings.push(ComplianceFinding {
209 severity: FindingSeverity::Medium,
210 control_area: "PCI-DSS Requirement 10.6".to_string(),
211 description: format!(
212 "{} security events require daily review",
213 security_events + critical_events
214 ),
215 evidence: vec![],
216 });
217 }
218
219 ComplianceReport {
220 framework: ComplianceFramework::PCIDSS,
221 generated_at: Utc::now(),
222 period_start,
223 period_end,
224 total_events,
225 audit_events,
226 security_events,
227 critical_events,
228 integrity_verified,
229 integrity_failures,
230 findings,
231 }
232 }
233
234 pub fn generate_glba_report(
236 entries: &[LogEntry],
237 period_start: DateTime<Utc>,
238 period_end: DateTime<Utc>,
239 ) -> ComplianceReport {
240 let filtered: Vec<_> = entries
241 .iter()
242 .filter(|e| e.timestamp >= period_start && e.timestamp <= period_end)
243 .collect();
244
245 let total_events = filtered.len();
246 let audit_events = filtered
247 .iter()
248 .filter(|e| e.level == SecurityLevel::Audit)
249 .count();
250 let security_events = filtered
251 .iter()
252 .filter(|e| e.level == SecurityLevel::SecurityEvent)
253 .count();
254 let critical_events = filtered
255 .iter()
256 .filter(|e| e.level == SecurityLevel::Critical)
257 .count();
258
259 let integrity_failures = filtered.iter().filter(|e| !e.verify_integrity()).count();
260 let integrity_verified = integrity_failures == 0;
261
262 let mut findings = Vec::new();
263
264 let access_events = filtered
266 .iter()
267 .filter(|e| {
268 e.category.as_ref().is_some_and(|c| {
269 c.contains("authentication") || c.contains("access")
270 })
271 })
272 .count();
273
274 if access_events == 0 {
275 findings.push(ComplianceFinding {
276 severity: FindingSeverity::Medium,
277 control_area: "GLBA Safeguards Rule - Access Controls".to_string(),
278 description: "No access control events logged".to_string(),
279 evidence: vec![],
280 });
281 }
282
283 ComplianceReport {
284 framework: ComplianceFramework::GLBA,
285 generated_at: Utc::now(),
286 period_start,
287 period_end,
288 total_events,
289 audit_events,
290 security_events,
291 critical_events,
292 integrity_verified,
293 integrity_failures,
294 findings,
295 }
296 }
297
298 pub fn export_json(report: &ComplianceReport) -> Result<String, serde_json::Error> {
300 serde_json::to_string_pretty(report)
301 }
302
303 pub fn export_csv(report: &ComplianceReport) -> String {
305 let mut csv = String::from("Metric,Value\n");
306 csv.push_str(&format!("Framework,{:?}\n", report.framework));
307 csv.push_str(&format!("Generated At,{}\n", report.generated_at));
308 csv.push_str(&format!("Period Start,{}\n", report.period_start));
309 csv.push_str(&format!("Period End,{}\n", report.period_end));
310 csv.push_str(&format!("Total Events,{}\n", report.total_events));
311 csv.push_str(&format!("Audit Events,{}\n", report.audit_events));
312 csv.push_str(&format!("Security Events,{}\n", report.security_events));
313 csv.push_str(&format!("Critical Events,{}\n", report.critical_events));
314 csv.push_str(&format!(
315 "Integrity Verified,{}\n",
316 report.integrity_verified
317 ));
318 csv.push_str(&format!(
319 "Integrity Failures,{}\n",
320 report.integrity_failures
321 ));
322 csv.push_str(&format!("Total Findings,{}\n", report.findings.len()));
323 csv
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use super::*;
330
331 fn create_test_entries() -> Vec<LogEntry> {
332 vec![
333 LogEntry::new(SecurityLevel::Audit, "User login".to_string(), None),
334 LogEntry::new(SecurityLevel::Info, "System start".to_string(), None),
335 LogEntry::new_with_context(
336 SecurityLevel::SecurityEvent,
337 "Failed login".to_string(),
338 None,
339 None,
340 Some("authentication".to_string()),
341 ),
342 LogEntry::new(SecurityLevel::Critical, "Breach detected".to_string(), None),
343 ]
344 }
345
346 #[test]
347 fn test_sox_report_generation() {
348 let entries = create_test_entries();
349 let start = Utc::now() - chrono::Duration::hours(1);
350 let end = Utc::now();
351
352 let report = ComplianceReporter::generate_sox_report(&entries, start, end);
353
354 assert_eq!(report.framework, ComplianceFramework::SOX);
355 assert_eq!(report.total_events, 4);
356 assert_eq!(report.audit_events, 1);
357 assert_eq!(report.security_events, 1);
358 assert_eq!(report.critical_events, 1);
359 }
360
361 #[test]
362 fn test_pci_report_generation() {
363 let entries = create_test_entries();
364 let start = Utc::now() - chrono::Duration::hours(1);
365 let end = Utc::now();
366
367 let report = ComplianceReporter::generate_pci_report(&entries, start, end);
368
369 assert_eq!(report.framework, ComplianceFramework::PCIDSS);
370 assert!(report.integrity_verified);
371 }
372
373 #[test]
374 fn test_glba_report_generation() {
375 let entries = create_test_entries();
376 let start = Utc::now() - chrono::Duration::hours(1);
377 let end = Utc::now();
378
379 let report = ComplianceReporter::generate_glba_report(&entries, start, end);
380
381 assert_eq!(report.framework, ComplianceFramework::GLBA);
382 assert!(report.total_events > 0);
383 }
384
385 #[test]
386 fn test_json_export() {
387 let entries = create_test_entries();
388 let start = Utc::now() - chrono::Duration::hours(1);
389 let end = Utc::now();
390
391 let report = ComplianceReporter::generate_sox_report(&entries, start, end);
392 let json = ComplianceReporter::export_json(&report).unwrap();
393
394 assert!(json.contains("SOX"));
395 assert!(json.contains("total_events"));
396 }
397
398 #[test]
399 fn test_csv_export() {
400 let entries = create_test_entries();
401 let start = Utc::now() - chrono::Duration::hours(1);
402 let end = Utc::now();
403
404 let report = ComplianceReporter::generate_sox_report(&entries, start, end);
405 let csv = ComplianceReporter::export_csv(&report);
406
407 assert!(csv.contains("Framework,SOX"));
408 assert!(csv.contains("Total Events,4"));
409 }
410}