shellhist-forensic 0.1.0

Forensic anomaly auditor for shell command history — history clearing, timestamp regression, and download-pipe-to-shell as graded report::Finding, built on shellhist-core
Documentation
#![allow(clippy::unwrap_used, clippy::expect_used)]
//! End-to-end validation against a REAL bash history file, generated by an actual
//! `bash` subshell (not a synthetic fixture) — the Doer-Checker front door. The
//! generator command is recorded in `tests/data/README.md`.

use shellhist_core::parse_auto;
use shellhist_forensic::{audit, HistAnomaly};

const REAL_BASH: &[u8] = include_bytes!("../../tests/data/real_bash_history");

#[test]
fn real_bash_history_parses_with_timestamps() {
    let entries = parse_auto(REAL_BASH, Some(".bash_history"));
    assert!(!entries.is_empty(), "real history must yield entries");
    // bash wrote `#<epoch>` lines (HISTTIMEFORMAT was set) → every entry timestamped.
    assert!(
        entries.iter().all(|e| e.timestamp.is_some()),
        "every entry should carry an epoch"
    );
    assert!(entries.iter().any(|e| e.command == "ls -la /tmp"));
}

#[test]
fn real_bash_history_surfaces_its_planted_anomalies() {
    let entries = parse_auto(REAL_BASH, Some(".bash_history"));
    let codes: Vec<&str> = audit(&entries).iter().map(HistAnomaly::code).collect();
    // The generated session contains `curl … | sh` and `unset HISTFILE`.
    assert!(
        codes.contains(&"SHELLHIST-REMOTE-EXEC-PIPE"),
        "download-pipe-to-shell not detected in real history; got {codes:?}"
    );
    assert!(
        codes.contains(&"SHELLHIST-HISTORY-DISABLED"),
        "history-clearing not detected in real history; got {codes:?}"
    );
}