pub struct DetectorSpec {Show 46 fields
pub id: String,
pub name: String,
pub service: String,
pub severity: Severity,
pub kind: DetectorKind,
pub ml: DetectorMlPolicySpec,
pub match_confidence: Option<DetectorMatchConfidenceSpec>,
pub validators: Vec<DetectorValidatorSpec>,
pub decode_transforms: DetectorDecodeTransformSpec,
pub patterns: Vec<PatternSpec>,
pub companions: Vec<CompanionSpec>,
pub verify: Option<VerifySpec>,
pub keywords: Vec<String>,
pub simdsieve_prefixes: Vec<String>,
pub min_confidence: Option<f64>,
pub entropy_floor: Vec<EntropyFloorBucket>,
pub entropy_high: Option<f64>,
pub entropy_low: Option<f64>,
pub entropy_very_high: Option<f64>,
pub entropy_fallback: Option<EntropyFallbackMetadata>,
pub entropy_fallback_confidence: Option<EntropyFallbackConfidenceSpec>,
pub generic_assignment_confidence: Option<GenericAssignmentConfidenceSpec>,
pub entropy_roles: Vec<EntropyDetectionRole>,
pub sensitive_path_entropy_very_high: Option<f64>,
pub entropy_shapes: Vec<EntropyShapeSpec>,
pub plausibility: Option<DetectorPlausibilityPolicySpec>,
pub entropy_policy_priority: Option<u16>,
pub bpe_max_bytes_per_token: Option<f64>,
pub bpe_enabled: Option<bool>,
pub decoded_hex_key_material_lengths: Vec<usize>,
pub canonical_hex_key_material: Vec<CanonicalHexKeyMaterialSpec>,
pub keyword_free_min_len: Option<usize>,
pub min_len: Option<usize>,
pub max_len: Option<usize>,
pub generic_vendor_suffixes: Vec<String>,
pub generic_assignment_tail_suffixes: Vec<String>,
pub allowlist_paths: Vec<String>,
pub allowlist_values: Vec<String>,
pub stopwords: Vec<String>,
pub public_identifier_assignment_markers: Vec<String>,
pub structural_password_slot: bool,
pub weak_anchor: bool,
pub private_key_block: bool,
pub resolution_priority: i16,
pub credential_shape: Option<CredentialShape>,
pub tests: Vec<DetectorTestSpec>,
}Expand description
A complete detector definition loaded from a TOML file.
Fields§
§id: StringUnique stable identifier (e.g. `aws-access-key`).
name: StringHuman-readable name.
service: StringTarget service (e.g. `aws`, `stripe`).
severity: SeverityDefault severity for findings.
kind: DetectorKindWhat scan phase produces this detector’s findings, and thus what the
loader requires of it. Defaults to DetectorKind::Regex. A regex
detector carries >=1 regex pattern and fires in phase 1. A
phase2-generic detector is a shapeless-secret bridge: bare passwords
and high-entropy blobs fire in phase 2 from keywords plus
entropy_floor. It may also declare structured regex envelopes while
keeping both paths under one detector owner. Modeled here so those
detectors are first-class TOML specs, one home for every knob, instead
of engine constants scattered across detector_ids.rs and policy files.
ml: DetectorMlPolicySpecDetector-owned policy for model scoring. The model implementation is a
shared engine, but whether this detector invokes it, how model and
structural evidence combine, and how much source context is extracted
are properties of the secret type and therefore live in its TOML.
TOML detectors must declare it. Programmatic DetectorSpec::default()
disables both model paths until the caller chooses a policy.
match_confidence: Option<DetectorMatchConfidenceSpec>Detector-owned scoring policy for regex matches. Every signal weight, entropy tier, penalty, structural floor, and low-promise result is compiled into the detector execution plan.
validators: Vec<DetectorValidatorSpec>Detector-owned offline validation policy. Each entry declares both the validator primitive and every detector-specific parameter it needs. Shared scanner code supplies the primitive implementations, but it must not own token prefixes, field widths, confidence floors, or shape rules.
decode_transforms: DetectorDecodeTransformSpecDetector-owned admission policy for asymmetric evasion transforms. Shared decoders implement reverse and Caesar recovery, while each detector declares the literal prefixes that make those transforms eligible. Empty lists disable the corresponding transform for this detector. The compiled scanner unions only the declarations in its active corpus, so a custom corpus never inherits unrelated prefixes.
patterns: Vec<PatternSpec>List of regex patterns to match. Defaults to empty so a
kind = "phase2-generic" detector can omit it when it has no structured
envelope; a kind = "regex" detector with no patterns is rejected by
the quality gate (validate_patterns_present), so this default never
silently ships a dead regex detector.
companions: Vec<CompanionSpec>Secondary patterns required to confirm a match.
verify: Option<VerifySpec>Live verification configuration.
keywords: Vec<String>High-performance pre-filtering keywords.
simdsieve_prefixes: Vec<String>Literal prefixes eligible for the optional simdsieve first-pass
accelerator. Each prefix must be non-empty ASCII, unique in the loaded
corpus, and an actual literal prefix of one of this detector’s patterns.
Empty means this detector does not participate in that accelerator.
min_confidence: Option<f64>Self-declared per-detector confidence floor, in [0.0, 1.0].
When set, findings from THIS detector use this floor instead of the
global --min-confidence / [scan].min_confidence. A detector with a
distinctive vendor prefix (e.g. sourcegraph sgp_<40hex>, cursor
key_<64hex>) is high-confidence by virtue of the prefix even when the
body is low-entropy hex that the generic confidence model scores below
the global floor; the detector author declares that here so the
detector ships working out of the box. Costs nothing at scan time
it is a single O(1) map lookup at the post-scan floor gate, on an
already-compiled corpus. An operator .keyhog.toml
[detector.<id>] min_confidence still overrides this self-declared
default. None (the default) means “use the global floor”.
entropy_floor: Vec<EntropyFloorBucket>Per-detector low-entropy suppression floor, owned HERE in the detector’s
own TOML, the single source of truth for generic and weak-anchor entropy
gates (there is no separate rules/entropy-floors.toml, no code table,
no cross-detector policy borrowing). Length-bucketed: the FIRST bucket whose
max_len >= L sets the floor for a candidate of length L; the last
bucket omits max_len and is the catch-all. max_len must strictly
increase. A generic-detector candidate whose Shannon entropy is BELOW the
applicable floor is suppressed. Active entropy owners must declare at
least one bucket.
entropy_high: Option<f64>Per-detector HIGH-entropy threshold (bits/byte), the keyword-independent bar. Active entropy owners must declare it.
entropy_low: Option<f64>Per-detector keyword-context (LOW) entropy threshold (bits/byte). Active entropy owners must declare it.
entropy_very_high: Option<f64>Per-detector VERY-high entropy threshold for keyword-free/isolated tokens. Active entropy owners must declare it.
entropy_fallback: Option<EntropyFallbackMetadata>Metadata used when this detector owns a synthetic entropy finding. Keeping the semantic class, emitted id, display name, and service beside the owning detector prevents scanner-side identity tables from drifting away from detector policy. Active entropy owners must declare it; a missing block is a compile-time configuration error, never a guessed scanner identity.
entropy_fallback_confidence: Option<EntropyFallbackConfidenceSpec>Detector-owned confidence tiers for synthetic entropy findings. The entropy engine supplies shared Shannon scoring, while each owning detector declares how that evidence maps to report confidence.
generic_assignment_confidence: Option<GenericAssignmentConfidenceSpec>Detector-owned confidence policy for phase-two generic assignments. Context bases and evidence lifts compile with the detector that owns the assignment keyword.
entropy_roles: Vec<EntropyDetectionRole>Corpus-level entropy roles owned by this detector. Roles make the shared entropy engine data-driven: it resolves keyword-free, isolated-bare, and unclaimed-keyword candidates from detector TOML instead of naming built-in detector IDs in scanner code. Each role may be claimed by at most one detector in a compiled corpus.
sensitive_path_entropy_very_high: Option<f64>Per-detector keyword-free entropy threshold used for clearly sensitive
paths. Active entropy owners must declare it; setting it lower than
entropy_very_high is an explicit recall policy for files such as .env
and secrets manifests, not a scanner-wide hidden discount.
entropy_shapes: Vec<EntropyShapeSpec>Detector-owned isolated entropy shapes. These are explicit structural exceptions to the broad keyword-free floor, such as a four-group lower-dash app password. Active entropy owners must declare the list.
plausibility: Option<DetectorPlausibilityPolicySpec>Complete detector-owned strict plausibility policy. Active entropy owners must declare the block; absence is valid only for detector paths that never invoke phase-2 plausibility scoring.
entropy_policy_priority: Option<u16>Precedence when this detector owns entropy-fallback policy for one of its declared keywords. Active entropy owners must declare the value; regex detectors opt in by doing so. Higher values win overlapping keyword claims, so the policy decision is declared in detector TOML instead of depending on detector IDs or load order.
bpe_max_bytes_per_token: Option<f64>Per-detector BPE token-efficiency ceiling in UTF-8 bytes per
cl100k_base token. Candidates above the ceiling are word-like and are
suppressed after the cheaper entropy/shape gates. BPE-enabled entropy
owners must declare it; an explicit scan override still has precedence.
bpe_enabled: Option<bool>Whether the BPE token-efficiency precision gate applies to this
detector. Active entropy owners must declare the choice. Some(false)
disables tokenization for detector families such as human-chosen
passwords where word-like values are legitimate. A disabled detector
must not also set a BPE ceiling.
decoded_hex_key_material_lengths: Vec<usize>Exact printable-hex character counts this phase-2 detector may retain after transport decoding. Keeping the lengths in detector TOML avoids a scanner-wide hardcoded key-width list. An empty list retains no decoded digest-shaped values.
canonical_hex_key_material: Vec<CanonicalHexKeyMaterialSpec>Detector-owned canonical pure-hex key material. Phase-2 generic
detectors scope lengths to exact assignment keywords or vendor
suffixes. Regex detectors use length-only entries because their own
matched pattern is already the anchor. This keeps digest-shaped recall
exceptions in detector TOML instead of a scanner-wide length table.
keyword_free_min_len: Option<usize>Per-detector minimum length for an anchor-free (keyword-free/isolated) candidate. Active entropy owners must declare it.
min_len: Option<usize>Per-detector minimum candidate length in UTF-8 bytes (any candidate this detector emits). Active entropy owners must declare it.
max_len: Option<usize>Per-detector maximum byte length for generic assignment values owned by
this entropy policy, including regex detectors that also claim generic
keywords through entropy_policy_priority.
Values above this ceiling are rejected whole; they are never truncated
into an apparently valid credential. Active phase-2 entropy owners must
declare it.
generic_vendor_suffixes: Vec<String>Structural assignment suffixes for <vendor>_<suffix> names not claimed
by an exact keyword. At most one phase-2 generic detector may declare a
non-empty list; omission disables unlisted vendor suffixes.
generic_assignment_tail_suffixes: Vec<String>Optional suffix segments accepted after an exact assignment keyword. At most one phase-2 generic detector may declare a non-empty list.
allowlist_paths: Vec<String>Per-detector path-exclusion regexes (betterleaks-style allowlist): a match whose FILE PATH matches any of these is suppressed. Owned per detector.
allowlist_values: Vec<String>Per-detector value-exclusion regexes: a matched SECRET VALUE matching any of these is suppressed (per-detector test/example/placeholder demotion).
stopwords: Vec<String>Per-detector literal stopwords: a matched value equal to / containing any of these (case-insensitive) is suppressed. Owned per detector.
public_identifier_assignment_markers: Vec<String>Uppercase assignment-key fragments that identify public IDs rather than
credentials for this detector’s entropy path. Runtime matching is ASCII
case-insensitive without allocating a normalized source line, so boundary
bytes such as =, :, space, and quote are semantic. An empty list
disables this detector-local suppression. TOML stores canonical uppercase.
structural_password_slot: boolPer-detector “structural password slot” classification, OWNED HERE per the architecture law above (was a hardcoded detector-id list in scanner code, so a detector’s family lived outside its TOML).
true marks a STRONG-anchor detector whose regex proves a syntactic
credential SLOT (scheme://user:<x>@host, IDENTIFIED BY '<x>',
--password <x>, Bearer <x>) but captures a FREE-FORM value the way a
real password is written. Such detectors apply the password-slot
placeholder gate (drop a captured literal dictionary word like password
/ secret, or a low-letter-diversity mask like xxxxxxxx) that a
service-anchored detector’s structured capture never needs. A new
structural-password-slot detector now declares this in its own TOML, no
code edit (and the whole story lives in the detector file).
weak_anchor: boolPer-detector weak-anchor classification, owned by this detector definition.
true marks a SERVICE-anchored detector whose regex capture nonetheless
structurally collides with a generic value (a bare hex/base64 run the
vendor prefix does not tightly bound: alchemy-api-key, carbon-black-api-key,
flickr-api-key, …), so scanner suppression keeps the Tier-B shape gates
ENGAGED for it (WeakAnchorBase::Always) instead of trusting the anchor.
Without this the collision-prone captures would bypass the generic
shape/entropy floors and flood FP. The structural-password-slot family is
deliberately NOT weak_anchor (its slot is syntactic, not a vendor prefix).
A new weak-anchor detector now declares this in its own TOML, no code
edit (and the whole story lives in the detector file).
private_key_block: boolPer-detector private-key-block classification, owned by this detector definition.
true marks a detector whose match SPAN is an enclosing private-key block
(private-key, ssh-private-key, github-app-private-key), a multi-line
PEM/OpenSSH body. Resolution (resolution::suppress_matches_nested_in_private_key_blocks)
fully suppresses any lower-specificity child finding nested inside such a
span (an entropy/base64 hit on a line INSIDE the key body is not a second
secret). A new private-key-block detector now declares this in its own TOML
no code edit (and the whole story lives in the detector file).
resolution_priority: i16Explicit detector specificity used when overlapping findings compete.
Higher values win. The default 0 preserves equal standing; detectors
that intentionally wrap a broader detector declare their precedence here
instead of relying on detector ID spelling or input order.
credential_shape: Option<CredentialShape>Per-detector credential shape constraint (see CredentialShape), OWNED
HERE per the architecture law (was rules/detector-credential-shapes.toml).
None (the default) means the detector declares no shape constraint.
tests: Vec<DetectorTestSpec>Inline self-test fixtures ([[detector.tests]], Tier-B data): each entry
carries a positive example the detector MUST fire on and/or a negative
example it MUST NOT. Consumed by the contract/self-validate harness;
ignored at scan time. Modeled here (rather than silently dropped) so the
schema’s deny_unknown_fields typo-guard covers the whole detector file.
Implementations§
Source§impl DetectorSpec
impl DetectorSpec
Sourcepub fn owns_entropy_policy(&self) -> bool
pub fn owns_entropy_policy(&self) -> bool
Whether this detector supplies policy to the generic entropy engine.
Sourcepub fn introspection(&self) -> DetectorIntrospection<'_>
pub fn introspection(&self) -> DetectorIntrospection<'_>
Return the stable, redaction-safe declaration used by detector introspection surfaces.
The projection starts from DetectorSpec’s own serializer. Fields that
describe identity and matching stay at the top level; every other
declared field moves into policy. This means a newly added detector
field is included automatically instead of requiring a second manual
field list in each CLI surface. Inline fixture bytes are replaced with
positive/negative coverage booleans.
Sourcepub fn allows_decoded_hex_key_material(&self, value: &str) -> bool
pub fn allows_decoded_hex_key_material(&self, value: &str) -> bool
Whether this detector admits transport-decoded pure-hex key material at the exact declared character count.
Sourcepub fn allows_decoded_hex_key_material_len(
&self,
decoded_len: Option<usize>,
) -> bool
pub fn allows_decoded_hex_key_material_len( &self, decoded_len: Option<usize>, ) -> bool
Whether this detector admits a transport wrapper whose decoded payload is pure hex at the exact declared character count.
Sourcepub fn allows_canonical_hex_key_material(
&self,
keyword: &str,
value: &str,
) -> bool
pub fn allows_canonical_hex_key_material( &self, keyword: &str, value: &str, ) -> bool
Whether this detector’s canonical-hex policy admits an exact assignment key and pure-hex value pair.
Trait Implementations§
Source§impl Clone for DetectorSpec
impl Clone for DetectorSpec
Source§fn clone(&self) -> DetectorSpec
fn clone(&self) -> DetectorSpec
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for DetectorSpec
impl Debug for DetectorSpec
Source§impl Default for DetectorSpec
impl Default for DetectorSpec
Source§fn default() -> DetectorSpec
fn default() -> DetectorSpec
Source§impl<'de> Deserialize<'de> for DetectorSpec
impl<'de> Deserialize<'de> for DetectorSpec
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for DetectorSpec
impl RefUnwindSafe for DetectorSpec
impl Send for DetectorSpec
impl Sync for DetectorSpec
impl Unpin for DetectorSpec
impl UnsafeUnpin for DetectorSpec
impl UnwindSafe for DetectorSpec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more