67 lines
3.6 KiB
TypeScript
67 lines
3.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { readFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
|
|
const serverSource = readFileSync(join(process.cwd(), 'src/server.ts'), 'utf8');
|
|
|
|
function routeBlock(startMarker: string, endMarker: string): string {
|
|
const start = serverSource.indexOf(startMarker);
|
|
expect(start, `missing route marker ${startMarker}`).toBeGreaterThanOrEqual(0);
|
|
const end = serverSource.indexOf(endMarker, start);
|
|
expect(end, `missing end marker ${endMarker}`).toBeGreaterThan(start);
|
|
return serverSource.slice(start, end);
|
|
}
|
|
|
|
describe('local API authorization hardening invariants', () => {
|
|
it('/api/events does not grant wildcard CORS and rejects foreign browser origins before opening SSE', () => {
|
|
const route = routeBlock("app.get('/api/events'", '// =============================================================================\n// API ENDPOINTS - HEALTH & STATUS');
|
|
|
|
expect(route).not.toMatch(/Access-Control-Allow-Origin['"]\s*:\s*['"]\*['"]/);
|
|
expect(route).toMatch(/const\s+origin\s*=\s*_?req\.get\(['"]origin['"]\)/);
|
|
expect(route).toMatch(/origin\s*&&\s*!isLoopbackOrigin\(origin\)/);
|
|
expect(route).toMatch(/Access-Control-Allow-Origin['"]\]\s*=\s*origin/);
|
|
});
|
|
|
|
it('/api/tools/execute binds approval to the parsed command target, not a caller-supplied target override', () => {
|
|
const route = routeBlock("app.post('/api/tools/execute'", "app.post('/api/tools/recon'");
|
|
|
|
expect(route).not.toMatch(/body\.target\s*\|\|\s*inferCommandTarget\(parsed\)/);
|
|
expect(route).toMatch(/resolveCommandExecutionTarget\(body, parsed\)/);
|
|
expect(route).toMatch(/guardAction\(body,\s*['"]command_execution['"],\s*targetResolution\.target/);
|
|
});
|
|
|
|
it('Admiral live launch permits expanded targets only with explicit operator approval receipts', () => {
|
|
const route = routeBlock("app.post('/api/admiral/launch'", '// =============================================================================\n// BOUNTY PLATFORM INTEGRATIONS');
|
|
|
|
expect(route).toMatch(/ensureExecTargetsAuthorized\(execConfig\.targets,\s*brief\.target,\s*req\.body/);
|
|
expect(route).toMatch(/outOfScopeTargets\.length/);
|
|
expect(route.indexOf('ensureExecTargetsAuthorized(execConfig.targets, brief.target'))
|
|
.toBeLessThan(route.indexOf('bringUpMissionFromPlan(execConfig, generalConfig)'));
|
|
expect(route).toMatch(/approvals/);
|
|
expect(route).toMatch(/approvalIds/);
|
|
});
|
|
|
|
it('approval lookup requires explicit receipt ids and wildcard hosts require opt-in', () => {
|
|
const findApproval = routeBlock('function findApproval(', 'function createApprovalRequest');
|
|
|
|
expect(findApproval).toMatch(/body\.approvalId/);
|
|
expect(findApproval).toMatch(/body\.approvalIds/);
|
|
expect(findApproval).not.toMatch(/\[\.\.\.approvalRequests\.values\(\)\]/);
|
|
expect(serverSource).toMatch(/Wildcard host approval requires explicit opt-in/);
|
|
expect(serverSource).toMatch(/body\.allowWildcard !== true/);
|
|
});
|
|
|
|
it('authorize-target only approves existing pending receipts and cannot mint broad active-action approvals', () => {
|
|
const route = routeBlock("app.post('/api/approvals/authorize-target'", "app.post('/api/approvals/:id/reject'");
|
|
|
|
expect(route).toMatch(/approvalId/);
|
|
expect(route).toMatch(/approvalIds/);
|
|
expect(route).toMatch(/approvalRequests\.get\(id\)/);
|
|
expect(route).toMatch(/approval\.status !== 'pending'/);
|
|
expect(route).toMatch(/Math\.min\(30/);
|
|
expect(route).not.toMatch(/createApprovalRequest/);
|
|
expect(route).not.toMatch(/allowedActions/);
|
|
expect(route).not.toMatch(/command_execution['"],\s*['"]autonomous_execution/);
|
|
});
|
|
});
|