#!/usr/bin/env node
/**
 * CI gate — globalApiAuth mounted; mutating routes declare requireAuth or ingestAuth.
 */
'use strict';

const fs = require('fs');
const path = require('path');

const appPath = path.join(__dirname, '../src/api/app.js');
const appSrc = fs.readFileSync(appPath, 'utf8');

let failed = false;

if (!/app\.use\(globalApiAuth\)/.test(appSrc)) {
  console.error('[verify:route-auth] FAIL — globalApiAuth middleware not mounted in app.js');
  failed = true;
}

function extractRouteBlocks(src) {
  const blocks = [];
  const re = /app\.(get|post|put|patch|delete)\(\s*['"]([^'"]+)['"]/gi;
  let m;
  while ((m = re.exec(src)) !== null) {
    const start = m.index;
    let depth = 0;
    let i = src.indexOf('(', start);
    while (i < src.length) {
      const ch = src[i];
      if (ch === '(') depth++;
      else if (ch === ')') {
        depth--;
        if (depth === 0) {
          blocks.push({
            method: m[1].toUpperCase(),
            path: m[2],
            block: src.slice(start, i + 1),
          });
          break;
        }
      }
      i++;
    }
  }
  return blocks;
}

const routes = extractRouteBlocks(appSrc);
const writeMethods = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
const anonymousWrites = [];

for (const r of routes) {
  if (!writeMethods.has(r.method)) continue;
  if (/requireAuth|ingestAuth/.test(r.block)) continue;
  if (r.path.startsWith('/api/ingest/')) continue;
  if (r.method === 'POST' && r.path === '/api/auth/login') continue;
  if (r.method === 'POST' && r.path === '/api/setup/bootstrap') continue;
  if (r.method === 'POST' && r.path.startsWith('/api/artifacts/verify')) continue;
  anonymousWrites.push(`${r.method} ${r.path}`);
}

if (anonymousWrites.length > 0) {
  console.error('[verify:route-auth] FAIL — write routes without requireAuth/ingestAuth in route block:');
  anonymousWrites.forEach(x => console.error('  ', x));
  failed = true;
}

console.log(`[verify:route-auth] Parsed ${routes.length} routes; unauthenticated writes: ${anonymousWrites.length}`);

const sensitiveGetPrefixes = ['/api/security/', '/api/admin/', '/api/audit', '/api/fleet'];
const openSensitiveGets = [];
for (const r of routes) {
  if (r.method !== 'GET') continue;
  if (!sensitiveGetPrefixes.some((pre) => r.path === pre || r.path.startsWith(pre))) continue;
  if (/requireAuth|ingestAuth/.test(r.block)) continue;
  openSensitiveGets.push(`GET ${r.path}`);
}
if (openSensitiveGets.length > 0) {
  console.warn('[verify:route-auth] WARN — sensitive GET routes without requireAuth in block:');
  openSensitiveGets.slice(0, 12).forEach((x) => console.warn('  ', x));
  if (openSensitiveGets.length > 12) console.warn(`  … and ${openSensitiveGets.length - 12} more`);
}

if (failed) process.exit(1);
console.log('[verify:route-auth] OK');
