keyhog-core 0.5.44

keyhog-core: shared data model and detector specifications for the KeyHog secret scanner
Documentation
use keyhog_core::PatternSpec;

fn pattern(regex: &str, literals: &[&str]) -> PatternSpec {
    PatternSpec {
        regex: regex.into(),
        required_literals: literals.iter().map(|literal| (*literal).into()).collect(),
        ..Default::default()
    }
}

#[test]
fn required_literals_prove_infix_and_required_repetition_routes() {
    pattern(
        r"[a-z][a-z0-9+.-]*://[^/@\s:]*:([^/@\s<>]{6,128})@[a-z0-9._-]",
        &["://"],
    )
    .validate_required_literals()
    .expect("URL scheme separator is required");
    pattern(r"(?:token_)+[A-Z0-9]{8}", &["token_"])
        .validate_required_literals()
        .expect("one-or-more repetition requires its literal");
}

#[test]
fn required_literal_alternatives_must_cover_every_regex_branch() {
    pattern(
        r"(?:alpha_key|beta_key)[A-Z0-9]{8}",
        &["alpha_key", "beta_key"],
    )
    .validate_required_literals()
    .expect("the OR-set covers both branches");
    let error = pattern(r"(?:alpha_key|public)[A-Z0-9]{8}", &["alpha_key"])
        .validate_required_literals()
        .expect_err("one uncovered branch makes the routing claim unsound");
    assert!(error.contains("necessary OR-condition"));
}

#[test]
fn optional_duplicate_empty_and_non_ascii_required_literals_are_rejected() {
    for (candidate, expected) in [
        (
            pattern(r"(?:token_)?[A-Z0-9]{8}", &["token_"]),
            "necessary OR-condition",
        ),
        (
            pattern(r"token_[A-Z0-9]{8}", &["token_", "TOKEN_"]),
            "duplicate",
        ),
        (pattern(r"token_[A-Z0-9]{8}", &[""]), "non-empty ASCII"),
        (pattern(r"tök_[A-Z0-9]{8}", &["tök_"]), "non-empty ASCII"),
    ] {
        let error = candidate
            .validate_required_literals()
            .expect_err("invalid routing literal declaration must fail closed");
        assert!(
            error.contains(expected),
            "{error:?} did not contain {expected:?}"
        );
    }
}