Choose categories & levels¶
Goal: pick the right set of categories and the right max_level for your use case, so
you scan what matters without paying for what you don't.
Pick categories by use case¶
| Use case | Suggested categories |
|---|---|
| Prompt firewall (block injections) | injection, threat |
| DLP / leak prevention | dlp, pii, sensitive_document |
| Open-vocabulary PII extraction | dynamic-pii (+ pii for validated identifiers) |
| Agent tool-use guard | injection, tool_class, tool_action, tool_tags |
| Request router | routing |
| Shell / Bash tool guard (caller passes the command) | shell_command |
Scan only what you will act on — each category adds work. See Categories for what each one classifies and which layers back it.
Pick a level¶
max_level is the hard ceiling on escalation:
max_level |
Use when |
|---|---|
l1 |
You want asset-free, always-offline, rule-based coverage only (shell_command is the exception: its L1 detector needs a small model file). Runtime still depends on input size and enabled rules. |
l2 |
You want learned classification but never the transformer cost. Great default for high-throughput paths. |
l3 |
You want maximum accuracy and can afford occasional transformer inference on promoted requests. |
use patronus_ark::{SecurityCategory, SecurityGateway, SecurityLevel};
let mut scanner = SecurityGateway::with_download_categories(
vec![SecurityCategory::Injection, SecurityCategory::Threat],
SecurityLevel::L2, // learned classifiers, no L3
None,
true, // download_files
Some(vec![SecurityCategory::Injection, SecurityCategory::Threat]),
);
scanner.warmup().expect("warmup");
Choose DLP rule families¶
dlp runs on L1 only. By default it reports credentials and secrets (groups API_KEY,
CLOUD_KEY, PAYMENT_KEY, SECRET_TOKEN, CREDENTIAL, PASSWORD_HASH, PRIVATE_KEY,
CRYPTO_KEY) and classification markings (dlp.document.classification_marking). Business
identifiers (dlp.de.*, dlp.record.*, project and organization IDs), content classes
(dlp.content.*, dlp.internal.business_metric) and the other document classes
(dlp.document.*: legal, contracts, NDA, M&A, board minutes, unpublished financials, HR,
security reports, export control, R&D) are off until a rules gate turns their rule on:
scanner = SecurityGateway(categories=["dlp"], max_level="l1")
scanner.set_execution_gates({
"dlp_mode": "balanced", # scored findings instead of strict 1.0
"rules": {
"dlp_document_hr": True, # opt-in document class
"dlp_sql_statement": True, # opt-in content class
"dlp_generic_credential_assignment": False, # default-on rule switched off
},
})
Every rule ID, its group, provider, validator strength, format source and default state is in
the L1 rule catalog; what each group means is
in the DLP taxonomy. Keep dlp_mode at strict
when every match should block; balanced and recall score findings with the validator strength
and key context (see DLP score and modes).
How the default profile compares with gitleaks, TruffleHog and detect-secrets is on
DLP coverage and comparison.
Consider the offline implications¶
pii,dlp→ native L1, no assets ever.injection,threat→ native L1 works without assets; L2/L3 need assets.sensitive_document,tool_*,routing→ model-only; with no cached assets they produce no verdict.dynamic-pii→ L3-only; needs its GLiNER bundle or it cannot run.shell_command→ L1 with a model bundle (4.4 MiB); with downloads disabled and the model missing, warmup fails.
If you need guaranteed coverage in an air-gapped environment, prefer categories with a native L1 stage or pre-cache assets (see Offline & air-gapped).
Download only what you use¶
Enable downloads for just the categories you configured with download_categories:
scanner = SecurityGateway(
categories=["injection", "dlp", "pii"],
max_level="l2",
download_files=True,
download_categories=["injection"], # dlp/pii are native; only injection downloads
)
Turn levels or detectors off per request¶
Use execution gates to disable a level or a specific detector below the ceiling, without rebuilding the gateway:
Running classifiers with L3 only¶
With L2 disabled and L3 enabled, requested classifier categories are sent directly to L3; L2 promotion is not required. The canonical tokenizer splits the full input into 256-token model inputs (254 content tokens plus two special tokens). Model and L3 conditional gates still apply. L3 assets and the configured local or remote inference service must be ready. Native-only categories do not acquire an L3 model. Without L2 fallback results, a positive classifier may stop its own head early, but does not skip the other requested classifier heads. Dedicated L3 startup still requires its NTDB package metadata for label mappings; disabling L2 skips its inference, not that existing asset prerequisite. Unified L3-only startup does not require NTDB L2 packages.