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