acc9045016
Новый общий secret-scan.mjs (анти-дрейф — один источник секрет-паттернов на 7.1 read-выдачу
и 7.3 egress): scanSecrets(text) → {found, hits}. Секрет-подмножество (не PII): PEM private
keys, токены провайдеров (AWS/GitHub/OpenAI/Slack/Sentry/Yandex/JWT/Bearer, regex согласованы
с observer-pii-filter), строки подключения с кредами (scheme://user:pass@). Чистая, без /g.
enforce-read-path-deny.decide расширен опциональным content: путь-деналист — грубый пре-фильтр;
если выдача Read содержит секрет (даже из не-protected пути) → block (fail-CLOSE). Активируется
PostToolUse-обёрткой (content); PreToolUse path-слой backward-compat не тронут.
+9 (secret-scan) +4 (read-path-deny) тестов. Дыра 6 (read без контента) закрыта.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
2.6 KiB
JavaScript
47 lines
2.6 KiB
JavaScript
// tools/secret-scan.test.mjs
|
|
// Машина 5 Пакет 7 (Блок 4) — общий скан секрет-паттернов в тексте. Используется
|
|
// read-path-deny (7.1, скан выдачи Read) и mcp-classification (7.3, скан исходящего egress).
|
|
// Секрет-подмножество (НЕ PII): приватные ключи PEM, известные токены (AWS/GitHub/OpenAI/
|
|
// Slack/Sentry/Yandex/JWT/Bearer), строки подключения с встроенными кредами. Анти-дрейф —
|
|
// один источник секрет-паттернов на оба канала (как classify-destructive для разрушительности).
|
|
import { describe, it, expect } from 'vitest';
|
|
import { scanSecrets } from './secret-scan.mjs';
|
|
|
|
describe('scanSecrets (Пакет 7): детект секрет-паттернов в тексте', () => {
|
|
it('PEM приватный ключ → found', () => {
|
|
const r = scanSecrets('foo\n-----BEGIN RSA PRIVATE KEY-----\nMII...\n-----END RSA PRIVATE KEY-----');
|
|
expect(r.found).toBe(true);
|
|
expect(r.hits).toContain('pem-private-key');
|
|
});
|
|
it('AWS Access Key (AKIA) → found', () => {
|
|
expect(scanSecrets('key=AKIAIOSFODNN7EXAMPLE').found).toBe(true);
|
|
});
|
|
it('GitHub token (ghp_) → found', () => {
|
|
expect(scanSecrets('token ghp_0123456789abcdefghijklmnopqrstuvwxyz').found).toBe(true);
|
|
});
|
|
it('OpenAI sk- токен → found', () => {
|
|
expect(scanSecrets('OPENAI=sk-abcdefghij0123456789ABCDE').found).toBe(true);
|
|
});
|
|
it('строка подключения с кредами (postgres://user:pass@host) → found', () => {
|
|
const r = scanSecrets('DATABASE_URL=postgres://admin:s3cretPwd@db.local:5432/app');
|
|
expect(r.found).toBe(true);
|
|
expect(r.hits).toContain('conn-string-creds');
|
|
});
|
|
it('Bearer-токен → found', () => {
|
|
expect(scanSecrets('Authorization: Bearer abcdefghijklmnopqrstuvwx').found).toBe(true);
|
|
});
|
|
it('обычный код без секретов → not found, hits пуст', () => {
|
|
const r = scanSecrets('export function add(a, b) { return a + b; }');
|
|
expect(r.found).toBe(false);
|
|
expect(r.hits).toEqual([]);
|
|
});
|
|
it('строка подключения БЕЗ кредов (postgres://host) → not found (нет user:pass@)', () => {
|
|
expect(scanSecrets('postgres://db.local:5432/app').found).toBe(false);
|
|
});
|
|
it('пустой/невалидный вход → not found, не бросает', () => {
|
|
expect(scanSecrets(null).found).toBe(false);
|
|
expect(scanSecrets(undefined).found).toBe(false);
|
|
expect(scanSecrets('').found).toBe(false);
|
|
});
|
|
});
|