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.iter().filter(|e| !e.verify_integrity()).count();
100        let integrity_verified = integrity_failures == 0;
101
102        let mut findings = Vec::new();
103
104        // SOX Section 404 - Internal Controls
105        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        // Integrity failures
115        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        // Critical events requiring review
128        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    /// Generate PCI-DSS compliance report
156    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        // PCI-DSS Requirement 10.2 - Audit trail for all access
186        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        // PCI-DSS Requirement 10.5 - Log integrity
197        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        // PCI-DSS Requirement 10.6 - Daily log review
207        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    /// Generate GLBA compliance report
235    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        // GLBA Safeguards Rule - Access controls
265        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    /// Export report as JSON
299    pub fn export_json(report: &ComplianceReport) -> Result<String, serde_json::Error> {
300        serde_json::to_string_pretty(report)
301    }
302
303    /// Export report as CSV summary
304    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}