Skip to main content

wafrift_wafmodel/
error.rs

1//! Error type for the WAF-decompilation engine.
2
3/// Anything that can go wrong while decompiling, mining, or hardening.
4#[derive(Debug, thiserror::Error)]
5pub enum WafModelError {
6    /// The oracle could not be queried (transport, timeout, etc.).
7    #[error("oracle query failed: {0}")]
8    Oracle(String),
9
10    /// The learner exhausted its membership-query budget before the
11    /// hypothesis stabilized. Carries the budget that was spent so the
12    /// caller can decide to raise it rather than trust a partial model.
13    #[error("learning budget exhausted after {queries} membership queries (hypothesis unstable)")]
14    BudgetExhausted {
15        /// Membership queries spent before giving up.
16        queries: u64,
17    },
18
19    /// A learned-model artifact failed to (de)serialize or its schema
20    /// version is not understood by this build.
21    #[error("model artifact error: {0}")]
22    Artifact(String),
23
24    /// A regex shipped in a Tier-B ruleset failed to compile.
25    #[error("Tier-B rule {rule} has an invalid pattern: {source}")]
26    BadRule {
27        /// The offending rule id.
28        rule: String,
29        /// The underlying regex compile error.
30        #[source]
31        source: regex::Error,
32    },
33
34    /// The equivalence oracle's UCB bandit was asked to draw a
35    /// counterexample word but the search space was empty — the
36    /// hypothesis has zero states, or the alphabet has zero symbols.
37    /// Neither is a valid input; the caller must supply a non-trivial
38    /// automaton and a non-empty alphabet.
39    #[error(
40        "UCB bandit equivalence oracle: search space is empty \
41         (state cover is empty or alphabet has zero symbols). \
42         Supply a non-trivial hypothesis and a non-empty alphabet."
43    )]
44    EmptySearchSpace,
45
46    /// The L\* observation table was found to be non-closed while
47    /// building a hypothesis. Pre-R51 this surfaced as a panic (the
48    /// `.expect("table closed ⇒ …")` call sites in build_hypothesis).
49    /// A WAF that returns non-deterministic oracle answers (load-
50    /// balanced cluster with inconsistent rule sets, mid-scan rule
51    /// reload, etc.) can push two identical prefixes to different
52    /// rows and trip this invariant. R51 pass-13 I3 (CLAUDE.md §15).
53    #[error(
54        "L* observation table is not closed at hypothesis-build time \
55         — likely caused by a non-deterministic oracle (WAF cluster, \
56         mid-scan rule reload). Retry with a stable target or raise \
57         the query budget."
58    )]
59    TableNotClosed,
60}
61
62/// Convenience alias used throughout the crate.
63pub type Result<T> = std::result::Result<T, WafModelError>;