// Whac-a-Leak rule and configuration schema.
// This file and the rule files next to it are embedded in the whac binary.
// User layers in .whac/*.cue (package whac) are unified with them at load
// time; see .okfw/specs/rule-schema for the semantics. internal/rules/spec.go
// mirrors these definitions for decoding.
#Severity: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"
// A rule sample: plain text, or text with a file name. The file name picks
// the structural extractor, e.g. {file: "config.yaml", content: "..."}.
// Plain text is scanned as an unstructured text file.
#Sample: string | {file: string & !="", content: string}
#Charset: "hex" | "alnum" | "base64" | "base64url"
id: =~"^[A-Z][A-Z0-9_]*$"
description: string & !=""
kind: *"pattern" | "assignment"
severity: *"HIGH" | #Severity
// Literal keywords for the Aho-Corasick prefilter, matched
// case-insensitively. Pattern rules need at least one. An assignment rule
// runs on unstructured text only on lines that hold one of its keywords;
// without keywords it runs on structured files only.
keywords: [...(string & !="")]
// RE2 syntax (Go regexp). Required for pattern rules. For an assignment
// rule it is optional and runs on the value.
// Capture group holding the secret; 0 means the whole match.
secretGroup: *1 | (int & >=0)
// The engine evaluates the regex on each line that holds a keyword. Set
// multiline for secrets that span lines, such as PEM keys: the window then
// runs up to 64 KiB from the start of the keyword's line.
// Assignment rules: a regex on the last key segment and/or doublestar
// globs over the dotted key path ("**.credentials.password"). When a rule
// sets both, both must match. Path matching ignores case.
// Bits per character. When min is omitted, the engine derives a
// length- and charset-aware default (ADR-0006).
if min != _|_ if max != _|_ {max: >=min}
// Case-insensitive substrings that, when present in the secret, drop it.
stopwords: [...(string & !="")]
// Secrets matching any of these regexes are dropped.
allowRegexes: [...string]
// Each sample must produce a finding. Use obviously fake values.
mustMatch: [#Sample, ...#Sample]
// Each sample must produce no finding (often: matches the regex but
// is rejected by entropy, placeholders, stopwords or allowRegexes).
keywords: [string, ...string]
// Cheap author-side check under `cue vet`; the authoritative check
// runs every sample through the real engine (ADR-0009).
tests: mustMatch: [...((string & =~regex) | {file: string, content: =~regex})]
// Re-grading or disabling a rule from a layer. A rule's own severity is
// concrete, so it cannot be changed by unification; overrides can.
// Files larger than this many bytes are skipped.
maxFileSize: *2097152 | (int & >0)
// Doublestar globs → reason.
exclude: [Glob=string]: string & !=""
// Key-path globs → reason. The builtin SENSITIVE_PATH rule reports any
// value at these paths in structured files, even with low entropy.
sensitivePaths: [Glob=string]: string & !=""
// Agent-context preflight (ADR-0011): well-known credential files,
// relative to $HOME and to each --root. Keyed by ID, so layers can add
// entries or disable one with `enabled: false`.
credentialPaths: [ID=string]: #CredentialPath
// Reachable access to credentials, reported as exposure findings.
sshAgent: {severity: *"HIGH" | #Severity, enabled: *true | bool}
dockerSocket: {severity: *"CRITICAL" | #Severity, enabled: *true | bool}
// Runs only with --probe-imds: the one network request whac makes.
cloudMetadata: {severity: *"HIGH" | #Severity, enabled: *true | bool}
// Doublestar glob relative to the root, e.g. ".aws/sso/cache/*.json".
description: string & !=""
// Omit for every operating system.
os?: "linux" | "darwin" | "windows"
// Forces a structural extractor when the file name has no extension.
format?: "yaml" | "json" | "dotenv" | "properties" | "ini" | "hcl"
// Larger files are skipped. Shell histories need more than the default.
maxSize: *1048576 | (int & >0)
// whac1 fingerprint → reason. Only for false positives: real secrets
// get rotated, never allowlisted (ADR-0007).
fingerprints: [=~"^whac1:[0-9a-f]{64}$"]: string & !=""
// Doublestar path globs → reason.
paths: [Glob=string]: string & !=""
// Regexes over the secret → reason.
regexes: [Re=string]: string & !=""
rules: [ID=string]: #SecretRule & {id: ID}
overrides: [ID=string]: #Override