rust_secure_logger/
compliance.rs

1//! Compliance reporting for SOX, GLBA, PCI-DSS
2
3use crate::entry::{LogEntry, SecurityLevel};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7/// Compliance framework types
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9pub enum ComplianceFramework {
10    /// Sarbanes-Oxley Act - Financial reporting controls
11    SOX,
12    /// Gramm-Leach-Bliley Act - Financial privacy
13    GLBA,
14    /// Payment Card Industry Data Security Standard
15    PCIDSS,
16    /// HIPAA - Healthcare data privacy
17    HIPAA,
18    /// General Data Protection Regulation
19    GDPR,
20}
21
22/// Compliance report
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ComplianceReport {
25    /// Framework being reported on
26    pub framework: ComplianceFramework,
27    /// Report generation timestamp
28    pub generated_at: DateTime<Utc>,
29    /// Report period start
30    pub period_start: DateTime<Utc>,
31    /// Report period end
32    pub period_end: DateTime<Utc>,
33    /// Total events in period
34    pub total_events: usize,
35    /// Audit events (high importance)
36    pub audit_events: usize,
37    /// Security events
38    pub security_events: usize,
39    /// Critical events
40    pub critical_events: usize,
41    /// Integrity verification status
42    pub integrity_verified: bool,
43    /// Failed integrity checks
44    pub integrity_failures: usize,
45    /// Specific compliance findings
46    pub findings: Vec<ComplianceFinding>,
47}
48
49/// Individual compliance finding
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct ComplianceFinding {
52    /// Finding severity
53    pub severity: FindingSeverity,
54    /// Control area affected
55    pub control_area: String,
56    /// Description of finding
57    pub description: String,
58    /// Evidence (log entry IDs or samples)
59    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
70/// Compliance report generator
71pub struct ComplianceReporter;
72
73impl ComplianceReporter {
74    /// Generate SOX compliance report
75    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        // SOX Section 404 - Internal Controls
108        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        // Integrity failures
118        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        // Critical events requiring review
131        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    /// Generate PCI-DSS compliance report
159    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        // PCI-DSS Requirement 10.2 - Audit trail for all access
192        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        // PCI-DSS Requirement 10.5 - Log integrity
203        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        // PCI-DSS Requirement 10.6 - Daily log review
213        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    /// Generate GLBA compliance report
241    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        // GLBA Safeguards Rule - Access controls
274        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    /// Export report as JSON
308    pub fn export_json(report: &ComplianceReport) -> Result<String, serde_json::Error> {
309        serde_json::to_string_pretty(report)
310    }
311
312    /// Export report as CSV summary
313    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}