// RUNTIME AUTHZ HARNESS (2026-06-25) — turns the IDOR-class isolation claim from "source-proven the
// guard exists" into "runtime-proven the guard FIRES". It boots the REAL Express app (registerRoutes:
// real session + tenantMiddleware + the real requireRole/requirePlatformRole/assertTenantOwnership +
// the real handlers), logs in as a TENANT-SCOPED admin (global role non-admin + a tenant-A grant — the
// exact "admin-trap" actor), and fires that authenticated session's REAL HTTP requests at ANOTHER
// tenant's resources, asserting each is rejected. One sink per guard MECHANISM (the enumeration proved
// every sink uses one of these); plus an own-tenant positive control (proves no over-lock).
//
// HONEST CEILING: this runtime-verifies the IDOR/admin-trap isolation class enumerated this session.
// It is NOT a full red-team / pen-test (no injection/infra/session-fixation/business-logic coverage).
// Run on the throwaway DB lane. One-shot script (not node:test) so the app's schedulers don't hang.
process.env.COOKIE_SECURE = "false";
process.env.AEGIS_ALLOW_INSECURE_COOKIE = "true";
process.env.SECRET_GUARD_DEV_MODE = "warn";
process.env.NODE_ENV = "development";

import express from "express";
import { createServer } from "http";
import { sql } from "drizzle-orm";
import bcrypt from "bcryptjs";
import { auditDb } from "../server/db";
import { applyBootSchemaMigrations, initRlsPolicies } from "../server/lib/rls-init";
import { registerRoutes } from "../server/routes";

const RUN = `authz-${Date.now().toString(36)}`;
const TENANT_A = `${RUN}-tenantA`;
const TENANT_B = `${RUN}-tenantB`;
const USER_A = `${RUN}-userA`;
const PW = "Harness-Pass-123!";

let base = "";
let cookie = "";

async function req(method: string, path: string): Promise<{ status: number; body: any }> {
  const res = await fetch(`${base}${path}`, { method, headers: cookie ? { Cookie: cookie } : {} });
  let body: any = null;
  try { body = await res.json(); } catch { /* non-json */ }
  return { status: res.status, body };
}

const results: { sink: string; mechanism: string; expect: string; got: string; pass: boolean }[] = [];
function record(sink: string, mechanism: string, expect: string, pass: boolean, got: string) {
  results.push({ sink, mechanism, expect, got, pass });
}

