tokmd-analysis 1.10.0

Analysis logic and enrichers for tokmd receipts.
Documentation
use std::path::PathBuf;

use crate::entropy::build_entropy_report;
use tempfile::tempdir;
use tokmd_analysis_types::AnalysisLimits;
use tokmd_analysis_types::EntropyClass;
use tokmd_types::{ChildIncludeMode, ExportData, FileKind, FileRow};

#[path = "../../../tests/support/crypto.rs"]
mod crypto;

fn export_for_paths(paths: &[&str]) -> ExportData {
    let rows = paths
        .iter()
        .map(|path| FileRow {
            path: (*path).to_string(),
            module: path
                .rsplit_once('/')
                .map(|(module, _)| module)
                .unwrap_or("(root)")
                .to_string(),
            lang: "Binary".to_string(),
            kind: FileKind::Parent,
            code: 1,
            comments: 0,
            blanks: 0,
            lines: 1,
            bytes: 10,
            tokens: 2,
        })
        .collect();

    ExportData {
        rows,
        module_roots: vec![],
        module_depth: 2,
        children: ChildIncludeMode::Separate,
    }
}

#[test]
fn synthetic_private_key_bytes_are_reproducible() {
    let first = crypto::synthetic_private_key_bytes(crypto::label::ENTROPY_PRIMARY);
    let second = crypto::synthetic_private_key_bytes(crypto::label::ENTROPY_PRIMARY);
    let different = crypto::synthetic_private_key_bytes(crypto::label::ENTROPY_ALTERNATE);

    assert_eq!(first, second);
    assert_ne!(first, different);
}

#[test]
fn entropy_report_detects_synthetic_private_key_fixture() {
    let dir = tempdir().expect("tempdir should be created");
    let relative_path = crypto::GENERATED_PRIVATE_KEY_RELATIVE_PATH;
    crypto::write_generated_private_key(dir.path(), crypto::label::ENTROPY_REPORT)
        .expect("synthetic fixture bytes should be written");

    let export = export_for_paths(&[relative_path]);
    let files = vec![PathBuf::from(relative_path)];
    let report = build_entropy_report(dir.path(), &files, &export, &AnalysisLimits::default())
        .expect("entropy report should be built");

    assert_eq!(report.suspects.len(), 1);

    let suspect = &report.suspects[0];
    assert_eq!(suspect.path, relative_path);
    assert_eq!(suspect.module, "fixtures/generated");
    assert!(
        suspect.entropy_bits_per_byte > 7.0,
        "generated fixture should be strongly entropic, got {}",
        suspect.entropy_bits_per_byte
    );
    assert_eq!(suspect.class, EntropyClass::High);
}