Skip to content

Commit 2df826f

Browse files
feat(guardrails): run PII via Presidio sidecars + TS recognizer registry
- replace the per-call python3 subprocess (cold spaCy load every call) with two long-lived Presidio sidecars (analyzer + anonymizer) reached over HTTP; the app image no longer carries Python/Presidio/venv - add PRESIDIO_ANALYZER_URL / PRESIDIO_ANONYMIZER_URL - move VIN out of Python into a TS recognizer (check-digit validated) behind a CUSTOM_RECOGNIZERS registry so new custom detectors are one entry; masking is handled uniformly by the anonymizer - drive the guardrails block's PII type picker from the shared pii-entities catalog (adds VIN, fixes drift) so block + Data Retention never diverge - delete validate_pii.py, requirements.txt, setup.sh and the Dockerfile venv step
1 parent 8b1ad58 commit 2df826f

13 files changed

Lines changed: 455 additions & 674 deletions

File tree

apps/sim/blocks/blocks/guardrails.ts

Lines changed: 10 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ShieldCheckIcon } from '@/components/icons'
2+
import { PII_ENTITY_GROUPS } from '@/lib/guardrails/pii-entities'
23
import type { BlockConfig } from '@/blocks/types'
34
import {
45
getModelOptions,
@@ -170,65 +171,15 @@ Return ONLY the regex pattern - no explanations, no quotes, no forward slashes,
170171
title: 'PII Types to Detect',
171172
type: 'grouped-checkbox-list',
172173
maxHeight: 400,
173-
options: [
174-
// Common PII types
175-
{ label: 'Person name', id: 'PERSON', group: 'Common' },
176-
{ label: 'Email address', id: 'EMAIL_ADDRESS', group: 'Common' },
177-
{ label: 'Phone number', id: 'PHONE_NUMBER', group: 'Common' },
178-
{ label: 'Location', id: 'LOCATION', group: 'Common' },
179-
{ label: 'Date or time', id: 'DATE_TIME', group: 'Common' },
180-
{ label: 'IP address', id: 'IP_ADDRESS', group: 'Common' },
181-
{ label: 'URL', id: 'URL', group: 'Common' },
182-
{ label: 'Credit card number', id: 'CREDIT_CARD', group: 'Common' },
183-
{ label: 'International bank account number (IBAN)', id: 'IBAN_CODE', group: 'Common' },
184-
{ label: 'Cryptocurrency wallet address', id: 'CRYPTO', group: 'Common' },
185-
{ label: 'Medical license number', id: 'MEDICAL_LICENSE', group: 'Common' },
186-
{ label: 'Nationality / religion / political group', id: 'NRP', group: 'Common' },
187-
188-
// USA
189-
{ label: 'US bank account number', id: 'US_BANK_NUMBER', group: 'USA' },
190-
{ label: 'US driver license number', id: 'US_DRIVER_LICENSE', group: 'USA' },
191-
{
192-
label: 'US individual taxpayer identification number (ITIN)',
193-
id: 'US_ITIN',
194-
group: 'USA',
195-
},
196-
{ label: 'US passport number', id: 'US_PASSPORT', group: 'USA' },
197-
{ label: 'US Social Security number', id: 'US_SSN', group: 'USA' },
198-
199-
// UK
200-
{ label: 'UK National Insurance number', id: 'UK_NINO', group: 'UK' },
201-
{ label: 'UK NHS number', id: 'UK_NHS', group: 'UK' },
202-
203-
// Spain
204-
{ label: 'Spanish NIF number', id: 'ES_NIF', group: 'Spain' },
205-
{ label: 'Spanish NIE number', id: 'ES_NIE', group: 'Spain' },
206-
207-
// Italy
208-
{ label: 'Italian fiscal code', id: 'IT_FISCAL_CODE', group: 'Italy' },
209-
{ label: 'Italian driver license', id: 'IT_DRIVER_LICENSE', group: 'Italy' },
210-
{ label: 'Italian identity card', id: 'IT_IDENTITY_CARD', group: 'Italy' },
211-
{ label: 'Italian passport', id: 'IT_PASSPORT', group: 'Italy' },
212-
213-
// Poland
214-
{ label: 'Polish PESEL', id: 'PL_PESEL', group: 'Poland' },
215-
216-
// Singapore
217-
{ label: 'Singapore NRIC/FIN', id: 'SG_NRIC_FIN', group: 'Singapore' },
218-
219-
// Australia
220-
{ label: 'Australian business number (ABN)', id: 'AU_ABN', group: 'Australia' },
221-
{ label: 'Australian company number (ACN)', id: 'AU_ACN', group: 'Australia' },
222-
{ label: 'Australian tax file number (TFN)', id: 'AU_TFN', group: 'Australia' },
223-
{ label: 'Australian Medicare number', id: 'AU_MEDICARE', group: 'Australia' },
224-
225-
// India
226-
{ label: 'Indian Aadhaar', id: 'IN_AADHAAR', group: 'India' },
227-
{ label: 'Indian PAN', id: 'IN_PAN', group: 'India' },
228-
{ label: 'Indian vehicle registration', id: 'IN_VEHICLE_REGISTRATION', group: 'India' },
229-
{ label: 'Indian voter number', id: 'IN_VOTER', group: 'India' },
230-
{ label: 'Indian passport', id: 'IN_PASSPORT', group: 'India' },
231-
],
174+
// Driven by the shared catalog (includes VIN and custom recognizers) so the
175+
// block and the Data Retention settings never drift.
176+
options: PII_ENTITY_GROUPS.flatMap((group) =>
177+
group.entities.map((entity) => ({
178+
label: entity.label,
179+
id: entity.value,
180+
group: group.label,
181+
}))
182+
),
232183
condition: {
233184
field: 'validationType',
234185
value: ['pii'],

apps/sim/lib/core/config/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ export const env = createEnv({
311311
PORT: z.number().optional(), // Main application port
312312
INTERNAL_API_BASE_URL: z.string().optional(), // Optional internal base URL for server-side self-calls; must include protocol if set (e.g., http://sim-app.namespace.svc.cluster.local:3000)
313313
ALLOWED_ORIGINS: z.string().optional(), // CORS allowed origins
314+
PRESIDIO_ANALYZER_URL: z.string().optional(), // Presidio analyzer sidecar base URL for PII detection (default http://localhost:5002)
315+
PRESIDIO_ANONYMIZER_URL: z.string().optional(), // Presidio anonymizer sidecar base URL for PII masking (default http://localhost:5001)
314316

315317
// OAuth Integration Credentials - All optional, enables third-party integrations
316318
GOOGLE_CLIENT_ID: z.string().optional(), // Google OAuth client ID for Google services

apps/sim/lib/guardrails/.gitignore

Lines changed: 0 additions & 13 deletions
This file was deleted.

apps/sim/lib/guardrails/README.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,26 @@ For **hallucination detection**, you'll need:
1919
- A knowledge base with documents
2020
- An LLM provider API key (or use hosted models)
2121

22-
### Python Validators (PII Detection)
22+
### PII Detection (Presidio sidecars)
2323

24-
For **PII detection**, you need to set up a Python virtual environment and install Microsoft Presidio:
24+
PII detection runs against two long-lived **Microsoft Presidio sidecar containers** reached over
25+
HTTP — the analyzer (NLP detection) and the anonymizer (masking). In deployment they run alongside the
26+
app container in the same ECS task; locally, run the official images:
2527

2628
```bash
27-
cd apps/sim/lib/guardrails
28-
./setup.sh
29+
docker run -d -p 5002:3000 mcr.microsoft.com/presidio-analyzer:latest
30+
docker run -d -p 5001:3000 mcr.microsoft.com/presidio-anonymizer:latest
2931
```
3032

31-
This will:
32-
1. Create a Python virtual environment in `apps/sim/lib/guardrails/venv`
33-
2. Install required dependencies:
34-
- `presidio-analyzer` - PII detection engine
35-
- `presidio-anonymizer` - PII masking/anonymization
33+
Point the app at them (defaults shown):
3634

37-
The TypeScript wrapper will automatically use the virtual environment's Python interpreter.
35+
```bash
36+
PRESIDIO_ANALYZER_URL=http://localhost:5002
37+
PRESIDIO_ANONYMIZER_URL=http://localhost:5001
38+
```
39+
40+
VIN recognition (check-digit validated) is implemented in TypeScript (`vin.ts`) and never sent to the
41+
sidecars. No Python or local venv is required.
3842

3943
## Usage
4044

@@ -93,10 +97,9 @@ See [Presidio documentation](https://microsoft.github.io/presidio/supported_enti
9397
- `validate_json.ts` - JSON validation (TypeScript)
9498
- `validate_regex.ts` - Regex validation (TypeScript)
9599
- `validate_hallucination.ts` - Hallucination detection with RAG + LLM scoring (TypeScript)
96-
- `validate_pii.ts` - PII detection TypeScript wrapper (TypeScript)
97-
- `validate_pii.py` - PII detection using Microsoft Presidio (Python)
100+
- `validate_pii.ts` - PII detection client: calls the Presidio analyzer/anonymizer sidecars (TypeScript)
101+
- `vin.ts` - Check-digit-validated VIN recognizer (TypeScript)
102+
- `pii-entities.ts` - Client-safe PII entity catalog
103+
- `mask-client.ts` - Internal HTTP client for batch PII masking from the log-redaction persist path
98104
- `validate.test.ts` - Test suite for JSON and regex validators
99-
- `validate_hallucination.py` - Legacy Python hallucination detector (deprecated)
100-
- `requirements.txt` - Python dependencies for PII detection (and legacy hallucination)
101-
- `setup.sh` - Legacy installation script (deprecated)
102105

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { findVins } from '@/lib/guardrails/vin'
2+
3+
/**
4+
* A custom PII recognizer for entities Microsoft Presidio doesn't ship.
5+
*
6+
* A recognizer only does **detection** — it returns character spans. Masking is
7+
* handled uniformly by the anonymizer sidecar, which replaces every span by its
8+
* `entityType` (e.g. `<VIN>`), so a recognizer never touches the sidecars or the
9+
* masking path.
10+
*
11+
* To add one:
12+
* 1. Implement a pure `detect(text)` (regex/checksum/etc., no I/O).
13+
* 2. Register it in {@link CUSTOM_RECOGNIZERS}.
14+
* 3. Add its entity to `pii-entities.ts` so it appears in the Data Retention UI.
15+
*/
16+
export interface CustomRecognizer {
17+
/** Entity name; becomes the `<ENTITY>` placeholder when masked. */
18+
entityType: string
19+
/** Character spans of confirmed matches in `text`. Pure — no I/O. */
20+
detect(text: string): Array<{ start: number; end: number }>
21+
}
22+
23+
/** The registry of TS-side recognizers, applied on top of Presidio's built-ins. */
24+
export const CUSTOM_RECOGNIZERS: CustomRecognizer[] = [{ entityType: 'VIN', detect: findVins }]
25+
26+
/** Entity names owned by a custom recognizer — never forwarded to the analyzer. */
27+
export const CUSTOM_ENTITY_TYPES = new Set(CUSTOM_RECOGNIZERS.map((r) => r.entityType))

apps/sim/lib/guardrails/requirements.txt

Lines changed: 0 additions & 4 deletions
This file was deleted.

apps/sim/lib/guardrails/setup.sh

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)