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
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
78 lines
2.7 KiB
Rust
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)"
|
|
);
|
|
}
|