import type { HookEvent, BootstrapFile } from '../src/types.js'; // Direct import of handlers for unit testing import securityBootstrapHandler from '../hooks/security-bootstrap/handler.js'; function makeBootstrapEvent(existingFiles: BootstrapFile[] = []): HookEvent { return { type: 'agent', action: 'bootstrap', sessionKey: 'test-session', timestamp: new Date(), messages: [], context: { bootstrapFiles: [...existingFiles], workspaceDir: '/tmp/test', }, }; } interface TestCase { name: string; test: () => Promise; } const TEST_CASES: TestCase[] = [ { name: 'Injects SECURITY.md into empty bootstrap', test: async () => { const event = makeBootstrapEvent(); await securityBootstrapHandler(event); const files = event.context.bootstrapFiles!; return files.length === 1 && files[0].name === 'SECURITY.md'; }, }, { name: 'SECURITY.md has content', test: async () => { const event = makeBootstrapEvent(); await securityBootstrapHandler(event); const file = event.context.bootstrapFiles![0]; return file.content.includes('Mandatory Safety Rules'); }, }, { name: 'Does not duplicate if SECURITY.md already exists', test: async () => { const existing: BootstrapFile = { name: 'SECURITY.md', path: '/custom/SECURITY.md', content: 'Custom rules', missing: false, }; const event = makeBootstrapEvent([existing]); await securityBootstrapHandler(event); return event.context.bootstrapFiles!.length === 1; }, }, { name: 'Preserves existing bootstrap files', test: async () => { const existing: BootstrapFile = { name: 'AGENTS.md', path: '/workspace/AGENTS.md', content: 'Agent rules', missing: false, }; const event = makeBootstrapEvent([existing]); await securityBootstrapHandler(event); const files = event.context.bootstrapFiles!; return files.length === 2 && files[0].name === 'AGENTS.md' && files[1].name === 'SECURITY.md'; }, }, { name: 'Skips non-bootstrap events', test: async () => { const event: HookEvent = { type: 'message', action: 'received', sessionKey: 'test', timestamp: new Date(), messages: [], context: { content: 'hello' }, }; await securityBootstrapHandler(event); return !event.context.bootstrapFiles; }, }, ]; export async function runSecurityBootstrapTests(): 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: 'Security Bootstrap', passed, failed, errors }; }