Files
Lucas RayanandClaude Sonnet 5 55e19a8e5b
CI / Format and clippy (push) Successful in 1m13s
CI / Dependency audit (push) Successful in 13s
CI / Tests (Linux) (push) Successful in 1m35s
Release / Create release (push) Successful in 7s
CI / Check desktop app (Linux) (push) Successful in 3m19s
Release / CLI (linux-aarch64) (push) Successful in 1m3s
Release / CLI (linux-x86_64) (push) Successful in 1m28s
Release / Desktop app (linux-aarch64) (push) Successful in 7m16s
Release / Desktop app (linux-x86_64) (push) Successful in 10m17s
Release / Desktop app (windows) (push) Successful in 4m54s
chore(i18n): finish translating code comments and scripts to English
Completes the English-only standardization for code, comments, scripts
and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en,
untouched). Covers the remaining crates/, apps/gui/ui/ and
apps/gui/src-tauri/ comments, .gitea/ workflow and template comments,
.githooks/ hooks, and the scripts/ source comments for the files
already renamed in a prior commit (check.sh, generate-logo.py,
install-hooks.sh).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
2026-10-30 20:44:39 -03:00

78 lines
2.7 KiB
Rust

//! 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<String> = 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)"
);
}