use std::{env, fs, path::Path};
use serde::Deserialize;
const CRITICAL_PATTERN_NAMES: &[&str] = &[
"AWS API Key", "AWS Access Key ID Value", "AWS MWS key", "AWS AppSync GraphQL Key", "Github App Token", "Github OAuth Access Token", "Github Personal Access Token", "Github Refresh Token", "Slack Token", "Slack Webhook", "Stripe API Key - 1", "Stripe Secret Live Key", "Stripe Restricted API Key", "Google API Key", "Google (GCP) Service Account", "Asymmetric Private Key", "Bearer token", "Twilio API Key", "SendGrid API Key", "PyPI upload token", "Alibaba - 2", ];
#[derive(Debug, Deserialize)]
struct PatternsFile {
patterns: Vec<PatternEntry>,
}
#[derive(Debug, Deserialize)]
struct PatternEntry {
pattern: Pattern,
}
#[derive(Debug, Deserialize)]
struct Pattern {
name: String,
regex: String,
confidence: String,
}
fn escape_string(s: &str) -> String {
let mut result = String::new();
for c in s.chars() {
match c {
'\\' => result.push_str("\\\\"),
'"' => result.push_str("\\\""),
'\n' => result.push_str("\\n"),
'\r' => result.push_str("\\r"),
'\t' => result.push_str("\\t"),
_ => result.push(c),
}
}
result
}
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("secrets_patterns_generated.rs");
let yaml_path = Path::new("src/vendor/rules-stable.yml");
if !yaml_path.exists() {
panic!(
"src/vendor/rules-stable.yml not found. \
Run: just vendor-update"
);
}
let yaml_content = fs::read_to_string(yaml_path).expect("Failed to read YAML file");
let patterns_file: PatternsFile =
serde_yml::from_str(&yaml_content).expect("Failed to parse YAML");
let mut critical_patterns = Vec::new();
let mut high_patterns = Vec::new();
let mut low_patterns = Vec::new();
for entry in patterns_file.patterns {
let name = escape_string(&entry.pattern.name);
let regex = escape_string(&entry.pattern.regex);
let tuple = format!("(\"{}\", \"{}\")", name, regex);
if CRITICAL_PATTERN_NAMES.contains(&entry.pattern.name.as_str()) {
critical_patterns.push(tuple);
continue;
}
match entry.pattern.confidence.as_str() {
"high" => high_patterns.push(tuple),
"low" => low_patterns.push(tuple),
other => eprintln!("cargo:warning=Unknown confidence level: {}", other),
}
}
let code = format!(
r#"// Auto-generated by build.rs - do not edit
pub const PATTERNS_CRITICAL: &[(&str, &str)] = &[
{}
];
pub const PATTERNS_HIGH: &[(&str, &str)] = &[
{}
];
pub const PATTERNS_LOW: &[(&str, &str)] = &[
{}
];
"#,
critical_patterns.join(",\n "),
high_patterns.join(",\n "),
low_patterns.join(",\n ")
);
fs::write(&dest_path, code).unwrap();
println!("cargo:rerun-if-changed=src/vendor/rules-stable.yml");
println!("cargo:rerun-if-changed=build.rs");
}