Deterministic host-side DLP detection: scan free text for US SSN and payment-card PAN (Luhn), returning fully-masked, structure-preserving findings with optional keyed-HMAC fingerprints. Pure, zero-I/O, regex-only; the caller supplies the key via a Fingerprinter. Detectors lifted from infrastructure-waf::pattern_detector.
| Tier | infrastructure |
| Role | unclassified (baselined) |
| Path | crates/infrastructure/dlp-detect |
| Edition | 2021 |
| Targets | infrastructure_dlp_detect |
| Public items | 24 across 2 modules |
| Tests | 105 |
What it is for
infrastructure-dlp-detect — deterministic host-side DLP detection.
Scans free text for US Social Security Numbers, payment-card PANs, and a set of format-shaped PII classes (phone, DOB, postal address, medical record number, case/docket number — added Sprint 3.8, see detectors.rs) and returns Findings that are fully masked (structure-preserving for the numeric classes; no digit survives) plus an optional keyed-HMAC fingerprint for dedup/correlation.
Design invariants (from sprint 2.5 Gate-1.5 consensus):
- Pure & zero-I/O.
regex+once_cellonly. No DB, no async, no network. - Fully masked by default (R2). Last-4 exposure is deliberately NOT offered
here; it belongs behind RBAC in the consuming module.
- Caller owns the key (R5). This crate never holds an HMAC secret; the host
supplies a Fingerprinter. Fingerprinting is computed over the normalized (digits-only) value internally, so the raw value never leaves detect.
Findingis sanitized (masked-only), so derivingDebug/Clone/Serialize
on it does not violate the "no raw in logs/serialization" rule — that rule binds the sensor's raw buffers, not this already-masked output.
Detectors (SSN area/group/serial rules, Luhn) are lifted from infrastructure-waf::pattern_detector; WAF is repointed at this crate (T2).
Capabilities
crate root
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
fn detect(text : & str, policy : & DlpPolicy <'_>) -> Vec <Finding> |
Confidence
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
pub enum Confidence |
DlpFindingType
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
pub enum DlpFindingType |
DlpFindingType :: fn as_str(& self) -> & 'static str |
DlpFindingType :: fn from_str_name(s : & str) -> Option <Self> |
DlpPolicy
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
pub struct DlpPolicy<'a> |
Finding
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
pub struct Finding |
Fingerprinter
infrastructure-dlp-detect — deterministic host-side DLP detection.
| Item |
|---|
pub trait Fingerprinter |
entropy (other)
Shannon entropy + corroborated high-entropy secret detection (Sprint 3.6 T2).
| Item |
|---|
pub const DEFAULT_ENTROPY_THRESHOLD: f64 |
fn shannon_entropy(s : & str) -> f64 |
policy (other)
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
fn screen(text : & str, policy : & ScreenPolicy) -> Result <Verdict, ScreenError> |
fn screen_at(text : & str, policy : & ScreenPolicy, now_unix : i64) -> Result <Verdict, ScreenError> |
Action
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub enum Action |
AllowlistEntry
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub struct AllowlistEntry |
PolicyError
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub enum PolicyError |
PolicyError :: fn fmt(& self, f : & mut core::fmt::Formatter <'_>) -> core::fmt::Result |
ScreenError
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub enum ScreenError |
ScreenError :: fn fmt(& self, f : & mut core::fmt::Formatter <'_>) -> core::fmt::Result |
ScreenPolicy
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub struct ScreenPolicy |
ScreenPolicy :: fn default() -> Self |
ScreenPolicy :: fn from_toml_str(source : & str) -> Result <Self, PolicyError> |
ScreenPolicy :: fn policy_version(& self) -> String |
ScreenPolicy :: fn action_for(& self, class : DlpFindingType) -> Action |
Verdict
Screening policy + verdicts for the outbound DLP gate (Sprint 3.6 T4).
| Item |
|---|
pub enum Verdict |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
infrastructure_dlp_detect
entropypolicy
flowchart TD n_infrastructure_dlp_detect["infrastructure_dlp_detect"] n_infrastructure_dlp_detect --> n_entropy["entropy"] n_infrastructure_dlp_detect --> n_policy["policy"]
Public surface
`crate root`
| Item | What it is |
|---|---|
pub enum DlpFindingType | The category of a detected sensitive value |
DlpFindingType :: fn as_str(& self) -> & 'static str | Stable machine identifier for the finding type. |
DlpFindingType :: fn from_str_name(s : & str) -> Option <Self> | Parse a stable machine identifier (the Self::as_str form) back into a finding type |
pub enum Confidence | Detection confidence grade |
pub struct Finding | A single detected sensitive value |
pub trait Fingerprinter | Supplies a keyed fingerprint over a normalized (digits-only) value |
pub struct DlpPolicy<'a> | Detection policy |
fn detect(text : & str, policy : & DlpPolicy <'_>) -> Vec <Finding> | Scan text and return all sensitive-value findings, sorted by position |
`entropy`
| Item | What it is |
|---|---|
pub const DEFAULT_ENTROPY_THRESHOLD: f64 | Default corroborated-entropy threshold (bits/char), matching the historical cookie_decode secret heuristic (entropy > 4.5 && len > 20). |
fn shannon_entropy(s : & str) -> f64 | Shannon entropy of a string (bits per character). |
`policy`
| Item | What it is |
|---|---|
pub enum Action | Per-class enforcement action. |
pub struct AllowlistEntry | A validated allowlist entry: a deliberate, expiring exemption for one exact value (keyed-HMAC fingerprint) of one class. |
pub enum Verdict | The screening outcome for one text. |
pub enum ScreenError | Screening runtime failure (distinct from policy-load failure). |
ScreenError :: fn fmt(& self, f : & mut core::fmt::Formatter <'_>) -> core::fmt::Result | — |
pub enum PolicyError | Policy-load failure |
PolicyError :: fn fmt(& self, f : & mut core::fmt::Formatter <'_>) -> core::fmt::Result | — |
pub struct ScreenPolicy | TOML-loadable screening policy |
ScreenPolicy :: fn default() -> Self | The built-in default policy: default actions, no allowlist, no denylist, no auto-redact, default entropy threshold. |
ScreenPolicy :: fn from_toml_str(source : & str) -> Result <Self, PolicyError> | Parse and validate a policy from TOML text |
ScreenPolicy :: fn policy_version(& self) -> String | sha256 hex of the canonical policy bytes (the TOML source; empty string for the built-in default policy). |
ScreenPolicy :: fn action_for(& self, class : DlpFindingType) -> Action | The effective action for a class: explicit entry, else the settled default table. |
fn screen(text : & str, policy : & ScreenPolicy) -> Result <Verdict, ScreenError> | Screen text against policy, using the current system clock for allowlist expiry |
fn screen_at(text : & str, policy : & ScreenPolicy, now_unix : i64) -> Result <Verdict, ScreenError> | Fully deterministic screening with an injected clock (unix seconds). |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
HmacFingerprinter | fingerprint::HmacFingerprinter |
redact | redact::redact |
shannon_entropy | entropy::shannon_entropy |
{screen,screen_at,Action,AllowlistEntry,PolicyError,ScreenError,ScreenPolicy,Verdict,} | policy::{screen,screen_at,Action,AllowlistEntry,PolicyError,ScreenError,ScreenPolicy,Verdict,} |
Boundary
Depends on no other workspace tier.
Shares tier infrastructure with 82 other crates: infrastructure-acquire, infrastructure-adapters-google-calendar, infrastructure-adapters-google-gmail, infrastructure-adapters-google-places, infrastructure-adapters-google-trends, infrastructure-adapters-shodan, infrastructure-adapters-yelp, infrastructure-agent, … (82 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | infrastructure |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/infrastructure/dlp-detect |
| Vocabulary in force (lexicon) | current |
Dependencies
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
hmac | ^0.12 | — | yes | always |
once_cell | ^1 | — | no | always |
regex | ^1 | — | no | always |
serde | ^1 | derive | yes | always |
sha2 | ^0.10 | — | yes | always |
toml | ^0.8 | — | yes | always |
Development. None.
Build. None.
Depended on by. 14 workspace crates.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_conversation["application-conversation"] -->|uses| SELF n_application_wiki["application-wiki"] -->|uses| SELF n_infrastructure_agent["infrastructure-agent"] -->|uses| SELF n_infrastructure_browser_automation["infrastructure-browser-automation"] -->|uses| SELF n_infrastructure_dlp["infrastructure-dlp"] -->|uses| SELF n_infrastructure_ocr_tesseract["infrastructure-ocr-tesseract"] -->|uses| SELF n_infrastructure_waf["infrastructure-waf"] -->|uses| SELF n_operations_dlp_agent["operations-dlp-agent"] -->|uses| SELF n_operations_dlp_sensor["operations-dlp-sensor"] -->|uses| SELF n_platform_privacy_scan_api["platform-privacy-scan-api"] -->|uses| SELF n_tools_ask_ai_core["tools-ask-ai-core"] -->|uses| SELF n_tools_corpus["tools-corpus"] -->|uses| SELF n_tools_knowitall["tools-knowitall"] -->|uses| SELF n_tools_prompt_shaper["tools-prompt-shaper"] -->|uses| SELF SELF["infrastructure-dlp-detect"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
default | — | yes |
fingerprint | dep:hmac, dep:sha2 | no |
policy | dep:toml, dep:serde, fingerprint | no |
serde | dep:serde | no |
flowchart LR n_default["default"] n_fingerprint["fingerprint"] --> n_dep_hmac["dep:hmac"] n_fingerprint["fingerprint"] --> n_dep_sha2["dep:sha2"] n_policy["policy"] --> n_dep_toml["dep:toml"] n_policy["policy"] --> n_dep_serde["dep:serde"] n_policy["policy"] --> n_fingerprint["fingerprint"] n_serde["serde"] --> n_dep_serde["dep:serde"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | infrastructure_dlp_detect | `src/lib.rs` |
Error model
| Error type | Named by |
|---|---|
PolicyError | declared, no public signature returns it |
ScreenError | screen, screen_at |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | none detected |
| database access | none detected |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
14 workspace crates depend on this one: application-conversation, application-wiki, infrastructure-agent, infrastructure-browser-automation, infrastructure-dlp, infrastructure-ocr-tesseract, infrastructure-waf, operations-dlp-agent, operations-dlp-sensor, platform-privacy-scan-api, tools-ask-ai-core, tools-corpus, … (14 total).
Verification
| Kind | Count |
|---|---|
| Unit tests | 105 |
| Integration tests | 0 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 6 | 0 | 35 |
entropy | 2 | 0 | 1 |
policy | 8 | 0 | 25 |
What the tests establish, by name:
aws_access_key_detected—src/detectors.rsaws_key_wins_over_generic_assignment—src/detectors.rsbare_date_without_keyword_not_dob—src/detectors.rsbare_nine_digits_common_shapes_not_ssn_without_keyword—src/detectors.rsbare_number_without_label_not_mrn—src/detectors.rsbirth_keyword_far_from_date_not_dob—src/detectors.rscase_and_docket_labeled_value_detected—src/detectors.rscase_as_ordinary_word_not_detected—src/detectors.rscommit_date_not_dob—src/detectors.rsdenylist_no_partial_word_match—src/detectors.rsdenylist_term_matched_case_insensitive—src/detectors.rsdob_labeled_dates_detected—src/detectors.rsdocket_as_ordinary_word_not_detected—src/detectors.rsdue_date_not_dob—src/detectors.rsemail_detected_and_masked—src/detectors.rsempty_denylist_matches_nothing—src/detectors.rsgeneric_key_assignment_detected_and_span_is_value—src/detectors.rsgeneric_token_colon_form_detected—src/detectors.rsgit_short_hash_not_phone—src/detectors.rsgithub_tokens_detected—src/detectors.rsintl_general_phone_detected—src/detectors.rsjwt_wins_over_entropy_detector—src/detectors.rsjwt_with_alg_header_detected—src/detectors.rsmigration_timestamp_not_dob—src/detectors.rsmrn_labeled_value_detected—src/detectors.rsmrn_word_without_digit_value_not_detected—src/detectors.rsnanp_dashed_paren_intl_and_bare_forms_detected—src/detectors.rsnot_an_email_not_detected—src/detectors.rsnumber_plus_capitalized_words_without_suffix_not_address—src/detectors.rspem_block_detected_full_span—src/detectors.rs- _… 75 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 22 | 24 |
Public modules with a //! block | 2 | 2 |
pie showData
title Public items with rustdoc
"Documented" : 22
"No rustdoc detected" : 2
Metrics
| Metric | Value |
|---|---|
| Rust source files | 6 |
| Source lines | 2708 |
| Code lines | 2055 |
| Public API items | 24 |
| Public modules | 2 |
| Tests | 105 |
| Examples | 0 |
| Cargo features | 4 |
| Direct runtime dependencies | 6 |
| Workspace reverse dependencies | 14 |
pie showData
title Public API by kind
"constant" : 1
"enum" : 6
"function" : 4
"method" : 8
"struct" : 4
"trait" : 1
pie showData
title Rust source composition
"Code" : 2055
"Blank or comment" : 653
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.