import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { ApiServer } from './src/services/apiServer.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const repoRoot = __dirname; async function verifyStaticGuards(): Promise { const apiServerSource = fs.readFileSync(path.join(repoRoot, 'src/services/apiServer.ts'), 'utf8'); const supabaseSource = fs.readFileSync(path.join(repoRoot, 'src/services/SupabaseService.ts'), 'utf8'); assert(/app\.post\('\/api\/trade',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/trade'); assert(/app\.post\('\/api\/close',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/close'); assert(/app\.post\('\/api\/chat',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/chat'); assert(/this\.io\.use\(async\s*\(socket,\s*next\)/.test(apiServerSource), 'Missing websocket auth middleware'); assert(/Unauthorized:\s*missing token/.test(apiServerSource), 'Missing explicit websocket unauthorized path'); assert(/SUPABASE_JWT_ISSUER/.test(supabaseSource), 'Missing JWT issuer check wiring'); assert(/SUPABASE_JWT_AUDIENCE/.test(supabaseSource), 'Missing JWT audience check wiring'); assert(/Invalid token issuer/.test(supabaseSource), 'Missing explicit invalid issuer rejection'); assert(/Invalid token audience/.test(supabaseSource), 'Missing explicit invalid audience rejection'); } async function verifyRuntimeGuards(): Promise { const originalStartServer = (ApiServer.prototype as any).startServer; (ApiServer.prototype as any).startServer = () => undefined; try { const server = new ApiServer(0); const req = { headers: {}, method: 'POST', path: '/api/trade' } as any; let statusCode = 200; let responseBody: any = null; let nextCalled = false; const res = { status(code: number) { statusCode = code; return this; }, json(payload: unknown) { responseBody = payload; return this; } } as any; await (server as any).requireAuth(req, res, () => { nextCalled = true; }); assert.equal(statusCode, 401, `Expected 401 for unauthorized /api/trade, got ${statusCode}`); assert.equal(nextCalled, false, 'Unauthorized /api/trade should not call next()'); assert.equal(responseBody?.error, 'Unauthorized: missing bearer token'); } finally { (ApiServer.prototype as any).startServer = originalStartServer; } } await verifyStaticGuards(); await verifyRuntimeGuards(); console.log('[security-guards] OK: static + unauthorized REST checks passed');