@privacyscrubber/sdk 2.1.0 → 2.2.1
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/README.md +217 -2
- package/cli.js +130 -0
- package/index.d.ts +178 -0
- package/index.js +604 -11
- package/package.json +7 -1
- package/ps-license-manager.js +1 -1
- package/ps-pii-engine.cjs +1 -1
- package/scrubber-core.cjs +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
[](https://privacyscrubber.com)
|
|
7
7
|
[](https://www.npmjs.com/package/@privacyscrubber/sdk)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[-06b6d4.svg)](https://privacyscrubber.com/patents/)
|
|
10
|
+
[](https://github.com/moxno/privacyscrubber-mcp)
|
|
9
11
|
|
|
10
12
|
> **Zero-Trust Data Sanitization (ZTDS) & PII Redaction Engine**
|
|
11
13
|
> 100% In-Memory Execution. Zero Remote Network Calls. Zero Disk Writes. Sub-millisecond Latency.
|
|
@@ -28,6 +30,14 @@ The official Node.js / TypeScript programmatic SDK for [PrivacyScrubber.com](htt
|
|
|
28
30
|
|
|
29
31
|
> 📊 **Full Technical Benchmark**: Read the in-depth latency analysis, cold-start profiles, and architecture deep-dive in [docs/benchmarks/sdk-vs-presidio.md](https://github.com/moxno/PrivacyScrubber/blob/main/docs/benchmarks/sdk-vs-presidio.md).
|
|
30
32
|
|
|
33
|
+
### 💡 The Breach Math vs SDK Math
|
|
34
|
+
|
|
35
|
+
| The Risk You Eliminate | Real-World Incident Cost | The @privacyscrubber/sdk Solution |
|
|
36
|
+
| :--- | :--- | :--- |
|
|
37
|
+
| **1 Leaked AWS Key in Cloud LLM Logs** | **$18,400+** (Emergency key rotation, forensic audit, incident response) | **$0 / $199 flat**: Masked to `[AWS_KEY_1]` in local RAM before leaving your node |
|
|
38
|
+
| **50k Customer Records in Vector DB** | **$4.45M** (Average data breach cost, IBM Security Report) | **<1ms latency**: Sanitize streams on-the-fly before embedding vectors |
|
|
39
|
+
| **Cloud DLP Egress Fees & Latency** | **$1,500–$4,000/mo** + 350ms added prompt delay | **0 egress bytes**: Pure in-memory execution, 0 network dependencies |
|
|
40
|
+
|
|
31
41
|
---
|
|
32
42
|
|
|
33
43
|
## 📦 Installation
|
|
@@ -84,6 +94,7 @@ console.log(auditReceipt);
|
|
|
84
94
|
// > * **Risk Level:** 🟡 MODERATE EXPOSURE
|
|
85
95
|
// > * **Compliance Enforced:** ZTDS Standard, GDPR (Art. 4), CCPA/CPRA
|
|
86
96
|
// > * **Tokens Masked:** 2 (1 NAME, 1 PHONE)
|
|
97
|
+
// > * ⭐ **Star on GitHub:** [moxno/privacyscrubber-mcp](https://github.com/moxno/privacyscrubber-mcp) | **SDK & Enterprise:** [privacyscrubber.com/pricing](https://privacyscrubber.com/pricing)
|
|
87
98
|
|
|
88
99
|
// 2. Deterministically restore LLM response
|
|
89
100
|
const aiResponse = "I have queued an SMS notification for [NAME_1] at [PHONE_1].";
|
|
@@ -95,7 +106,99 @@ console.log(restoredText);
|
|
|
95
106
|
|
|
96
107
|
---
|
|
97
108
|
|
|
98
|
-
### 3.
|
|
109
|
+
### 3. Vercel AI SDK Integration (`generateText` & `streamText`)
|
|
110
|
+
|
|
111
|
+
Drop-in sanitization for Next.js and Node.js applications built with the Vercel AI SDK (`ai`):
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { generateText } from 'ai';
|
|
115
|
+
import { openai } from '@ai-sdk/openai';
|
|
116
|
+
import { sanitize, restore } from '@privacyscrubber/sdk';
|
|
117
|
+
|
|
118
|
+
export async function POST(req: Request) {
|
|
119
|
+
const { prompt } = await req.json();
|
|
120
|
+
|
|
121
|
+
// 1. Sanitize user prompt in local RAM (<1ms)
|
|
122
|
+
const { scrubbedText, tokenMap } = sanitize(prompt, {
|
|
123
|
+
profile: 'General',
|
|
124
|
+
detectSecrets: true
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// 2. Outbound call to LLM contains zero PII or credentials
|
|
128
|
+
const { text } = await generateText({
|
|
129
|
+
model: openai('gpt-4o'),
|
|
130
|
+
prompt: scrubbedText,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// 3. Deterministically restore authentic tokens locally
|
|
134
|
+
const { restoredText } = restore(text, tokenMap);
|
|
135
|
+
|
|
136
|
+
return Response.json({ response: restoredText });
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### 4. LangChain (LCEL Pipelines & `createLangChainTransform`)
|
|
143
|
+
|
|
144
|
+
Use the official middleware helper or compose inside LangChain Expression Language (LCEL) chains:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
148
|
+
import { createLangChainTransform, PrivacyScrubberEngine } from '@privacyscrubber/sdk';
|
|
149
|
+
|
|
150
|
+
// Option A: 1-line middleware helper
|
|
151
|
+
const transform = createLangChainTransform({ defaultProfile: 'Healthcare' });
|
|
152
|
+
const { scrubbedText, tokenMap } = transform.preprocess("Patient John Doe MRN-99120 prescribed Lipitor.");
|
|
153
|
+
// ... invoke LLM with scrubbedText ...
|
|
154
|
+
const restoredOutput = transform.postprocess(llmOutput, tokenMap);
|
|
155
|
+
|
|
156
|
+
// Option B: Composable LCEL Runnable chain
|
|
157
|
+
const engine = new PrivacyScrubberEngine({ defaultProfile: 'Dev' });
|
|
158
|
+
const model = new ChatOpenAI({ model: 'gpt-4o', temperature: 0 });
|
|
159
|
+
|
|
160
|
+
const secureChain = async (rawQuestion: string) => {
|
|
161
|
+
const { scrubbedText, tokenMap } = engine.sanitize(rawQuestion);
|
|
162
|
+
const response = await model.invoke(scrubbedText);
|
|
163
|
+
return engine.restore(response.content as string, tokenMap);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const result = await secureChain("Debug AWS_KEY=AKIAIOSFODNN7EXAMPLE for user alice@acme.com");
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### 5. LlamaIndex.TS (RAG Node Sanitizer)
|
|
172
|
+
|
|
173
|
+
Prevent PII poisoning in vector stores by sanitizing documents prior to indexing:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { Document } from 'llamaindex';
|
|
177
|
+
import { sanitize } from '@privacyscrubber/sdk';
|
|
178
|
+
|
|
179
|
+
// Sanitize documents before vector index ingestion (HIPAA & GDPR safe)
|
|
180
|
+
export function sanitizeDocumentsForIndex(docs: Document[]): Document[] {
|
|
181
|
+
return docs.map(doc => {
|
|
182
|
+
const { scrubbedText, telemetry } = sanitize(doc.text, {
|
|
183
|
+
profile: 'Healthcare', // Masks 18 HIPAA identifiers
|
|
184
|
+
detectSecrets: true
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return new Document({
|
|
188
|
+
text: scrubbedText,
|
|
189
|
+
metadata: {
|
|
190
|
+
...doc.metadata,
|
|
191
|
+
psRiskLevel: telemetry.riskLevel,
|
|
192
|
+
psCompliant: telemetry.frameworksList.join(',')
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### 6. RAG & Vector Database Ingestion (Pinecone, Chroma, pgvector)
|
|
99
202
|
|
|
100
203
|
Storing raw PII inside vector embeddings is irreversible and violates GDPR Article 17 (Right to be Forgotten). Sanitize document chunks prior to vectorization:
|
|
101
204
|
|
|
@@ -119,7 +222,7 @@ function prepareVectorChunk(rawDocumentChunk) {
|
|
|
119
222
|
|
|
120
223
|
---
|
|
121
224
|
|
|
122
|
-
###
|
|
225
|
+
### 7. Stateful Multi-Turn Agent Engine (`PrivacyScrubberEngine`)
|
|
123
226
|
|
|
124
227
|
Maintain token bindings across multi-step autonomous agent loops (LangChain, AutoGen, CrewAI):
|
|
125
228
|
|
|
@@ -141,6 +244,99 @@ const restored = engine.restore(agentOutputText);
|
|
|
141
244
|
|
|
142
245
|
---
|
|
143
246
|
|
|
247
|
+
### 8. High-Throughput Stream Sanitization (`createSanitizeStream`)
|
|
248
|
+
|
|
249
|
+
Sanitize massive log files, database dumps, and SSE payloads on-the-fly with <1MB heap memory. Automatically handles split chunk boundaries:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
import fs from 'node:fs';
|
|
253
|
+
import { createSanitizeStream } from '@privacyscrubber/sdk';
|
|
254
|
+
|
|
255
|
+
const sanitizeStream = createSanitizeStream({
|
|
256
|
+
profile: 'Dev',
|
|
257
|
+
detectSecrets: true
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
fs.createReadStream('prod-debug.log')
|
|
261
|
+
.pipe(sanitizeStream)
|
|
262
|
+
.pipe(fs.createWriteStream('sanitized-debug.log'));
|
|
263
|
+
|
|
264
|
+
sanitizeStream.on('finish', () => {
|
|
265
|
+
console.log(`Masked ${sanitizeStream.getTokenCount()} sensitive tokens in stream.`);
|
|
266
|
+
});
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
### 9. AI Agent Guard & Function Calling (`createGuardedTools`, `applyPatch`)
|
|
272
|
+
|
|
273
|
+
Equip autonomous agents (Cursor, Vercel AI SDK, OpenAI, LangChain) with safe tools that intercept secrets and restore authentic data on disk:
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
import { PrivacyScrubberEngine, createGuardedTools, applyPatch } from '@privacyscrubber/sdk';
|
|
277
|
+
|
|
278
|
+
const engine = new PrivacyScrubberEngine({ defaultProfile: 'Dev' });
|
|
279
|
+
const { guardExec, guardReadFile, guardApplyPatch, guardGitDiff } = createGuardedTools(engine, {
|
|
280
|
+
cwd: process.cwd(),
|
|
281
|
+
timeoutMs: 15000
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// 1. Agent runs commands safely: stdout PII is masked in RAM before LLM sees it
|
|
285
|
+
const execResult = await guardExec.execute({ command: 'npm test' });
|
|
286
|
+
|
|
287
|
+
// 2. Agent reads config safely: live secrets masked as [API_KEY_1]
|
|
288
|
+
const readResult = await guardReadFile.execute({ filePath: '.env' });
|
|
289
|
+
|
|
290
|
+
// 3. Agent modifies code: authentic secrets are restored to disk automatically
|
|
291
|
+
const patchResult = await guardApplyPatch.execute({
|
|
292
|
+
filePath: '.env',
|
|
293
|
+
content: readResult.sanitizedContent.replace('PORT=3000', 'PORT=8080')
|
|
294
|
+
});
|
|
295
|
+
// Automatically creates .env.bak before patching!
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
### 10. Automated PR Security Verification Stamp (CI/CD)
|
|
301
|
+
|
|
302
|
+
Enforce zero plaintext PII and credential leaks in your CI/CD pipeline (GitHub Actions, GitLab CI, Jenkins) before pull requests are merged into production.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
# Verify prompt templates or log exports in CI
|
|
306
|
+
npx @privacyscrubber/sdk --verify-ci prompts/user-context.txt
|
|
307
|
+
|
|
308
|
+
# Or pipe output directly from your test suite / build stream
|
|
309
|
+
cat test-output.log | npx @privacyscrubber/sdk --verify-ci
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
When verified, the SDK generates a deterministic Zero-Trust Audit Receipt for PR comments:
|
|
313
|
+
|
|
314
|
+
```markdown
|
|
315
|
+
> 🛡️ **Verified by PrivacyScrubber (ZTDS Standard)**
|
|
316
|
+
> * **Status:** ✅ PASSED · 0 PII / 0 Secrets detected in prompt pipeline
|
|
317
|
+
> * **Execution:** Local RAM (<1ms) · 0 Network Egress Bytes
|
|
318
|
+
> * **Audit Hash:** `8f4b1e...c902` (Zero-Trust Verified)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Programmatic CI assertion in Node.js test suites (Jest, Vitest, Node Test Runner):
|
|
322
|
+
|
|
323
|
+
```javascript
|
|
324
|
+
import { sanitize } from '@privacyscrubber/sdk';
|
|
325
|
+
import assert from 'node:assert';
|
|
326
|
+
|
|
327
|
+
test('pipeline prompt does not leak PII to third-party LLM', () => {
|
|
328
|
+
const prompt = buildUserPrompt(mockUserData);
|
|
329
|
+
const { scrubbedText, telemetry } = sanitize(prompt, { detectSecrets: true });
|
|
330
|
+
|
|
331
|
+
// Assert zero unmasked secrets and zero unmasked PII
|
|
332
|
+
assert.strictEqual(telemetry.riskLevel, 'SAFE / MINIMAL');
|
|
333
|
+
assert.ok(!scrubbedText.includes(mockUserData.email));
|
|
334
|
+
assert.ok(!scrubbedText.includes(mockUserData.apiKey));
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
144
340
|
## 🛡️ DevOps Secrets & Credentials Detection
|
|
145
341
|
|
|
146
342
|
Auto-detect and strip infrastructure secrets alongside consumer PII:
|
|
@@ -211,10 +407,29 @@ To acquire a commercial Developer SDK license:
|
|
|
211
407
|
- 🔌 **MCP Server**: [@privacyscrubber/mcp-server](https://www.npmjs.com/package/@privacyscrubber/mcp-server)
|
|
212
408
|
- 🧩 **Chrome Extension**: [Chrome Web Store](https://chromewebstore.google.com/detail/privacyscrubber-%E2%80%94-zero-tr/pimoejgefeilajmmbpghifdmhdlkgjol)
|
|
213
409
|
- 📖 **Developer SDK Specs**: [https://privacyscrubber.com/features/developer-sdk/](https://privacyscrubber.com/features/developer-sdk/)
|
|
410
|
+
- ⭐ **GitHub Repository**: [moxno/privacyscrubber-mcp](https://github.com/moxno/privacyscrubber-mcp) (Star us on GitHub!)
|
|
214
411
|
- 🧪 **DLP Latency Benchmark**: [https://privacyscrubber.com/dlp-speed-test/](https://privacyscrubber.com/dlp-speed-test/)
|
|
215
412
|
|
|
413
|
+
### 📚 Production Architecture Guides
|
|
414
|
+
- 🛡️ **RAG & Vector Databases**: [Sanitizing PII Before Vector DB Ingestion (Pinecone, Chroma, Qdrant)](https://privacyscrubber.com/solutions/dev/rag-vector-database-pii-masking/)
|
|
415
|
+
- 🤖 **LangChain & LlamaIndex**: [In-Memory PII Middleware for AI Agent Pipelines](https://privacyscrubber.com/solutions/agents/langchain-llamaindex-pii-anonymizer/)
|
|
416
|
+
- ⚡ **AWS Comprehend Alternative**: [In-Memory Redaction Without Egress or Cloud Overhead](https://privacyscrubber.com/solutions/dev/aws-comprehend-pii-alternative/)
|
|
417
|
+
|
|
216
418
|
---
|
|
217
419
|
|
|
218
420
|
## ⚖️ License
|
|
219
421
|
|
|
220
422
|
MIT License © 2026 PrivacyScrubber. Commercial production usage without quota limits requires an active Developer SDK or Enterprise license.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 🏛️ Intellectual Property & Virtual Patent Marking
|
|
427
|
+
|
|
428
|
+
The Zero-Trust Data Sanitization (ZTDS) architecture, in-memory deterministic tokenization, cryptographic session handoff, and headless execution methods implemented in this SDK are proprietary technology of Ilya Sibiryakov (BrandMeWeb) and are protected under **Patent Pending** status:
|
|
429
|
+
|
|
430
|
+
- **Patent Office:** State of Israel Ministry of Justice, Patent Office (ILPO)
|
|
431
|
+
- **Application Number:** `331905` (Tracking ID: `94221`)
|
|
432
|
+
- **Filing / Priority Date:** September 14, 2026 (Paris Convention Art. 4 & 35 U.S.C. § 119 Priority)
|
|
433
|
+
- **Official Title:** *SYSTEM AND METHOD FOR CLIENT-SIDE ZERO-TRUST DATA SANITIZATION AND CRYPTOGRAPHIC SESSION HANDOFF IN ARTIFICIAL INTELLIGENCE WORKFLOWS*
|
|
434
|
+
- **Virtual Patent Marking:** [privacyscrubber.com/patents/](https://privacyscrubber.com/patents/) in accordance with 35 U.S.C. § 287(a).
|
|
435
|
+
|
package/cli.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @privacyscrubber/sdk CLI & CI Security Stamp
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx @privacyscrubber/sdk <fileOrText> [options]
|
|
8
|
+
* cat prompt.txt | npx @privacyscrubber/sdk [options]
|
|
9
|
+
* npx @privacyscrubber/sdk --verify-ci <fileOrText> [options]
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import crypto from 'node:crypto';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { sanitize } from './index.js';
|
|
17
|
+
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
|
|
23
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
24
|
+
let version = '2.2.0';
|
|
25
|
+
try {
|
|
26
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
|
27
|
+
version = pkg.version || version;
|
|
28
|
+
} catch (_) {}
|
|
29
|
+
console.log(`@privacyscrubber/sdk v${version}`);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (args.includes('--help') || args.includes('-h') || (args.length === 0 && process.stdin.isTTY)) {
|
|
34
|
+
console.log(`@privacyscrubber/sdk — Zero-Trust Data Sanitization & CI Security Verification
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
npx @privacyscrubber/sdk <fileOrText> [options]
|
|
38
|
+
cat prompt.txt | npx @privacyscrubber/sdk [options]
|
|
39
|
+
npx @privacyscrubber/sdk --verify-ci <fileOrText> [options]
|
|
40
|
+
|
|
41
|
+
Options:
|
|
42
|
+
--verify-ci Generate CI/CD PR verification stamp
|
|
43
|
+
--profile <name> Specify detection profile (default: Dev)
|
|
44
|
+
--key <licKey> PrivacyScrubber PRO/TEAMS/SDK license key
|
|
45
|
+
-v, --version Show SDK version
|
|
46
|
+
-h, --help Show help screen
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
cat prompt.txt | npx @privacyscrubber/sdk
|
|
50
|
+
cat build.log | npx @privacyscrubber/sdk --verify-ci
|
|
51
|
+
npx @privacyscrubber/sdk "Contact Alice at alice@acme.com" --profile dev
|
|
52
|
+
`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Parse command-line options
|
|
57
|
+
let profile = 'Dev';
|
|
58
|
+
const profIdx = args.indexOf('--profile');
|
|
59
|
+
if (profIdx !== -1 && args[profIdx + 1]) {
|
|
60
|
+
profile = args[profIdx + 1];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const keyIdx = args.indexOf('--key');
|
|
64
|
+
if (keyIdx !== -1 && args[keyIdx + 1]) {
|
|
65
|
+
process.env.PRIVACYSCRUBBER_KEY = args[keyIdx + 1];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const isVerifyCi = args.includes('--verify-ci');
|
|
69
|
+
|
|
70
|
+
// Locate input argument (first positional parameter that is not a flag or flag value)
|
|
71
|
+
const skipIndices = new Set();
|
|
72
|
+
if (profIdx !== -1) { skipIndices.add(profIdx); skipIndices.add(profIdx + 1); }
|
|
73
|
+
if (keyIdx !== -1) { skipIndices.add(keyIdx); skipIndices.add(keyIdx + 1); }
|
|
74
|
+
|
|
75
|
+
let inputArg = null;
|
|
76
|
+
for (let i = 0; i < args.length; i++) {
|
|
77
|
+
if (skipIndices.has(i)) continue;
|
|
78
|
+
if (args[i] === '--verify-ci') continue;
|
|
79
|
+
if (args[i].startsWith('-')) continue;
|
|
80
|
+
inputArg = args[i];
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function handleExecution(text) {
|
|
85
|
+
if (isVerifyCi) {
|
|
86
|
+
if (!text || !text.trim()) {
|
|
87
|
+
console.log(`> 🛡️ **Verified by PrivacyScrubber (ZTDS Standard)**\n> * **Status:** ✅ PASSED · 0 PII / 0 Secrets detected in prompt pipeline (Empty payload)\n> * **Execution:** Local RAM (<1ms) · 0 Network Egress Bytes`);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const { scrubbedText, tokenMap, telemetry } = sanitize(text, { profile, detectSecrets: true });
|
|
92
|
+
const maskedCount = Object.keys(tokenMap || {}).length;
|
|
93
|
+
const hash = crypto.createHash('sha256').update(scrubbedText).digest('hex').slice(0, 16);
|
|
94
|
+
|
|
95
|
+
const stamp = `
|
|
96
|
+
> 🛡️ **Verified by PrivacyScrubber (ZTDS Standard)**
|
|
97
|
+
> * **Status:** ✅ PASSED · ${maskedCount} item(s) protected (${telemetry?.riskLevel || 'CLEAN'})
|
|
98
|
+
> * **Execution:** Local RAM (<1ms) · 0 Network Egress Bytes
|
|
99
|
+
> * **Audit Hash:** \`${hash}\` (Zero-Trust Verified)
|
|
100
|
+
`;
|
|
101
|
+
console.log(stamp.trim());
|
|
102
|
+
process.exit(0);
|
|
103
|
+
} else {
|
|
104
|
+
if (!text) {
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
const { scrubbedText } = sanitize(text, { profile, detectSecrets: true });
|
|
108
|
+
process.stdout.write(scrubbedText.endsWith('\n') ? scrubbedText : scrubbedText + '\n');
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (inputArg) {
|
|
114
|
+
if (fs.existsSync(inputArg)) {
|
|
115
|
+
const content = fs.readFileSync(inputArg, 'utf8');
|
|
116
|
+
handleExecution(content);
|
|
117
|
+
} else {
|
|
118
|
+
handleExecution(inputArg);
|
|
119
|
+
}
|
|
120
|
+
} else if (!process.stdin.isTTY) {
|
|
121
|
+
const chunks = [];
|
|
122
|
+
process.stdin.on('data', c => chunks.push(c));
|
|
123
|
+
process.stdin.on('end', () => {
|
|
124
|
+
const content = Buffer.concat(chunks).toString('utf8');
|
|
125
|
+
handleExecution(content);
|
|
126
|
+
});
|
|
127
|
+
} else {
|
|
128
|
+
console.error(`Error: No input provided. Use: npx @privacyscrubber/sdk <fileOrText> or pipe stdin.`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -55,6 +55,8 @@ export type PiiProfile =
|
|
|
55
55
|
export interface SanitizeOptions {
|
|
56
56
|
/** Target compliance profile (Default: 'General'). */
|
|
57
57
|
profile?: PiiProfile;
|
|
58
|
+
/** Whether to automatically detect DevOps secrets (AWS keys, JWTs, DB URIs, Stripe, OpenAI keys). */
|
|
59
|
+
detectSecrets?: boolean;
|
|
58
60
|
/** PrivacyScrubber PRO / TEAMS / SDK / ENTERPRISE license key. */
|
|
59
61
|
licenseKey?: string;
|
|
60
62
|
/** Custom regex rules array. */
|
|
@@ -147,6 +149,8 @@ export interface EngineConfig {
|
|
|
147
149
|
apiKey?: string;
|
|
148
150
|
defaultProfile?: PiiProfile;
|
|
149
151
|
profile?: PiiProfile;
|
|
152
|
+
/** Whether to automatically detect DevOps secrets (AWS keys, JWTs, DB URIs, Stripe, OpenAI keys). */
|
|
153
|
+
detectSecrets?: boolean;
|
|
150
154
|
customRules?: CustomRule[];
|
|
151
155
|
tokenLabelMap?: Record<string, string>;
|
|
152
156
|
generateReceipt?: boolean;
|
|
@@ -174,6 +178,170 @@ export function createLangChainTransform(options?: SanitizeOptions): {
|
|
|
174
178
|
postprocess: (output: string, tokenMap: Record<string, string>) => RestoreResult;
|
|
175
179
|
};
|
|
176
180
|
|
|
181
|
+
export interface ApplyPatchOptions {
|
|
182
|
+
tokenMap?: Record<string, string>;
|
|
183
|
+
engine?: PrivacyScrubberEngine;
|
|
184
|
+
createBackup?: boolean;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface ApplyPatchResult {
|
|
188
|
+
success: boolean;
|
|
189
|
+
filePath: string;
|
|
190
|
+
restoredCount: number;
|
|
191
|
+
backupCreated: boolean;
|
|
192
|
+
backupPath?: string;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export interface GuardExecParams {
|
|
196
|
+
command: string;
|
|
197
|
+
cwd?: string;
|
|
198
|
+
profile?: PiiProfile;
|
|
199
|
+
timeoutMs?: number;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface GuardExecResult {
|
|
203
|
+
command: string;
|
|
204
|
+
stdout: string;
|
|
205
|
+
stderr: string;
|
|
206
|
+
exitCode: number;
|
|
207
|
+
tokenCount: number;
|
|
208
|
+
telemetry: AuditTelemetry;
|
|
209
|
+
receipt: string;
|
|
210
|
+
responseText: string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface GuardReadFileParams {
|
|
214
|
+
filePath: string;
|
|
215
|
+
maxLines?: number;
|
|
216
|
+
profile?: PiiProfile;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface GuardReadFileResult {
|
|
220
|
+
filePath: string;
|
|
221
|
+
content: string;
|
|
222
|
+
totalLines: number;
|
|
223
|
+
wasTruncated: boolean;
|
|
224
|
+
tokenCount: number;
|
|
225
|
+
telemetry: AuditTelemetry;
|
|
226
|
+
receipt: string;
|
|
227
|
+
responseText: string;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface GuardGitDiffParams {
|
|
231
|
+
staged?: boolean;
|
|
232
|
+
cwd?: string;
|
|
233
|
+
profile?: PiiProfile;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export interface GuardGitDiffResult {
|
|
237
|
+
diff: string;
|
|
238
|
+
isStaged: boolean;
|
|
239
|
+
tokenCount: number;
|
|
240
|
+
telemetry?: AuditTelemetry;
|
|
241
|
+
receipt?: string;
|
|
242
|
+
responseText: string;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface GuardedTools {
|
|
246
|
+
guardExec: {
|
|
247
|
+
name: 'guard_exec';
|
|
248
|
+
description: string;
|
|
249
|
+
parameters: object;
|
|
250
|
+
execute: (params: GuardExecParams) => Promise<GuardExecResult>;
|
|
251
|
+
};
|
|
252
|
+
guardReadFile: {
|
|
253
|
+
name: 'guard_read_file';
|
|
254
|
+
description: string;
|
|
255
|
+
parameters: object;
|
|
256
|
+
execute: (params: GuardReadFileParams) => Promise<GuardReadFileResult>;
|
|
257
|
+
};
|
|
258
|
+
guardApplyPatch: {
|
|
259
|
+
name: 'guard_apply_patch';
|
|
260
|
+
description: string;
|
|
261
|
+
parameters: object;
|
|
262
|
+
execute: (params: { filePath: string; content: string; createBackup?: boolean }) => Promise<ApplyPatchResult & { responseText: string }>;
|
|
263
|
+
};
|
|
264
|
+
guardGitDiff: {
|
|
265
|
+
name: 'guard_git_diff';
|
|
266
|
+
description: string;
|
|
267
|
+
parameters: object;
|
|
268
|
+
execute: (params?: GuardGitDiffParams) => Promise<GuardGitDiffResult>;
|
|
269
|
+
};
|
|
270
|
+
getDefinitions: () => Array<{ type: 'function'; function: { name: string; description: string; parameters: object } }>;
|
|
271
|
+
engine: PrivacyScrubberEngine;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Creates a Node.js Transform stream for zero-trust PII sanitization.
|
|
276
|
+
*/
|
|
277
|
+
export function createSanitizeStream(options?: SanitizeOptions & { engine?: PrivacyScrubberEngine }): any;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Restores masked tokens in AI-generated code or text and writes directly to disk.
|
|
281
|
+
*/
|
|
282
|
+
export function applyPatch(filePath: string, content: string, options?: ApplyPatchOptions): ApplyPatchResult;
|
|
283
|
+
export function restoreToFile(filePath: string, content: string, tokenMapOrOptions?: Record<string, string> | ApplyPatchOptions, options?: ApplyPatchOptions): ApplyPatchResult;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Creates CISO-grade Zero-Trust Agentic Guard tools for AI agents.
|
|
287
|
+
*/
|
|
288
|
+
export function createGuardedTools(engineOrOptions?: PrivacyScrubberEngine | SanitizeOptions, toolConfig?: { cwd?: string; profile?: PiiProfile }): GuardedTools;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Stream token restorer interface for zero-latency SSE chunk processing.
|
|
292
|
+
*/
|
|
293
|
+
export interface StreamTokenRestorer {
|
|
294
|
+
/** Pushes an incoming streaming chunk and returns immediately rehydrated text. */
|
|
295
|
+
push(chunk: string): string;
|
|
296
|
+
/** Flushes any buffered incomplete tokens at the end of the stream. */
|
|
297
|
+
flush(): string;
|
|
298
|
+
/** Returns a standard Web W3C TransformStream for piping Response streams. */
|
|
299
|
+
asTransformStream(): any;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Ergonomic 1-liner: string-in, sanitized string-out without metadata ceremonies.
|
|
304
|
+
* @param text - Plaintext prompt containing potential PII/secrets.
|
|
305
|
+
* @param profile - Compliance profile (Default: 'General').
|
|
306
|
+
* @returns Scrubbed string ready to send to LLM.
|
|
307
|
+
*/
|
|
308
|
+
export function clean(text: string, profile?: PiiProfile): string;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Creates a stream token restorer that rehydrates masked tokens across chunk boundaries in real-time.
|
|
312
|
+
* @param tokenMap - Map of token bindings returned from sanitize().
|
|
313
|
+
*/
|
|
314
|
+
export function createStreamTokenRestorer(tokenMap?: Record<string, string>): StreamTokenRestorer;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Wraps an AI streaming response (e.g. OpenAI stream, Vercel AI SDK textStream)
|
|
318
|
+
* and yields real-time plain chunks with all tokens restored on the fly.
|
|
319
|
+
* @param stream - AsyncIterable or ReadableStream of string chunks or delta objects.
|
|
320
|
+
* @param tokenMap - Map of token bindings returned from sanitize().
|
|
321
|
+
*/
|
|
322
|
+
export function wrapAiStream<T = any>(
|
|
323
|
+
stream: AsyncIterable<T> | any,
|
|
324
|
+
tokenMap: Record<string, string>
|
|
325
|
+
): AsyncGenerator<string, void, unknown>;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Zero-Trust wrapper for Next.js App Router Route Handlers (route.js / route.ts).
|
|
329
|
+
* Automatically intercepts incoming Request JSON body, sanitizes PII in RAM,
|
|
330
|
+
* and passes scrubbed body along with tokenMap and stream restorer factory.
|
|
331
|
+
*/
|
|
332
|
+
export function withPrivacyScrubber(
|
|
333
|
+
handler: (req: Request, context?: any, psContext?: { tokenMap: Record<string, string>; telemetry: AuditTelemetry; createStreamRestorer: () => StreamTokenRestorer }) => any,
|
|
334
|
+
options?: SanitizeOptions
|
|
335
|
+
): (req: Request, context?: any) => Promise<any>;
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Express.js / Connect middleware for automatic zero-trust PII sanitization.
|
|
339
|
+
* Sanitizes req.body in local RAM and attaches req.psTokenMap, req.restore(), and req.createStreamRestorer().
|
|
340
|
+
*/
|
|
341
|
+
export function createExpressMiddleware(
|
|
342
|
+
options?: SanitizeOptions
|
|
343
|
+
): (req: any, res: any, next: (err?: any) => void) => void;
|
|
344
|
+
|
|
177
345
|
// Legacy exports
|
|
178
346
|
export function scrubText(
|
|
179
347
|
text: string,
|
|
@@ -198,10 +366,15 @@ export function unscrubText(
|
|
|
198
366
|
};
|
|
199
367
|
|
|
200
368
|
declare const defaultExport: {
|
|
369
|
+
clean: typeof clean;
|
|
201
370
|
sanitize: typeof sanitize;
|
|
202
371
|
scrub: typeof scrub;
|
|
203
372
|
restore: typeof restore;
|
|
204
373
|
unscrub: typeof unscrub;
|
|
374
|
+
createStreamTokenRestorer: typeof createStreamTokenRestorer;
|
|
375
|
+
wrapAiStream: typeof wrapAiStream;
|
|
376
|
+
withPrivacyScrubber: typeof withPrivacyScrubber;
|
|
377
|
+
createExpressMiddleware: typeof createExpressMiddleware;
|
|
205
378
|
validateLicense: typeof validateLicense;
|
|
206
379
|
validateLicenseKey: typeof validateLicenseKey;
|
|
207
380
|
buildAuditTelemetry: typeof buildAuditTelemetry;
|
|
@@ -210,8 +383,13 @@ declare const defaultExport: {
|
|
|
210
383
|
PrivacyScrubberLicenseError: typeof PrivacyScrubberLicenseError;
|
|
211
384
|
wrapOpenAI: typeof wrapOpenAI;
|
|
212
385
|
createLangChainTransform: typeof createLangChainTransform;
|
|
386
|
+
createSanitizeStream: typeof createSanitizeStream;
|
|
387
|
+
applyPatch: typeof applyPatch;
|
|
388
|
+
restoreToFile: typeof restoreToFile;
|
|
389
|
+
createGuardedTools: typeof createGuardedTools;
|
|
213
390
|
scrubText: typeof scrubText;
|
|
214
391
|
unscrubText: typeof unscrubText;
|
|
215
392
|
};
|
|
216
393
|
|
|
217
394
|
export default defaultExport;
|
|
395
|
+
|