KeiSeiKit-1.0/_primitives/_rust/kei-leak-matrix/tests/scan_fixtures.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

167 lines
5.9 KiB
Rust

//! Scanner integration tests.
//!
//! Tests use a synthetic in-test matrix written to a temp file. We do NOT
//! echo any real SSoT pattern. Test fixtures use clearly-test-only tokens
//! (TESTONLY_* prefixes) that the SSoT matrix does not list.
//!
//! Where we cross-check the real SSoT matrix, we reference rules by `id`
//! only — never by pattern source.
use kei_leak_matrix::{scan_file, scan_string, Matrix, Scope, Severity};
use std::io::Write;
use tempfile::NamedTempFile;
/// Build a tiny test matrix on disk and return the loaded Matrix.
/// Patterns below are TEST-ONLY tokens, intentionally distinct from any
/// SSoT pattern, so this fixture cannot accidentally leak IP-bearing regex.
fn build_test_matrix() -> (NamedTempFile, Matrix) {
let toml = r#"
[[rule]]
id = "test-block-alpha"
pattern = "TESTONLY_BLOCK_ALPHA"
category = "secret"
severity = "block"
scope = ["all-writes", "public-mirror"]
rationale = "test-only block rule"
added = "2026-04-26"
[[rule]]
id = "test-warn-beta"
pattern = "TESTONLY_WARN_BETA"
category = "secret"
severity = "warn"
scope = ["public-mirror"]
rationale = "test-only warn rule"
added = "2026-04-26"
[[rule]]
id = "test-sub-gamma"
pattern = "TESTONLY_SUB_GAMMA"
substitute_with = "REDACTED"
category = "personal"
severity = "substitute"
scope = ["public-mirror"]
rationale = "test-only substitute rule"
added = "2026-04-26"
[[rule]]
id = "test-scoped-only-commit"
pattern = "TESTONLY_COMMIT_ONLY"
category = "secret"
severity = "block"
scope = ["commit-msg"]
rationale = "test-only commit-msg rule"
added = "2026-04-26"
"#;
let mut f = NamedTempFile::new().expect("tmp file");
f.write_all(toml.as_bytes()).expect("write");
f.flush().expect("flush");
let m = Matrix::load(f.path()).expect("matrix loads");
(f, m)
}
#[test]
fn loads_and_compiles_all_test_rules() {
let (_f, m) = build_test_matrix();
assert_eq!(m.rules.len(), 4);
let ids: Vec<&str> = m.rules.iter().map(|r| r.id.as_str()).collect();
assert!(ids.contains(&"test-block-alpha"));
assert!(ids.contains(&"test-warn-beta"));
assert!(ids.contains(&"test-sub-gamma"));
assert!(ids.contains(&"test-scoped-only-commit"));
}
#[test]
fn scan_string_finds_block_violation_by_id() {
let (_f, m) = build_test_matrix();
// Synthetic content that triggers the block rule.
let content = "line one\nfoo TESTONLY_BLOCK_ALPHA bar\nline three\n";
let v = scan_string(&m, content, Scope::AllWrites, None, "syn");
assert_eq!(v.len(), 1, "exactly one violation");
assert_eq!(v[0].rule_id, "test-block-alpha");
assert_eq!(v[0].line, 2);
assert_eq!(v[0].severity, "block");
}
#[test]
fn scan_string_redacts_match_to_12_chars_plus_ellipsis() {
let (_f, m) = build_test_matrix();
let content = "TESTONLY_BLOCK_ALPHA";
let v = scan_string(&m, content, Scope::AllWrites, None, "syn");
assert_eq!(v.len(), 1);
// Exactly 12 chars + ellipsis when source longer than 12.
let chars: Vec<char> = v[0].matched_redacted.chars().collect();
assert_eq!(chars.len(), 13, "12 + ellipsis");
assert_eq!(chars.last(), Some(&'…'));
}
#[test]
fn scope_filter_excludes_non_matching_scope() {
let (_f, m) = build_test_matrix();
// test-scoped-only-commit only applies to commit-msg.
let content = "x TESTONLY_COMMIT_ONLY y";
let v = scan_string(&m, content, Scope::PublicMirror, None, "syn");
assert_eq!(v.len(), 0, "commit-msg-only rule must not fire on public-mirror");
let v2 = scan_string(&m, content, Scope::CommitMsg, None, "syn");
assert_eq!(v2.len(), 1);
assert_eq!(v2[0].rule_id, "test-scoped-only-commit");
}
#[test]
fn all_writes_scope_matches_every_request() {
let (_f, m) = build_test_matrix();
// test-block-alpha has scope all-writes — matches both PublicMirror and AllWrites.
let content = "x TESTONLY_BLOCK_ALPHA y";
let v_pm = scan_string(&m, content, Scope::PublicMirror, None, "syn");
let v_aw = scan_string(&m, content, Scope::AllWrites, None, "syn");
assert_eq!(v_pm.len(), 1);
assert_eq!(v_aw.len(), 1);
}
#[test]
fn severity_filter_narrows_to_block_only() {
let (_f, m) = build_test_matrix();
let content = "TESTONLY_BLOCK_ALPHA TESTONLY_WARN_BETA TESTONLY_SUB_GAMMA";
let v_block = scan_string(&m, content, Scope::PublicMirror, Some(Severity::Block), "syn");
assert_eq!(v_block.len(), 1);
assert_eq!(v_block[0].rule_id, "test-block-alpha");
}
#[test]
fn severity_filter_narrows_to_warn_only() {
let (_f, m) = build_test_matrix();
let content = "TESTONLY_BLOCK_ALPHA TESTONLY_WARN_BETA TESTONLY_SUB_GAMMA";
let v_warn = scan_string(&m, content, Scope::PublicMirror, Some(Severity::Warn), "syn");
assert_eq!(v_warn.len(), 1);
assert_eq!(v_warn[0].rule_id, "test-warn-beta");
}
#[test]
fn scan_file_reads_path_and_finds_violations() {
let (_f, m) = build_test_matrix();
let mut tf = NamedTempFile::new().unwrap();
writeln!(tf, "first line").unwrap();
writeln!(tf, "TESTONLY_BLOCK_ALPHA on second").unwrap();
tf.flush().unwrap();
let v = scan_file(&m, tf.path(), Scope::AllWrites, None).expect("scan ok");
assert_eq!(v.len(), 1);
assert_eq!(v[0].rule_id, "test-block-alpha");
assert_eq!(v[0].line, 2);
}
#[test]
fn ssot_matrix_has_eleven_secret_rules() {
// Cross-check the real SSoT matrix: count secret-category rules.
// We never echo any pattern; we count by category alone.
let path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../../security/leak-matrix.toml");
if !path.exists() {
// Skip if the SSoT file isn't reachable from test harness path.
eprintln!("ssot path not present, skipping: {}", path.display());
return;
}
let m = Matrix::load(&path).expect("ssot matrix loads");
let secret_count = m.rules.iter()
.filter(|r| r.category == kei_leak_matrix::Category::Secret).count();
assert_eq!(secret_count, 11, "SSoT must contain 11 secret rules");
}