async function main() {
  // 1. Provision the DB: current_tenant_id(), boot migrations, RLS policies (so RLS-backed routes behave).
  await auditDb.execute(sql`CREATE OR REPLACE FUNCTION public.current_tenant_id() RETURNS text LANGUAGE sql STABLE AS $func$ SELECT NULLIF(current_setting('app.current_tenant_id', true), '') $func$`);
  await applyBootSchemaMigrations();
  await initRlsPolicies();
  // Ensure the bypass role can actually bypass RLS (login + apiKeyAuth use withBypassRls). In this
  // throwaway lane the attribute may not have stuck; set it explicitly (superuser).
  await auditDb.execute(sql`ALTER ROLE aegis_rls_bypass BYPASSRLS`);
  await auditDb.execute(sql`GRANT aegis_rls_bypass TO aegis_app`);

  // 2. Seed the trap actor: a user whose GLOBAL users.role is NON-admin (risk_manager), with a
  //    tenant-A admin grant. resolveEffectiveRole -> 'admin' in tenant A (passes requireRole), but
  //    requirePlatformRole('admin') must reject (global role != admin). session.tenantId = TENANT_A.
  const hash = await bcrypt.hash(PW, 10);
  await auditDb.execute(sql`INSERT INTO users (id, username, password, role, full_name, is_active)
    VALUES (${USER_A}, ${USER_A}, ${hash}, 'risk_manager', 'Harness Tenant-A Admin', true)`);
  await auditDb.execute(sql`INSERT INTO user_tenant_roles (user_id, tenant_id, role, granted_by, is_active, is_primary)
    VALUES (${USER_A}, ${TENANT_A}, 'admin', 'harness', true, true)`);
  // (No tenants-table row needed: login derives session.tenantId from user_tenant_roles, the GUC is a
  // plain string, and the probed routes do not FK to tenants.)
  // 3. Seed a TENANT_B DSAR purge job (so the dsar-filter sink has cross-tenant data to (not) leak).
  await auditDb.execute(sql`INSERT INTO dsar_purge_jobs (id, job_ref, dsar_id, customer_ref, status, enqueued_by, tenant_id)
    VALUES (${RUN + "-jobB"}, ${RUN + "-jobB"}, ${RUN + "-dsarB"}, ${RUN + "-custB"}, 'pending', 'harness', ${TENANT_B})`);

  // DIAGNOSTIC: confirm the seed row + the login-style bypass read both see it.
  const { withBypassRls } = await import("../server/db");
  const chk: any = await auditDb.execute(sql`SELECT user_id, tenant_id, is_primary, is_active FROM user_tenant_roles WHERE user_id = ${USER_A}`);
  console.log("• seeded UTR (auditDb):", JSON.stringify(chk.rows ?? chk));
  const byp: any = await withBypassRls((b: any) => b.execute(sql`SELECT count(*)::int AS c FROM user_tenant_roles WHERE user_id = ${USER_A} AND is_primary = true AND is_active = true`));
  console.log("• login-style bypass count:", JSON.stringify(byp.rows ?? byp));

  // 4. Boot the REAL app.
  const app = express();
  app.use(express.json());
  const httpServer = createServer(app);
  await registerRoutes(httpServer, app);
  await new Promise<void>((resolve) => httpServer.listen(0, () => resolve()));
  const addr = httpServer.address() as any;
  base = `http://127.0.0.1:${addr.port}`;

  // 5. Real login -> capture the session cookie.
  const loginRes = await fetch(`${base}/api/auth/login`, {
    method: "POST", headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ username: USER_A, password: PW }),
  });
  const setCookie = loginRes.headers.get("set-cookie");
  cookie = setCookie ? setCookie.split(";")[0] : "";
  console.log(`• login status ${loginRes.status}; session cookie ${cookie ? "captured" : "MISSING"}`);
  if (loginRes.status !== 200 || !cookie) {
    console.error("FATAL: login failed — cannot run authenticated cross-tenant probes.", await loginRes.text().catch(() => ""));
    process.exit(2);
  }

  // 6. Fire tenant-A's authenticated session at TENANT-B / platform resources.
  // (a) OWNERSHIP guard (assertTenantOwnership): param tenant != session tenant -> 403.
  let r = await req("GET", `/api/whitelabel/${TENANT_B}`);
  record(`GET /api/whitelabel/:tenantId (B)`, "assertTenantOwnership", "403", r.status === 403, String(r.status));

  // (b) PLATFORM gate (requirePlatformRole): a tenant-scoped admin (global non-admin) -> 403.
  r = await req("GET", `/api/billing/tenants/TEN-DOESNOTMATTER`);
  record(`GET /api/billing/tenants/:id`, "requirePlatformRole", "403", r.status === 403, String(r.status));
  r = await req("GET", `/api/finops/budgets`);
  record(`GET /api/finops/budgets (list-all)`, "requirePlatformRole", "403", r.status === 403, String(r.status));

  // (c) DSAR app-level tenant filter: list returns only the caller's tenant's jobs, NOT tenant-B's.
  r = await req("GET", `/api/dsar/purge/jobs`);
  const leakedB = Array.isArray(r.body) && r.body.some((j: any) => j.tenantId === TENANT_B || j.id === `${RUN}-jobB`);
  record(`GET /api/dsar/purge/jobs`, "dsar tenant-filter", "no tenant-B job", r.status === 200 && !leakedB, `status ${r.status}, leakedB=${leakedB}`);

  // (d) OWN-tenant positive control (no over-lock): own tenant must NOT be 403.
  r = await req("GET", `/api/whitelabel/${TENANT_A}`);
  record(`GET /api/whitelabel/:tenantId (own A)`, "ownership (allow own)", "not 403", r.status !== 403, String(r.status));

  // 7. Report.
  console.log("\n=== RUNTIME AUTHZ HARNESS RESULTS ===");
  let allPass = true;
  for (const x of results) {
    console.log(`${x.pass ? "PASS" : "FAIL"}  [${x.mechanism}]  ${x.sink}  — expect ${x.expect}, got ${x.got}`);
    if (!x.pass) allPass = false;
  }
  console.log(`\nOVERALL: ${allPass ? "ALL PASS — isolation guards FIRE at runtime for real cross-tenant requests" : "FAILURES PRESENT"}`);

  // cleanup
  try {
    await auditDb.execute(sql`DELETE FROM dsar_purge_jobs WHERE id LIKE ${RUN + "%"}`);
    await auditDb.execute(sql`DELETE FROM user_tenant_roles WHERE user_id = ${USER_A}`);
    await auditDb.execute(sql`DELETE FROM users WHERE id = ${USER_A}`);
    await auditDb.execute(sql`DELETE FROM tenants WHERE id IN (${TENANT_A}, ${TENANT_B})`);
  } catch { /* throwaway DB */ }
  process.exit(allPass ? 0 : 1);
}
main().catch((e) => { console.error("HARNESS ERROR:", e?.stack ?? e?.message ?? e); process.exit(3); });
