struct

PassiveScan::Matcher

Inherits Struct < Value < Object

Constants

ALLOWED_CONDITIONS = {"and", "or"}
ALLOWED_TYPES = {"word", "regex"}
NEWLINE_TOKEN = /\\[sWDRvnNX]|\[\^|\\x\{?0*[aA]\b|\\0?12\b|\\o\{|\\cJ|\\p\{|\(\?[a-z]*s|\n/

A token that can match \n: \s, a negated class, \n itself, …

NO_FILE_GATE = /\\[AzZG]|\(\*/

Constructs that make a whole-file gate unsound: absolute anchors (\A \z \Z \G) hold only at the file's edges, not each line's, and a (*VERB) can change newline handling or matching outright. A pattern carrying one gets no gate and is left to the per-line loop.

Lookarounds, atomic groups and possessive quantifiers keep the plain gate: at a line edge they see the \n where the per-line match sees the end of the string, which only differs for a construct that reaches across the newline — and treating them as gate-less made a gitleaks-style (?<![A-Za-z0-9])…(?![A-Za-z0-9]) rule set walk every line of every file.

UNION_UNSAFE = /\\[1-9gk]|\(\?P=|\(\?[+-]?\d|\(\?R|\(\?\(|\(\?[a-zA-Z^-]*x/

Constructs Regex.union changes the meaning of. The union renumbers capture groups, so a \1, \g{1}, (?1) or (?(1)…) in any pattern but the first points at the wrong group; and under (?x) a # comment runs to the end of the joined source and swallows the union's closing parens, so the whole rule failed to compile. Over-matching here (an escaped \\1) only costs the union fast path.

Constructors

new(yaml : YAML::Any)
Source

Class methods

line_anchored?(pattern : String) : Bool

True when pattern has an unescaped ^ or $ outside a character class. A misread here only costs a MULTILINE gate, which still accepts every line the pattern can match.

Source
newline_negative_lookaround?(pattern : String) : Bool

True when a negative lookaround in pattern can match a newline. At a line's end the per-line match sees end-of-string where the whole-file gate sees \n and the next line, so key(?!\s*=\s*null) fires on the line key but the gate rejects key\n= null and the rule never runs. Over-matching here only costs the gate.

Source

Instance methods

compiled_regex

or: the single union every pattern is folded into, or nil when the patterns cannot share one (see UNION_UNSAFE) and are matched one by one through compiled_regexes instead.

Source
compiled_regex=(compiled_regex : Regex | Nil)

or: the single union every pattern is folded into, or nil when the patterns cannot share one (see UNION_UNSAFE) and are matched one by one through compiled_regexes instead.

Source
compiled_regexes

One compiled regex per pattern, under either condition.

Source
compiled_regexes=(compiled_regexes : Array(Regex) | Nil)

One compiled regex per pattern, under either condition.

Source
condition
Source
condition=(condition : String)
Source
patterns
Source
patterns=(patterns : Array(YAML::Any))
Source
regex_compile_failed?

True when this matcher's regexes failed to compile. detect.cr checks it to short-circuit instead of retrying the (already-broken) compilation on every line.

Source
regex_error

Why this matcher's regexes failed to compile, or nil when they compiled. Held as the message rather than a bare flag so the loader can name the pattern in the warning it prints — the previous shape wrote the reason straight to Crystal's global Log, whose default backend is STDOUT, so it landed in the middle of -f json / -f sarif output and broke every downstream parser.

Source
regex_match?(content : String, options : Regex::MatchOptions = Regex::MatchOptions::None) : Bool

Whether a regex matcher fires on content (a line, as detect.cr calls it). Shared with the false-positive gate so both agree on what fired.

Source
regex_may_match_file?(content : String, options : Regex::MatchOptions = Regex::MatchOptions::None) : Bool

Whole-file form of regex_match?: false only when no line of content can satisfy this matcher.

Source
string_patterns

Pre-stringified patterns. detect.cr's hot path used to call pattern.to_s per (file × line × matcher); the conversion is the same every call so we do it once at load time.

Source
string_patterns=(string_patterns : Array(String))

Pre-stringified patterns. detect.cr's hot path used to call pattern.to_s per (file × line × matcher); the conversion is the same every call so we do it once at load time.

Source
type
Source
type=(type : String)
Source
valid?
Source
validation_errors
Source
word_regex

word patterns as escaped literal regexes: one union for or, one regex per pattern for and. A literal regex matches exactly where String#includes? does, and PCRE2 (with Noir::TextFile::MATCH_OPTIONS) scans a whole file far faster than includes?'s rolling hash, which restarts per pattern.

Source
word_regexes
Source