wafrift-evolution 0.2.3

Genetic algorithm engine, differential analysis, intelligence feedback loop, and WAF-aware advisor.
Documentation
//! Build script: compile community-contributed differential probes
//! (`rules/probes/differential.toml`) into a Rust source file.

use serde::Deserialize;
use std::fs;
use std::path::Path;

#[derive(Deserialize)]
struct ProbesFile {
    baseline_payload: String,
    baseline_description: String,
    sql_keywords: Vec<String>,
    sql_operators: Vec<String>,
    sql_comments: Vec<String>,
    sql_tautologies: Vec<String>,
    #[serde(default)]
    xss_tag: Vec<TagOrFn>,
    xss_events: Vec<String>,
    #[serde(default)]
    xss_function: Vec<TagOrFn>,
    command_separators: Vec<String>,
    command_names: Vec<String>,
    command_paths: Vec<String>,
}

#[derive(Deserialize)]
struct TagOrFn {
    name: String,
    payload: String,
    expected_blocked: bool,
}

fn emit_str_array(out: &mut String, name: &str, values: &[String]) {
    out.push_str(&format!("pub(crate) const {name}: &[&str] = &[\n"));
    for v in values {
        out.push_str(&format!("    {:?},\n", v));
    }
    out.push_str("];\n\n");
}

fn emit_tagfn_array(out: &mut String, name: &str, values: &[TagOrFn]) {
    out.push_str(&format!(
        "pub(crate) const {name}: &[(&str, &str, bool)] = &[\n"
    ));
    for e in values {
        out.push_str(&format!(
            "    ({:?}, {:?}, {}),\n",
            e.name, e.payload, e.expected_blocked
        ));
    }
    out.push_str("];\n\n");
}

fn main() {
    let in_path = Path::new("rules/probes/differential.toml");
    let out_dir = std::env::var("OUT_DIR").unwrap();
    let out_path = Path::new(&out_dir).join("differential_data.rs");

    let raw =
        fs::read_to_string(in_path).unwrap_or_else(|e| panic!("read {}: {e}", in_path.display()));
    let parsed: ProbesFile =
        toml::from_str(&raw).unwrap_or_else(|e| panic!("parse {}: {e}", in_path.display()));

    let mut out = String::with_capacity(8192);
    out.push_str(
        "// Auto-generated by build.rs from rules/probes/differential.toml — do not edit.\n\n",
    );
    out.push_str(&format!(
        "pub(crate) const BASELINE_PAYLOAD: &str = {:?};\n",
        parsed.baseline_payload
    ));
    out.push_str(&format!(
        "pub(crate) const BASELINE_DESCRIPTION: &str = {:?};\n\n",
        parsed.baseline_description
    ));

    emit_str_array(&mut out, "SQL_KEYWORDS", &parsed.sql_keywords);
    emit_str_array(&mut out, "SQL_OPERATORS", &parsed.sql_operators);
    emit_str_array(&mut out, "SQL_COMMENTS", &parsed.sql_comments);
    emit_str_array(&mut out, "SQL_TAUTOLOGIES", &parsed.sql_tautologies);
    emit_tagfn_array(&mut out, "XSS_TAGS", &parsed.xss_tag);
    emit_str_array(&mut out, "XSS_EVENTS", &parsed.xss_events);
    emit_tagfn_array(&mut out, "XSS_FUNCTIONS", &parsed.xss_function);
    emit_str_array(&mut out, "COMMAND_SEPARATORS", &parsed.command_separators);
    emit_str_array(&mut out, "COMMAND_NAMES", &parsed.command_names);
    emit_str_array(&mut out, "COMMAND_PATHS", &parsed.command_paths);

    fs::write(&out_path, out).expect("write differential_data.rs");
    println!("cargo::rerun-if-changed={}", in_path.display());
}