visus-mcp 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ROADMAP.md +70 -27
- package/dist/sanitizer/index.d.ts +8 -2
- package/dist/sanitizer/index.d.ts.map +1 -1
- package/dist/sanitizer/index.js +8 -5
- package/dist/sanitizer/index.js.map +1 -1
- package/dist/sanitizer/pii-allowlist.d.ts +49 -0
- package/dist/sanitizer/pii-allowlist.d.ts.map +1 -0
- package/dist/sanitizer/pii-allowlist.js +231 -0
- package/dist/sanitizer/pii-allowlist.js.map +1 -0
- package/dist/sanitizer/pii-redactor.d.ts +13 -1
- package/dist/sanitizer/pii-redactor.d.ts.map +1 -1
- package/dist/sanitizer/pii-redactor.js +26 -2
- package/dist/sanitizer/pii-redactor.js.map +1 -1
- package/dist/tools/fetch-structured.d.ts.map +1 -1
- package/dist/tools/fetch-structured.js +5 -2
- package/dist/tools/fetch-structured.js.map +1 -1
- package/dist/tools/fetch.d.ts.map +1 -1
- package/dist/tools/fetch.js +3 -2
- package/dist/tools/fetch.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/sanitizer/index.ts +10 -5
- package/src/sanitizer/pii-allowlist.ts +273 -0
- package/src/sanitizer/pii-redactor.ts +43 -2
- package/src/tools/fetch-structured.ts +5 -2
- package/src/tools/fetch.ts +3 -2
- package/src/types.ts +2 -0
- package/tests/pii-allowlist.test.ts +282 -0
package/ROADMAP.md
CHANGED
|
@@ -1,41 +1,84 @@
|
|
|
1
1
|
# Visus MCP — Product Roadmap
|
|
2
2
|
|
|
3
|
-
## v0.1.0 ✅ PUBLISHED
|
|
3
|
+
## v0.1.0 ✅ PUBLISHED (2026-03-21)
|
|
4
4
|
- 43 injection pattern categories
|
|
5
|
-
- PII redaction (email, phone, SSN,
|
|
6
|
-
- undici fetch() renderer
|
|
5
|
+
- PII redaction (email, phone, SSN, credit card, IP)
|
|
6
|
+
- undici fetch() renderer (static + server-rendered pages)
|
|
7
7
|
- visus_fetch + visus_fetch_structured tools
|
|
8
8
|
- 95/95 tests passing
|
|
9
9
|
- Published to npm
|
|
10
|
+
- Claude Desktop smoke tested (4/4 passing)
|
|
10
11
|
|
|
11
|
-
## v0.2.0
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
12
|
+
## v0.2.0 ✅ PUBLISHED + DEPLOYED (2026-03-22)
|
|
13
|
+
- Playwright headless Chromium (JavaScript-rendered pages, SPAs)
|
|
14
|
+
- AWS Lambda renderer (x86_64, Amazon Linux, Node.js 20)
|
|
15
|
+
- API Gateway (REST API)
|
|
16
|
+
- Cognito User Pool with OAuth 2.0 (email authentication)
|
|
17
|
+
- DynamoDB audit logging table (KMS-encrypted, PITR in prod)
|
|
18
|
+
- IAM roles with scoped permissions
|
|
19
|
+
- CloudWatch structured logging (30-day retention)
|
|
20
|
+
- Dual-mode runtime (stdio MCP + Lambda unified codebase)
|
|
21
|
+
- BYOC support (user-supplied Lambda endpoint via VISUS_RENDERER_URL)
|
|
22
|
+
- Lateos managed endpoint live:
|
|
23
|
+
https://wyomy29zd7.execute-api.us-east-1.amazonaws.com
|
|
24
|
+
- 95/95 tests passing (no regressions)
|
|
25
|
+
- Lambda smoke tests: 3/3 passing
|
|
26
|
+
- example.com (static): 1.0s warm
|
|
27
|
+
- github.com (SPA): 6.2s warm
|
|
28
|
+
- medlineplus.gov (clinical): 3.0s warm
|
|
17
29
|
|
|
18
30
|
## v0.3.0 — PLANNED
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
31
|
+
Focus: managed tier activation — make the deployed
|
|
32
|
+
infrastructure useful to end users
|
|
33
|
+
|
|
34
|
+
- Activate Cognito authentication on managed endpoint
|
|
35
|
+
(currently deployed but open — no auth enforced)
|
|
36
|
+
- Free tier rate limiting (requests/day per user)
|
|
37
|
+
- API key management for managed tier users
|
|
38
|
+
- CloudWatch metrics dashboard (usage visibility)
|
|
39
|
+
- WAF rules on API Gateway (bot protection)
|
|
40
|
+
- CORS restricted to authenticated origins
|
|
41
|
+
- npm publish v0.3.0
|
|
24
42
|
|
|
25
43
|
## v0.4.0 — PLANNED
|
|
26
|
-
|
|
44
|
+
Focus: paid tier + enterprise
|
|
45
|
+
|
|
46
|
+
- Stripe billing integration
|
|
27
47
|
- Usage dashboard for managed tier users
|
|
28
|
-
-
|
|
48
|
+
- Paid tier gating (rate limit increase)
|
|
49
|
+
- BYOC enterprise tier (dedicated Lambda, SLA documentation)
|
|
29
50
|
- Lateos platform integration
|
|
51
|
+
- Multi-region consideration (me-central-1 for MENA healthcare)
|
|
52
|
+
|
|
53
|
+
## Phase 3 — USER SESSION RELAY (future)
|
|
54
|
+
Focus: login-gated content (LinkedIn, X, EHR portals)
|
|
55
|
+
|
|
56
|
+
- Chrome extension / in-app browser layer
|
|
57
|
+
- User-authenticated session relay
|
|
58
|
+
- Content passes through Visus sanitizer before reaching Claude
|
|
59
|
+
- Zero Lateos infrastructure in the auth path (user's own session)
|
|
60
|
+
- Tagline: "What the web shows you, Lateos reads safely"
|
|
61
|
+
- This is the feature that unlocks LinkedIn, X, and clinical portals
|
|
62
|
+
|
|
63
|
+
## Architecture Decisions (permanent record)
|
|
64
|
+
|
|
65
|
+
| Decision | Rationale |
|
|
66
|
+
|---|---|
|
|
67
|
+
| Sanitizer always runs locally | PHI never touches Lateos infrastructure |
|
|
68
|
+
| x86_64 Lambda only | ARM64 incompatible with Playwright |
|
|
69
|
+
| us-east-1 for managed endpoint | Best Lambda cold start globally |
|
|
70
|
+
| me-central-1 reserved | Future Lateos backend (MENA healthcare) |
|
|
71
|
+
| Open endpoint until v0.3.0 | Minimize adoption friction at launch |
|
|
72
|
+
| Cognito deployed in v0.2.0 | Available, not yet enforced |
|
|
73
|
+
| DynamoDB deployed in v0.2.0 | Available, not yet activated for audit |
|
|
74
|
+
| undici fallback retained | Graceful degradation if Lambda unavailable |
|
|
75
|
+
|
|
76
|
+
## Known Limitations (Phase 2)
|
|
30
77
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- Sanitizer ALWAYS runs locally — PHI never touches Lateos infrastructure
|
|
39
|
-
- Managed tier open (no auth) until v0.3.0 — minimize adoption friction
|
|
40
|
-
- BYOC uses same CDK template as Lateos managed deployment
|
|
41
|
-
- x86_64 Lambda required for Playwright (ARM64 incompatible)
|
|
78
|
+
| Limitation | Resolution |
|
|
79
|
+
|---|---|
|
|
80
|
+
| Login-gated pages (LinkedIn, X) | Phase 3 user-session relay |
|
|
81
|
+
| Lambda cold start 4-5s | Provisioned concurrency (v0.3.0) |
|
|
82
|
+
| No rate limiting on managed endpoint | v0.3.0 |
|
|
83
|
+
| DynamoDB audit log not yet active | v0.3.0 activation |
|
|
84
|
+
| Cognito auth deployed but not enforced | v0.3.0 activation |
|
|
@@ -12,6 +12,11 @@ export interface SanitizationResult {
|
|
|
12
12
|
sanitization: {
|
|
13
13
|
patterns_detected: string[];
|
|
14
14
|
pii_types_redacted: string[];
|
|
15
|
+
pii_allowlisted: Array<{
|
|
16
|
+
type: string;
|
|
17
|
+
value: string;
|
|
18
|
+
reason: string;
|
|
19
|
+
}>;
|
|
15
20
|
content_modified: boolean;
|
|
16
21
|
};
|
|
17
22
|
metadata: {
|
|
@@ -32,13 +37,14 @@ export interface SanitizationResult {
|
|
|
32
37
|
*
|
|
33
38
|
* Pipeline:
|
|
34
39
|
* 1. Injection detection and neutralization (43 patterns)
|
|
35
|
-
* 2. PII redaction (email, phone, SSN, CC, IP)
|
|
40
|
+
* 2. PII redaction (email, phone, SSN, CC, IP) with allowlisting
|
|
36
41
|
* 3. Metadata collection and logging
|
|
37
42
|
*
|
|
38
43
|
* @param content Raw content from web page
|
|
44
|
+
* @param sourceUrl Optional source URL for domain-scoped PII allowlisting
|
|
39
45
|
* @returns Sanitized content with detection metadata
|
|
40
46
|
*/
|
|
41
|
-
export declare function sanitize(content: string): SanitizationResult;
|
|
47
|
+
export declare function sanitize(content: string, sourceUrl?: string): SanitizationResult;
|
|
42
48
|
/**
|
|
43
49
|
* Quick check: does content need sanitization?
|
|
44
50
|
* (Used for optimization - skip pipeline if content is clean)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sanitizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,iBAAiB,EAAE,MAAM,EAAE,CAAC;QAC5B,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,gBAAgB,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE;QACR,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,oBAAoB,EAAE,OAAO,CAAC;QAC9B,sBAAsB,EAAE;YACtB,QAAQ,EAAE,MAAM,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH,CAAC;CACH;AAED
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sanitizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,iBAAiB,EAAE,MAAM,EAAE,CAAC;QAC5B,kBAAkB,EAAE,MAAM,EAAE,CAAC;QAC7B,eAAe,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACxE,gBAAgB,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE;QACR,eAAe,EAAE,MAAM,CAAC;QACxB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,oBAAoB,EAAE,OAAO,CAAC;QAC9B,sBAAsB,EAAE;YACtB,QAAQ,EAAE,MAAM,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,MAAM,CAAC;SACb,CAAC;KACH,CAAC;CACH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,kBAAkB,CA0ChF;AA0BD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG3D;AAED;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/sanitizer/index.js
CHANGED
|
@@ -14,18 +14,19 @@ import { redactPII } from './pii-redactor.js';
|
|
|
14
14
|
*
|
|
15
15
|
* Pipeline:
|
|
16
16
|
* 1. Injection detection and neutralization (43 patterns)
|
|
17
|
-
* 2. PII redaction (email, phone, SSN, CC, IP)
|
|
17
|
+
* 2. PII redaction (email, phone, SSN, CC, IP) with allowlisting
|
|
18
18
|
* 3. Metadata collection and logging
|
|
19
19
|
*
|
|
20
20
|
* @param content Raw content from web page
|
|
21
|
+
* @param sourceUrl Optional source URL for domain-scoped PII allowlisting
|
|
21
22
|
* @returns Sanitized content with detection metadata
|
|
22
23
|
*/
|
|
23
|
-
export function sanitize(content) {
|
|
24
|
+
export function sanitize(content, sourceUrl) {
|
|
24
25
|
const originalLength = content.length;
|
|
25
26
|
// Step 1: Detect and neutralize injection patterns
|
|
26
27
|
const injectionResult = detectAndNeutralize(content);
|
|
27
|
-
// Step 2: Redact PII from the already-sanitized content
|
|
28
|
-
const piiResult = redactPII(injectionResult.content);
|
|
28
|
+
// Step 2: Redact PII from the already-sanitized content (with allowlisting)
|
|
29
|
+
const piiResult = redactPII(injectionResult.content, sourceUrl);
|
|
29
30
|
// Step 3: Combine results
|
|
30
31
|
const finalContent = piiResult.content;
|
|
31
32
|
const contentModified = injectionResult.content_modified || piiResult.content_modified;
|
|
@@ -35,6 +36,7 @@ export function sanitize(content) {
|
|
|
35
36
|
logSanitization({
|
|
36
37
|
patterns_detected: injectionResult.patterns_detected,
|
|
37
38
|
pii_types_redacted: piiResult.pii_types_redacted,
|
|
39
|
+
pii_allowlisted: piiResult.pii_allowlisted,
|
|
38
40
|
severity_score: severityScore,
|
|
39
41
|
has_critical_threats: criticalThreats,
|
|
40
42
|
content_modified: contentModified
|
|
@@ -44,6 +46,7 @@ export function sanitize(content) {
|
|
|
44
46
|
sanitization: {
|
|
45
47
|
patterns_detected: injectionResult.patterns_detected,
|
|
46
48
|
pii_types_redacted: piiResult.pii_types_redacted,
|
|
49
|
+
pii_allowlisted: piiResult.pii_allowlisted,
|
|
47
50
|
content_modified: contentModified
|
|
48
51
|
},
|
|
49
52
|
metadata: {
|
|
@@ -66,7 +69,7 @@ function logSanitization(event) {
|
|
|
66
69
|
...event
|
|
67
70
|
};
|
|
68
71
|
// Only log if there were detections (reduce noise)
|
|
69
|
-
if (event.content_modified) {
|
|
72
|
+
if (event.content_modified || event.pii_allowlisted.length > 0) {
|
|
70
73
|
console.error(JSON.stringify(logEntry));
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sanitizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sanitizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACpG,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAwB9C;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,SAAkB;IAC1D,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAEtC,mDAAmD;IACnD,MAAM,eAAe,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAErD,4EAA4E;IAC5E,MAAM,SAAS,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEhE,0BAA0B;IAC1B,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC;IACvC,MAAM,eAAe,GAAG,eAAe,CAAC,gBAAgB,IAAI,SAAS,CAAC,gBAAgB,CAAC;IAEvF,MAAM,aAAa,GAAG,gBAAgB,CAAC,eAAe,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IACxF,MAAM,eAAe,GAAG,kBAAkB,CAAC,eAAe,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAE5F,2DAA2D;IAC3D,eAAe,CAAC;QACd,iBAAiB,EAAE,eAAe,CAAC,iBAAiB;QACpD,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;QAChD,eAAe,EAAE,SAAS,CAAC,eAAe;QAC1C,cAAc,EAAE,aAAa;QAC7B,oBAAoB,EAAE,eAAe;QACrC,gBAAgB,EAAE,eAAe;KAClC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,YAAY;QACrB,YAAY,EAAE;YACZ,iBAAiB,EAAE,eAAe,CAAC,iBAAiB;YACpD,kBAAkB,EAAE,SAAS,CAAC,kBAAkB;YAChD,eAAe,EAAE,SAAS,CAAC,eAAe;YAC1C,gBAAgB,EAAE,eAAe;SAClC;QACD,QAAQ,EAAE;YACR,eAAe,EAAE,cAAc;YAC/B,gBAAgB,EAAE,YAAY,CAAC,MAAM;YACrC,cAAc,EAAE,aAAa;YAC7B,oBAAoB,EAAE,eAAe;YACrC,sBAAsB,EAAE,eAAe,CAAC,QAAQ,CAAC,sBAAsB;SACxE;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAOxB;IACC,MAAM,QAAQ,GAAG;QACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,KAAK,EAAE,cAAc;QACrB,GAAG,KAAK;KACT,CAAC;IAEF,mDAAmD;IACnD,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/D,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,sDAAsD;IACtD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Allowlist Configuration
|
|
3
|
+
*
|
|
4
|
+
* Defines trusted phone numbers that should NOT be redacted from web content.
|
|
5
|
+
* Primarily for verified health authority and government emergency numbers.
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL: Only add numbers that are:
|
|
8
|
+
* 1. Publicly published institutional/government numbers
|
|
9
|
+
* 2. Verified health/safety authorities
|
|
10
|
+
* 3. Not personal contact information
|
|
11
|
+
*/
|
|
12
|
+
export interface TrustedPhoneNumber {
|
|
13
|
+
/** Display name for logging */
|
|
14
|
+
name: string;
|
|
15
|
+
/** Normalized phone number variants (all formats this number might appear in) */
|
|
16
|
+
numbers: string[];
|
|
17
|
+
/** Optional: domains where this number is trusted (empty = trusted everywhere) */
|
|
18
|
+
trustedDomains?: string[];
|
|
19
|
+
/** Category for audit logging */
|
|
20
|
+
category: 'emergency' | 'health_authority' | 'government' | 'helpline';
|
|
21
|
+
}
|
|
22
|
+
export interface PIIAllowlistConfig {
|
|
23
|
+
/** When true, trusted numbers only preserved if source domain matches trustedDomains */
|
|
24
|
+
strictDomainMode: boolean;
|
|
25
|
+
/** List of verified trusted phone numbers */
|
|
26
|
+
trustedPhoneNumbers: TrustedPhoneNumber[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Normalize a phone number to digits-only format for comparison
|
|
30
|
+
*/
|
|
31
|
+
export declare function normalizePhoneNumber(phone: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Extract domain from URL (returns hostname without www.)
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractDomain(url: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Built-in allowlist of verified health authority and emergency numbers
|
|
38
|
+
*/
|
|
39
|
+
export declare const DEFAULT_ALLOWLIST: PIIAllowlistConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Check if a phone number should be allowlisted (not redacted)
|
|
42
|
+
*
|
|
43
|
+
* @param phoneNumber The phone number to check (in any format)
|
|
44
|
+
* @param sourceUrl Optional source URL for domain-scoped allowlisting
|
|
45
|
+
* @param config Optional custom config (defaults to DEFAULT_ALLOWLIST)
|
|
46
|
+
* @returns The trusted number entry if allowlisted, null otherwise
|
|
47
|
+
*/
|
|
48
|
+
export declare function isAllowlistedPhoneNumber(phoneNumber: string, sourceUrl?: string, config?: PIIAllowlistConfig): TrustedPhoneNumber | null;
|
|
49
|
+
//# sourceMappingURL=pii-allowlist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-allowlist.d.ts","sourceRoot":"","sources":["../../src/sanitizer/pii-allowlist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,iCAAiC;IACjC,QAAQ,EAAE,WAAW,GAAG,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC;CACxE;AAED,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6CAA6C;IAC7C,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;CAC3C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,kBA+J/B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,GAAE,kBAAsC,GAC7C,kBAAkB,GAAG,IAAI,CA+C3B"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII Allowlist Configuration
|
|
3
|
+
*
|
|
4
|
+
* Defines trusted phone numbers that should NOT be redacted from web content.
|
|
5
|
+
* Primarily for verified health authority and government emergency numbers.
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL: Only add numbers that are:
|
|
8
|
+
* 1. Publicly published institutional/government numbers
|
|
9
|
+
* 2. Verified health/safety authorities
|
|
10
|
+
* 3. Not personal contact information
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Normalize a phone number to digits-only format for comparison
|
|
14
|
+
*/
|
|
15
|
+
export function normalizePhoneNumber(phone) {
|
|
16
|
+
return phone.replace(/\D/g, '');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extract domain from URL (returns hostname without www.)
|
|
20
|
+
*/
|
|
21
|
+
export function extractDomain(url) {
|
|
22
|
+
try {
|
|
23
|
+
const parsedUrl = new URL(url);
|
|
24
|
+
return parsedUrl.hostname.replace(/^www\./, '').toLowerCase();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Built-in allowlist of verified health authority and emergency numbers
|
|
32
|
+
*/
|
|
33
|
+
export const DEFAULT_ALLOWLIST = {
|
|
34
|
+
strictDomainMode: false, // Default: trust globally, not domain-scoped
|
|
35
|
+
trustedPhoneNumbers: [
|
|
36
|
+
// Emergency Services
|
|
37
|
+
{
|
|
38
|
+
name: 'Emergency Services (911)',
|
|
39
|
+
numbers: ['911'],
|
|
40
|
+
category: 'emergency'
|
|
41
|
+
},
|
|
42
|
+
// Poison Control
|
|
43
|
+
{
|
|
44
|
+
name: 'Poison Control Center',
|
|
45
|
+
numbers: [
|
|
46
|
+
'18002221222',
|
|
47
|
+
'8002221222',
|
|
48
|
+
'1-800-222-1222',
|
|
49
|
+
'800-222-1222'
|
|
50
|
+
],
|
|
51
|
+
trustedDomains: [
|
|
52
|
+
'medlineplus.gov',
|
|
53
|
+
'cdc.gov',
|
|
54
|
+
'fda.gov',
|
|
55
|
+
'aapcc.org',
|
|
56
|
+
'poison.org',
|
|
57
|
+
'nih.gov',
|
|
58
|
+
'nlm.nih.gov'
|
|
59
|
+
],
|
|
60
|
+
category: 'health_authority'
|
|
61
|
+
},
|
|
62
|
+
// FDA MedWatch (adverse event reporting)
|
|
63
|
+
{
|
|
64
|
+
name: 'FDA MedWatch',
|
|
65
|
+
numbers: [
|
|
66
|
+
'18003321088',
|
|
67
|
+
'8003321088',
|
|
68
|
+
'1-800-332-1088',
|
|
69
|
+
'800-332-1088'
|
|
70
|
+
],
|
|
71
|
+
trustedDomains: [
|
|
72
|
+
'fda.gov',
|
|
73
|
+
'medlineplus.gov',
|
|
74
|
+
'cdc.gov',
|
|
75
|
+
'nih.gov'
|
|
76
|
+
],
|
|
77
|
+
category: 'health_authority'
|
|
78
|
+
},
|
|
79
|
+
// CDC INFO
|
|
80
|
+
{
|
|
81
|
+
name: 'CDC INFO',
|
|
82
|
+
numbers: [
|
|
83
|
+
'18002324636',
|
|
84
|
+
'8002324636',
|
|
85
|
+
'1-800-232-4636',
|
|
86
|
+
'800-232-4636'
|
|
87
|
+
],
|
|
88
|
+
trustedDomains: [
|
|
89
|
+
'cdc.gov',
|
|
90
|
+
'medlineplus.gov',
|
|
91
|
+
'nih.gov'
|
|
92
|
+
],
|
|
93
|
+
category: 'health_authority'
|
|
94
|
+
},
|
|
95
|
+
// SAMHSA National Helpline (substance abuse/mental health)
|
|
96
|
+
{
|
|
97
|
+
name: 'SAMHSA National Helpline',
|
|
98
|
+
numbers: [
|
|
99
|
+
'18006624357',
|
|
100
|
+
'8006624357',
|
|
101
|
+
'1-800-662-4357',
|
|
102
|
+
'800-662-4357'
|
|
103
|
+
],
|
|
104
|
+
trustedDomains: [
|
|
105
|
+
'samhsa.gov',
|
|
106
|
+
'medlineplus.gov',
|
|
107
|
+
'cdc.gov',
|
|
108
|
+
'nih.gov'
|
|
109
|
+
],
|
|
110
|
+
category: 'helpline'
|
|
111
|
+
},
|
|
112
|
+
// National Suicide Prevention Lifeline
|
|
113
|
+
{
|
|
114
|
+
name: 'National Suicide Prevention Lifeline',
|
|
115
|
+
numbers: [
|
|
116
|
+
'18002738255',
|
|
117
|
+
'8002738255',
|
|
118
|
+
'1-800-273-8255',
|
|
119
|
+
'800-273-8255',
|
|
120
|
+
'988' // New 3-digit code
|
|
121
|
+
],
|
|
122
|
+
trustedDomains: [
|
|
123
|
+
'suicidepreventionlifeline.org',
|
|
124
|
+
'samhsa.gov',
|
|
125
|
+
'medlineplus.gov',
|
|
126
|
+
'cdc.gov',
|
|
127
|
+
'nih.gov'
|
|
128
|
+
],
|
|
129
|
+
category: 'helpline'
|
|
130
|
+
},
|
|
131
|
+
// National Domestic Violence Hotline
|
|
132
|
+
{
|
|
133
|
+
name: 'National Domestic Violence Hotline',
|
|
134
|
+
numbers: [
|
|
135
|
+
'18007997233',
|
|
136
|
+
'8007997233',
|
|
137
|
+
'1-800-799-7233',
|
|
138
|
+
'800-799-7233'
|
|
139
|
+
],
|
|
140
|
+
trustedDomains: [
|
|
141
|
+
'thehotline.org',
|
|
142
|
+
'cdc.gov',
|
|
143
|
+
'medlineplus.gov',
|
|
144
|
+
'nih.gov'
|
|
145
|
+
],
|
|
146
|
+
category: 'helpline'
|
|
147
|
+
},
|
|
148
|
+
// Medicare
|
|
149
|
+
{
|
|
150
|
+
name: 'Medicare',
|
|
151
|
+
numbers: [
|
|
152
|
+
'18006331795',
|
|
153
|
+
'8006331795',
|
|
154
|
+
'1-800-633-1795',
|
|
155
|
+
'800-633-1795'
|
|
156
|
+
],
|
|
157
|
+
trustedDomains: [
|
|
158
|
+
'medicare.gov',
|
|
159
|
+
'cms.gov',
|
|
160
|
+
'medlineplus.gov',
|
|
161
|
+
'nih.gov'
|
|
162
|
+
],
|
|
163
|
+
category: 'government'
|
|
164
|
+
},
|
|
165
|
+
// Veterans Crisis Line
|
|
166
|
+
{
|
|
167
|
+
name: 'Veterans Crisis Line',
|
|
168
|
+
numbers: [
|
|
169
|
+
'18002738255',
|
|
170
|
+
'8002738255',
|
|
171
|
+
'1-800-273-8255',
|
|
172
|
+
'800-273-8255'
|
|
173
|
+
],
|
|
174
|
+
trustedDomains: [
|
|
175
|
+
'va.gov',
|
|
176
|
+
'veteranscrisisline.net',
|
|
177
|
+
'medlineplus.gov',
|
|
178
|
+
'nih.gov'
|
|
179
|
+
],
|
|
180
|
+
category: 'helpline'
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* Check if a phone number should be allowlisted (not redacted)
|
|
186
|
+
*
|
|
187
|
+
* @param phoneNumber The phone number to check (in any format)
|
|
188
|
+
* @param sourceUrl Optional source URL for domain-scoped allowlisting
|
|
189
|
+
* @param config Optional custom config (defaults to DEFAULT_ALLOWLIST)
|
|
190
|
+
* @returns The trusted number entry if allowlisted, null otherwise
|
|
191
|
+
*/
|
|
192
|
+
export function isAllowlistedPhoneNumber(phoneNumber, sourceUrl, config = DEFAULT_ALLOWLIST) {
|
|
193
|
+
const normalized = normalizePhoneNumber(phoneNumber);
|
|
194
|
+
const sourceDomain = sourceUrl ? extractDomain(sourceUrl) : '';
|
|
195
|
+
for (const trustedEntry of config.trustedPhoneNumbers) {
|
|
196
|
+
// Check if any variant of this trusted number matches
|
|
197
|
+
const matchesNumber = trustedEntry.numbers.some(variant => {
|
|
198
|
+
const normalizedVariant = normalizePhoneNumber(variant);
|
|
199
|
+
return normalized === normalizedVariant;
|
|
200
|
+
});
|
|
201
|
+
if (!matchesNumber) {
|
|
202
|
+
continue; // Number doesn't match, check next entry
|
|
203
|
+
}
|
|
204
|
+
// Number matches - now check domain restrictions
|
|
205
|
+
const hasDomainRestrictions = trustedEntry.trustedDomains && trustedEntry.trustedDomains.length > 0;
|
|
206
|
+
if (!hasDomainRestrictions) {
|
|
207
|
+
// No domain restrictions - trust globally
|
|
208
|
+
return trustedEntry;
|
|
209
|
+
}
|
|
210
|
+
// Has domain restrictions
|
|
211
|
+
if (config.strictDomainMode && !sourceUrl) {
|
|
212
|
+
// Strict mode requires domain match, but no URL provided
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (sourceUrl && trustedEntry.trustedDomains) {
|
|
216
|
+
// Check if source domain matches any trusted domain
|
|
217
|
+
const isDomainTrusted = trustedEntry.trustedDomains.some(trustedDomain => {
|
|
218
|
+
return sourceDomain.endsWith(trustedDomain);
|
|
219
|
+
});
|
|
220
|
+
if (isDomainTrusted) {
|
|
221
|
+
return trustedEntry;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// In non-strict mode, trust the number even if domain doesn't match
|
|
225
|
+
if (!config.strictDomainMode) {
|
|
226
|
+
return trustedEntry;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return null; // No match found
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=pii-allowlist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-allowlist.js","sourceRoot":"","sources":["../../src/sanitizer/pii-allowlist.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,19 +5,31 @@
|
|
|
5
5
|
* to prevent leakage of sensitive data to the LLM.
|
|
6
6
|
*
|
|
7
7
|
* Redacts: emails, phone numbers, SSNs, credit cards, IP addresses
|
|
8
|
+
* Supports allowlisting of trusted institutional phone numbers (e.g., Poison Control)
|
|
8
9
|
*/
|
|
10
|
+
import { type PIIAllowlistConfig } from './pii-allowlist.js';
|
|
9
11
|
export interface PIIRedactionResult {
|
|
10
12
|
content: string;
|
|
11
13
|
pii_types_redacted: string[];
|
|
14
|
+
pii_allowlisted: Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
value: string;
|
|
17
|
+
reason: string;
|
|
18
|
+
}>;
|
|
12
19
|
content_modified: boolean;
|
|
13
20
|
metadata: {
|
|
14
21
|
redaction_counts: Record<string, number>;
|
|
22
|
+
allowlist_counts: Record<string, number>;
|
|
15
23
|
};
|
|
16
24
|
}
|
|
17
25
|
/**
|
|
18
26
|
* Redact PII from content
|
|
27
|
+
*
|
|
28
|
+
* @param content Content to redact PII from
|
|
29
|
+
* @param sourceUrl Optional source URL for domain-scoped allowlisting
|
|
30
|
+
* @param allowlistConfig Optional custom allowlist config
|
|
19
31
|
*/
|
|
20
|
-
export declare function redactPII(content: string): PIIRedactionResult;
|
|
32
|
+
export declare function redactPII(content: string, sourceUrl?: string, allowlistConfig?: PIIAllowlistConfig): PIIRedactionResult;
|
|
21
33
|
/**
|
|
22
34
|
* Check if content contains any PII (without redacting)
|
|
23
35
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pii-redactor.d.ts","sourceRoot":"","sources":["../../src/sanitizer/pii-redactor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pii-redactor.d.ts","sourceRoot":"","sources":["../../src/sanitizer/pii-redactor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE;QACR,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACzC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1C,CAAC;CACH;AAuID;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,GAAE,kBAAsC,GACtD,kBAAkB,CA2DpB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAYpD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAcxD"}
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* to prevent leakage of sensitive data to the LLM.
|
|
6
6
|
*
|
|
7
7
|
* Redacts: emails, phone numbers, SSNs, credit cards, IP addresses
|
|
8
|
+
* Supports allowlisting of trusted institutional phone numbers (e.g., Poison Control)
|
|
8
9
|
*/
|
|
10
|
+
import { isAllowlistedPhoneNumber, DEFAULT_ALLOWLIST } from './pii-allowlist.js';
|
|
9
11
|
/**
|
|
10
12
|
* PII detection patterns with validators
|
|
11
13
|
*/
|
|
@@ -129,10 +131,16 @@ function luhnCheck(digits) {
|
|
|
129
131
|
}
|
|
130
132
|
/**
|
|
131
133
|
* Redact PII from content
|
|
134
|
+
*
|
|
135
|
+
* @param content Content to redact PII from
|
|
136
|
+
* @param sourceUrl Optional source URL for domain-scoped allowlisting
|
|
137
|
+
* @param allowlistConfig Optional custom allowlist config
|
|
132
138
|
*/
|
|
133
|
-
export function redactPII(content) {
|
|
139
|
+
export function redactPII(content, sourceUrl, allowlistConfig = DEFAULT_ALLOWLIST) {
|
|
134
140
|
const piiTypesRedacted = new Set();
|
|
135
141
|
const redactionCounts = {};
|
|
142
|
+
const allowlistCounts = {};
|
|
143
|
+
const piiAllowlisted = [];
|
|
136
144
|
let sanitizedContent = content;
|
|
137
145
|
for (const pattern of PII_PATTERNS) {
|
|
138
146
|
const matches = Array.from(sanitizedContent.matchAll(pattern.regex));
|
|
@@ -142,6 +150,20 @@ export function redactPII(content) {
|
|
|
142
150
|
if (pattern.validator && !pattern.validator(matchedText)) {
|
|
143
151
|
continue;
|
|
144
152
|
}
|
|
153
|
+
// Check allowlist for phone numbers
|
|
154
|
+
if (pattern.type === 'PHONE') {
|
|
155
|
+
const allowlistedEntry = isAllowlistedPhoneNumber(matchedText, sourceUrl, allowlistConfig);
|
|
156
|
+
if (allowlistedEntry) {
|
|
157
|
+
// This is a trusted number - DO NOT redact
|
|
158
|
+
piiAllowlisted.push({
|
|
159
|
+
type: pattern.type,
|
|
160
|
+
value: matchedText,
|
|
161
|
+
reason: `Trusted ${allowlistedEntry.category}: ${allowlistedEntry.name}`
|
|
162
|
+
});
|
|
163
|
+
allowlistCounts[pattern.name] = (allowlistCounts[pattern.name] || 0) + 1;
|
|
164
|
+
continue; // Skip redaction
|
|
165
|
+
}
|
|
166
|
+
}
|
|
145
167
|
// Redact the PII
|
|
146
168
|
sanitizedContent = sanitizedContent.replace(matchedText, `[REDACTED:${pattern.type}]`);
|
|
147
169
|
piiTypesRedacted.add(pattern.name);
|
|
@@ -151,9 +173,11 @@ export function redactPII(content) {
|
|
|
151
173
|
return {
|
|
152
174
|
content: sanitizedContent,
|
|
153
175
|
pii_types_redacted: Array.from(piiTypesRedacted),
|
|
176
|
+
pii_allowlisted: piiAllowlisted,
|
|
154
177
|
content_modified: sanitizedContent !== content,
|
|
155
178
|
metadata: {
|
|
156
|
-
redaction_counts: redactionCounts
|
|
179
|
+
redaction_counts: redactionCounts,
|
|
180
|
+
allowlist_counts: allowlistCounts
|
|
157
181
|
}
|
|
158
182
|
};
|
|
159
183
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pii-redactor.js","sourceRoot":"","sources":["../../src/sanitizer/pii-redactor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pii-redactor.js","sourceRoot":"","sources":["../../src/sanitizer/pii-redactor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-structured.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-structured.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA2EjG;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"fetch-structured.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-structured.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AA2EjG;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,GAC/B,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC,CA+FpD;AAED;;GAEG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;CAyB9C,CAAC"}
|