Skip to main content

DetectorSpec

Struct DetectorSpec 

Source
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: String

Unique stable identifier (e.g. `aws-access-key`).

§name: String

Human-readable name.

§service: String

Target service (e.g. `aws`, `stripe`).

§severity: Severity

Default severity for findings.

§kind: DetectorKind

What 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: DetectorMlPolicySpec

Detector-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: DetectorDecodeTransformSpec

Detector-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: bool

Per-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: bool

Per-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: bool

Per-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: i16

Explicit 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

Source

pub fn owns_entropy_policy(&self) -> bool

Whether this detector supplies policy to the generic entropy engine.

Source

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.

Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> DetectorSpec

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DetectorSpec

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DetectorSpec

Source§

fn default() -> DetectorSpec

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for DetectorSpec

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for DetectorSpec

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more