//! Integration test: hash-chained audit trail — appends entries, verifies //! chain integrity, then tampers with a middle record on disk and confirms //! verification pinpoints the corrupted entry. mod common; use sabia_core::audit::AuditLog; use std::io::Write; #[test] fn chain_validates_after_recording_entries() { let dir = tempfile::tempdir().expect("tempdir"); let path = dir.path().join("audit.log"); { let mut log = AuditLog::open(&path).expect("open"); log.record("monitor-on", "wlan0", "modo monitor ativado") .expect("record 1"); log.record("scan-start", "wlan0", "início da captura") .expect("record 2"); log.record("deauth", "00:11:22:33:44:55", "teste de deautenticação") .expect("record 3"); } let entries = AuditLog::read_entries(&path, None).expect("read_entries"); assert_eq!(entries.len(), 3); assert_eq!(entries[0].action, "monitor-on"); assert_eq!(entries[2].action, "deauth"); // each entry's `prev_hash` matches the preceding entry's `hash` assert_eq!(entries[1].prev_hash, entries[0].hash); assert_eq!(entries[2].prev_hash, entries[1].hash); let result = AuditLog::verify(&path).expect("verify"); assert_eq!( result, None, "cadeia íntegra não deve apontar entrada inválida" ); } #[test] fn tampering_with_an_entry_breaks_verification() { let dir = tempfile::tempdir().expect("tempdir"); let path = dir.path().join("audit.log"); { let mut log = AuditLog::open(&path).expect("open"); log.record("monitor-on", "wlan0", "modo monitor ativado") .expect("record 1"); log.record("scan-start", "wlan0", "início da captura") .expect("record 2"); log.record("scan-stop", "wlan0", "fim da captura") .expect("record 3"); } // Intact chain verifies cleanly. assert_eq!(AuditLog::verify(&path).expect("verify ok"), None); // Tamper with the second entry's `detail` field without recomputing its hash. // let contents = std::fs::read_to_string(&path).expect("read"); let mut lines: Vec = contents.lines().map(|l| l.to_string()).collect(); assert_eq!(lines.len(), 3); assert!(lines[1].contains("início da captura")); lines[1] = lines[1].replace("início da captura", "evento adulterado"); let mut file = std::fs::File::create(&path).expect("recreate"); for line in &lines { writeln!(file, "{line}").expect("write tampered line"); } let result = AuditLog::verify(&path).expect("verify"); assert_eq!( result, Some(1), "verificação deveria apontar a entrada adulterada (índice 1)" ); }