// kb#147 HTTP-layer proof, run with: node src/trust-gate-http.test.mjs
//
// Proves the Authorization-header -> agent-id -> trust-rank path end to end
// over real HTTP, WITHOUT touching the live agap-mcp container (:3100),
// LiteLLM, or Vaultwarden: this spins up a throwaway express app on an
// ephemeral local port using the exact same trust-gate.js functions
// server.js imports, with a synthetic registry + token map (no real bw
// session, no real credentials). It exercises authHeaderToken() (the bit
// trust-gate.test.mjs's pure unit tests can't reach, since it needs a real
// `req` object) on top of the already-unit-tested trustRankOf/vaultAllowed.

import assert from 'node:assert/strict';
import express from 'express';
import {
  loadTokenMap,
  resolveCallerAgent,
  vaultAllowed,
  authHeaderToken,
  isVaultTool,
  _resetRegistryCacheForTests,
} from './trust-gate.js';

const registry = {
  trust_classes: {
    trusted: { rank: 2 },
    sandboxed: { rank: 1 },
    untrusted: { rank: 0 },
  },
  agents: [
    { id: 'adolf', trust_class: 'trusted' },
    { id: 'torgash', trust_class: 'sandboxed' },
  ],
};
_resetRegistryCacheForTests(registry);

const tokenMap = loadTokenMap(JSON.stringify({
  'tok-adolf-e2e-test': 'adolf',
  'tok-torgash-e2e-test': 'torgash',
}));

// A minimal stand-in for server.js's app.all('/mcp', ...) handler: resolve
// the caller from the Authorization header, then simulate a vw_get_password
// tool call gated the same way requireVaultAccess() gates it in server.js.
const app = express();
app.post('/mcp', (req, res) => {
  const callerAgentId = resolveCallerAgent(authHeaderToken(req), tokenMap);
  const toolName = req.body?.tool || 'vw_get_password';
  if (isVaultTool(toolName) && !vaultAllowed(callerAgentId, registry)) {
    return res.status(200).json({ isError: true, error: `vault access denied for caller=${callerAgentId || '(none)'}` });
  }
  return res.status(200).json({ isError: false, caller: callerAgentId });
});

const server = app.listen(0);
const port = server.address().port;

async function post(token) {
  const res = await fetch(`http://127.0.0.1:${port}/mcp`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
    },
    body: JSON.stringify({ tool: 'vw_get_password' }),
  });
  return res.json();
}

let passed = 0;
async function check(label, fn) {
  await fn();
  passed++;
  console.log(`ok - ${label}`);
}

try {
  await check('trusted agent (adolf) bearer token -> vw_get_password allowed over real HTTP', async () => {
    const body = await post('tok-adolf-e2e-test');
    assert.equal(body.isError, false);
    assert.equal(body.caller, 'adolf');
  });

  await check('sandboxed agent (torgash) bearer token -> vw_get_password DENIED over real HTTP', async () => {
    const body = await post('tok-torgash-e2e-test');
    assert.equal(body.isError, true);
    assert.match(body.error, /vault access denied/);
  });

  await check('no Authorization header at all -> vw_get_password DENIED over real HTTP', async () => {
    const body = await post(null);
    assert.equal(body.isError, true);
  });

  await check('garbage/unknown token -> vw_get_password DENIED over real HTTP', async () => {
    const body = await post('this-token-was-never-issued');
    assert.equal(body.isError, true);
  });

  console.log(`\n${passed} passed`);
} finally {
  server.close();
  _resetRegistryCacheForTests(null);
}
