4616308402
Used by Stop-hook before JSONL write. 6 Vitest cases including idempotence and recursive object sanitization. Per Pravila §16.2 + ADR-011 + spec §5.4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
42 lines
1.3 KiB
JavaScript
42 lines
1.3 KiB
JavaScript
/**
|
|
* PII filter for brain governance observer (B2).
|
|
* Used by Stop-hook before JSONL write — per Pravila §16.2 + ADR-011 + spec §5.4.
|
|
*
|
|
* Patterns covered:
|
|
* RU_PHONE — +7XXXXXXXXXX (10 digits after +7)
|
|
* EMAIL — any user@domain.tld
|
|
* SENTRY_TOKEN — sntrys?_<12+ alphanum>
|
|
* OPENAI_TOKEN — sk-<20+ alphanum>
|
|
* GENERIC_BEARER — Bearer <20+ token chars>
|
|
*
|
|
* Security Guidance #40: pure regex — no exec/execSync.
|
|
*/
|
|
|
|
const RU_PHONE = /\+7\d{10}/g;
|
|
const EMAIL = /[\w.+-]+@[\w-]+\.[\w.-]+/g;
|
|
const SENTRY_TOKEN = /sntrys?_[A-Za-z0-9]{12,}/g;
|
|
const OPENAI_TOKEN = /sk-[A-Za-z0-9]{20,}/g;
|
|
const GENERIC_BEARER = /Bearer\s+[A-Za-z0-9._-]{20,}/g;
|
|
|
|
function sanitizeString(s) {
|
|
if (typeof s !== 'string') return s;
|
|
return s
|
|
.replace(RU_PHONE, '+7XXXXXXXXXX')
|
|
.replace(EMAIL, '***@***')
|
|
.replace(SENTRY_TOKEN, '[REDACTED:sentry]')
|
|
.replace(OPENAI_TOKEN, '[REDACTED:openai]')
|
|
.replace(GENERIC_BEARER, '[REDACTED:bearer]');
|
|
}
|
|
|
|
export function sanitize(input) {
|
|
if (typeof input === 'string') return sanitizeString(input);
|
|
if (input === null || input === undefined) return input;
|
|
if (Array.isArray(input)) return input.map(sanitize);
|
|
if (typeof input === 'object') {
|
|
const out = {};
|
|
for (const [k, v] of Object.entries(input)) out[k] = sanitize(v);
|
|
return out;
|
|
}
|
|
return input;
|
|
}
|