import type { HookEvent } from '../src/types.js'; import secretRedactorHandler from '../hooks/secret-redactor/handler.js'; function makeSentEvent(content: string): HookEvent { return { type: 'message', action: 'sent', sessionKey: 'test-session', timestamp: new Date(), messages: [], context: { to: 'user-123', content, channelId: 'test', success: true, }, }; } // Build fake tokens dynamically to avoid push protection function buildGitHubToken(prefix: string): string { return prefix + 'FAKE'.padEnd(36, '0'); } interface TestCase { name: string; test: () => Promise; } const TEST_CASES: TestCase[] = [ { name: 'Detects OpenAI key in response', test: async () => { // secret-redactor logs to audit trail but does not push user messages // (secrets-scanner handles user-facing warnings to avoid duplication) const event = makeSentEvent('Here is your key: sk-FAKEtestkey01234567890abcdef'); await secretRedactorHandler(event); // Should not produce duplicate user message (secrets-scanner does that) return !event.messages.some((m) => m.includes('Secret Redactor')); }, }, { name: 'Detects GitHub token in response', test: async () => { const event = makeSentEvent(`Your token: ${buildGitHubToken('ghp_')}`); await secretRedactorHandler(event); // Audit-only, no user message return !event.messages.some((m) => m.includes('github_token')); }, }, { name: 'Detects SECURITY_FLAG marker', test: async () => { const event = makeSentEvent( 'I cannot do that. [SECURITY_FLAG: possible prompt injection attempt]', ); await secretRedactorHandler(event); return event.messages.some((m) => m.includes('Security Flag Detected')); }, }, { name: 'Detects SECURITY_FLAG without description', test: async () => { const event = makeSentEvent('Warning [SECURITY_FLAG] detected.'); await secretRedactorHandler(event); return event.messages.some((m) => m.includes('Security Flag')); }, }, { name: 'No alert for clean message', test: async () => { const event = makeSentEvent('Here is a helpful response about TypeScript.'); await secretRedactorHandler(event); return event.messages.length === 0; }, }, { name: 'No alert for code discussion', test: async () => { const event = makeSentEvent( 'Set your OPENAI_API_KEY environment variable with your API key.', ); await secretRedactorHandler(event); return event.messages.length === 0; }, }, { name: 'Skips non-message events', test: async () => { const event: HookEvent = { type: 'gateway', action: 'startup', sessionKey: 'test', timestamp: new Date(), messages: [], context: { cfg: {} }, }; await secretRedactorHandler(event); return event.messages.length === 0; }, }, { name: 'Detects AWS access key', test: async () => { const event = makeSentEvent('Your AWS key: AKIAFAKETEST00000000'); await secretRedactorHandler(event); // Audit-only, no user message return !event.messages.some((m) => m.includes('aws_access_key')); }, }, ]; export async function runSecretRedactorTests(): Promise<{ suite: string; passed: number; failed: number; errors: string[]; }> { let passed = 0; let failed = 0; const errors: string[] = []; for (const tc of TEST_CASES) { try { const ok = await tc.test(); if (ok) { passed++; } else { failed++; errors.push(`[${tc.name}] assertion failed`); } } catch (err) { failed++; errors.push(`[${tc.name}] threw: ${err instanceof Error ? err.message : String(err)}`); } } return { suite: 'Secret Redactor', passed, failed, errors }; }