pub struct BuiltinSuite {
pub name: &'static str,
pub description: &'static str,
pub source: &'static str,
}
const SUITES: &[BuiltinSuite] = &[
BuiltinSuite {
name: "authentication",
description: "Login bypass, brute-force, and protected-route checks.",
source: include_str!("../suites/authentication.klr"),
},
BuiltinSuite {
name: "web",
description: "Reflected XSS and path traversal.",
source: include_str!("../suites/web.klr"),
},
BuiltinSuite {
name: "api",
description: "Input-injection fuzzing and rate limiting.",
source: include_str!("../suites/api.klr"),
},
BuiltinSuite {
name: "database",
description: "SQL-injection fuzzing and error-leak checks.",
source: include_str!("../suites/database.klr"),
},
BuiltinSuite {
name: "crypto",
description: "Secret and private-key exposure checks.",
source: include_str!("../suites/crypto.klr"),
},
BuiltinSuite {
name: "filesystem",
description: "Path-traversal and file-exposure checks.",
source: include_str!("../suites/filesystem.klr"),
},
];
pub fn get(name: &str) -> Option<&'static BuiltinSuite> {
let name = name.trim().to_ascii_lowercase();
SUITES.iter().find(|s| s.name.eq_ignore_ascii_case(&name))
}
pub fn all() -> &'static [BuiltinSuite] {
SUITES
}
#[cfg(test)]
mod tests {
use super::*;
use crate::klr::parse;
#[test]
fn all_builtin_suites_parse() {
for suite in all() {
let program = parse(suite.source)
.unwrap_or_else(|e| panic!("suite {} failed to parse: {e}", suite.name));
assert!(
!program.suites.is_empty() || !program.attacks.is_empty(),
"suite {} has no tests",
suite.name
);
}
}
#[test]
fn lookup_is_case_insensitive() {
assert!(get("AUTHENTICATION").is_some());
assert!(get("web").is_some());
assert!(get("nonexistent").is_none());
}
}