{"version":3,"sources":["../src/index.ts","../src/ca-store.ts","../src/config.ts","../src/proxy.ts","../src/matcher.ts","../src/auth.ts","../src/grants-client.ts","../src/audit.ts","../src/ssrf.ts","../src/connect.ts","../src/mitm-connect.ts","../src/secrets-store.ts","../src/secrets-match.ts"],"sourcesContent":["#!/usr/bin/env node\nimport type { DaemonIdentity, MultiAgentProxyConfig } from './types.js'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { createServer } from 'node:http'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { parseArgs } from 'node:util'\nimport { createLeafCertCache, loadOrCreateCa } from './ca-store.js'\nimport { loadMultiAgentConfig } from './config.js'\nimport { createNodeHandler } from './proxy.js'\nimport { parseSecretsBlob } from './secrets-store.js'\n\nfunction loadIdentity(): DaemonIdentity {\n  const path = join(homedir(), '.config', 'apes', 'auth.json')\n  if (!existsSync(path)) {\n    console.error(`[openape-proxy] missing ${path} — run \\`apes login\\` first`)\n    process.exit(2)\n  }\n  const raw = JSON.parse(readFileSync(path, 'utf-8')) as {\n    email?: string\n    idp?: string\n    access_token?: string\n    bearer?: string\n  }\n  // Production apes-login writes OAuth-2.0 standard `access_token`; some test\n  // harnesses use `bearer` for brevity. Accept either.\n  const bearer = raw.access_token ?? raw.bearer\n  if (!raw.email || !raw.idp || !bearer) {\n    console.error(`[openape-proxy] malformed ${path} — re-run \\`apes login\\``)\n    process.exit(2)\n  }\n  return { email: raw.email, idpUrl: raw.idp, bearer }\n}\n\nconst { values } = parseArgs({\n  options: {\n    config: { type: 'string', short: 'c', default: 'config.toml' },\n    'dry-run': { type: 'boolean', default: false },\n    'mandatory-auth': { type: 'boolean', default: false },\n    global: { type: 'boolean', default: false },\n    port: { type: 'string' },\n  },\n})\n\nif (values.global) {\n  // Bun's `node:tls` compat layer does not handle TLSSocket-on-existing-socket\n  // reliably for the CONNECT-MITM pipeline (the inner TLS handshake never\n  // completes — no `secure`, no `error`, no `close` events fire). Detect Bun\n  // and refuse with a helpful pointer at Node before doing any work.\n  if ((process.versions as Record<string, string | undefined>).bun) {\n    console.error(\n      '[openape-proxy] --global mode requires Node (Bun is not supported).\\n'\n      + '  Bun\\'s node:tls compat layer does not handle TLSSocket-on-existing-socket\\n'\n      + '  for the CONNECT-MITM pipeline. Re-run with `node` directly, or use the\\n'\n      + '  built `openape-proxy` binary (its shebang invokes Node).',\n    )\n    process.exit(2)\n  }\n\n  // --global mode: read secrets TOML from stdin (max 4 KiB enforced by\n  // parseSecretsBlob; we cap stdin at 8 KiB to surface oversize input early\n  // with a friendlier error than waiting for the parser).\n  const stdinBuf: Buffer[] = []\n  let total = 0\n  let aborted = false\n  process.stdin.on('data', (chunk: Buffer) => {\n    if (aborted) return\n    total += chunk.length\n    if (total > 8 * 1024) {\n      console.error('[openape-proxy] stdin > 8 KiB, refusing')\n      aborted = true\n      process.exit(2)\n    }\n    stdinBuf.push(chunk)\n  })\n  process.stdin.on('end', () => {\n    if (aborted) return\n    const blob = Buffer.concat(stdinBuf).toString('utf-8')\n    if (!blob.trim()) {\n      console.error('[openape-proxy] --global requires secrets TOML on stdin')\n      process.exit(2)\n    }\n    let store\n    try {\n      store = parseSecretsBlob(blob)\n    }\n    catch (err) {\n      console.error(`[openape-proxy] secrets parse error: ${(err as Error).message}`)\n      process.exit(2)\n    }\n    const identity = loadIdentity()\n    const port = Number.parseInt(values.port ?? '18789')\n\n    // Bootstrap (or reuse) the per-user MITM CA stored under\n    // ~/.openape/proxy/. Tagging the CN with the operator email keeps\n    // multi-account dev machines self-explanatory in the system trust store.\n    const ca = loadOrCreateCa({\n      certPath: join(homedir(), '.openape', 'proxy', 'ca.crt'),\n      keyPath: join(homedir(), '.openape', 'proxy', 'ca.key'),\n      subjectCN: `OpenApe Proxy CA (${identity.email})`,\n    })\n    if (ca.created) {\n      console.log(`[openape-proxy] generated new CA at ~/.openape/proxy/ca.crt`)\n    }\n    const leafCache = createLeafCertCache(ca, { capacity: 256 })\n\n    // Daemon mode synthesizes a minimal MultiAgentProxyConfig from the loaded\n    // identity. `default_action: 'allow'` keeps Task 15 a pure bind/CA wiring\n    // milestone — Task 16 will add the daemon-mode auth bypass on top.\n    const config: MultiAgentProxyConfig = {\n      proxy: { listen: `127.0.0.1:${port}`, default_action: 'allow' },\n      agents: [{ email: identity.email, idp_url: identity.idpUrl }],\n    }\n\n    const handler = createNodeHandler(config, { secretsStore: store, leafCache, daemonMode: true })\n    const server = createServer(handler.handleRequest)\n    server.on('connect', handler.handleConnect)\n    server.listen(port, '127.0.0.1', () => {\n      // `--port 0` lets the OS pick a free port — surface the actual bound\n      // port so harness/orchestrators can grep the banner reliably.\n      const addr = server.address()\n      const actualPort = typeof addr === 'object' && addr ? addr.port : port\n      // Emit identity / secrets / OPENAPE_PROXY hint BEFORE the canonical\n      // `listening on 127.0.0.1:<port>` banner. The banner is what spawners\n      // grep to confirm the daemon is up; printing the hint first guarantees\n      // it lives in the same captured chunk that the spawner reads.\n      console.log(`[openape-proxy] identity: ${identity.email} (${identity.idpUrl})`)\n      const names = store.entries.map(e => e.name).join(', ')\n      console.log(`[openape-proxy] secrets: ${names}`)\n      console.log(`[openape-proxy] export OPENAPE_PROXY=127.0.0.1:${actualPort}`)\n      console.log(`[openape-proxy] listening on 127.0.0.1:${actualPort}`)\n    })\n\n    process.on('SIGINT', () => server.close(() => process.exit(0)))\n    process.on('SIGTERM', () => server.close(() => process.exit(0)))\n  })\n  process.stdin.resume()\n}\nelse {\n  const configPath = values.config!\n\n  console.log(`[openape-proxy] Loading config from ${configPath}`)\n  const config = loadMultiAgentConfig(configPath, {\n    mandatoryAuth: values['mandatory-auth'] || undefined,\n  })\n\n  if (values['dry-run']) {\n    console.log('[openape-proxy] DRY RUN mode — logging only, not blocking')\n    console.log('[openape-proxy] Config loaded:')\n    console.log(`  Listen: ${config.proxy.listen}`)\n    console.log(`  Default action: ${config.proxy.default_action}`)\n    console.log(`  Mandatory auth: ${config.proxy.mandatory_auth ?? false}`)\n    console.log(`  Agents: ${config.agents.length}`)\n    for (const agent of config.agents) {\n      const allowCount = agent.allow?.length ?? 0\n      const denyCount = agent.deny?.length ?? 0\n      const grantCount = agent.grant_required?.length ?? 0\n      console.log(`    ${agent.email} (${agent.idp_url}) — ${allowCount} allow, ${denyCount} deny, ${grantCount} grant`)\n    }\n    process.exit(0)\n  }\n\n  const handler = createNodeHandler(config)\n\n  const port = Number.parseInt(config.proxy.listen.split(':')[1] || '9090')\n  const hostname = config.proxy.listen.split(':')[0] || '127.0.0.1'\n\n  const server = createServer(handler.handleRequest)\n  server.on('connect', handler.handleConnect)\n\n  server.listen(port, hostname, () => {\n    // When configured with port 0, the OS assigns a free port — use the actual\n    // bound port for the log line so external orchestrators (apes proxy --) can\n    // grep this line to discover where to connect.\n    const addr = server.address()\n    const actualPort = typeof addr === 'object' && addr ? addr.port : port\n    console.log(`[openape-proxy] Listening on http://${hostname}:${actualPort}`)\n    console.log(`[openape-proxy] CONNECT tunneling enabled`)\n    console.log(`[openape-proxy] Mandatory auth: ${config.proxy.mandatory_auth ?? false}`)\n    console.log(`[openape-proxy] Agents: ${config.agents.map(a => a.email).join(', ')}`)\n    console.log(`[openape-proxy] Default action: ${config.proxy.default_action}`)\n  })\n\n  // Graceful shutdown\n  process.on('SIGINT', () => {\n    console.log('\\n[openape-proxy] Shutting down...')\n    server.close()\n    process.exit(0)\n  })\n\n  process.on('SIGTERM', () => {\n    console.log('[openape-proxy] Shutting down...')\n    server.close()\n    process.exit(0)\n  })\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport forge from 'node-forge'\n\nexport interface LoadOrCreateCaOpts {\n  certPath: string\n  keyPath: string\n  subjectCN: string\n}\n\nexport interface CaBundle {\n  certPem: string\n  keyPem: string\n  created: boolean\n}\n\nexport function loadOrCreateCa(opts: LoadOrCreateCaOpts): CaBundle {\n  if (existsSync(opts.certPath) && existsSync(opts.keyPath)) {\n    return {\n      certPem: readFileSync(opts.certPath, 'utf-8'),\n      keyPem: readFileSync(opts.keyPath, 'utf-8'),\n      created: false,\n    }\n  }\n\n  const keys = forge.pki.rsa.generateKeyPair({ bits: 2048 })\n  const cert = forge.pki.createCertificate()\n  cert.publicKey = keys.publicKey\n  cert.serialNumber = String(Date.now())\n  cert.validity.notBefore = new Date()\n  cert.validity.notAfter = new Date(Date.now() + 10 * 365 * 86400_000)\n  // Tag the CN explicitly as UTF8String. node-forge defaults to PrintableString\n  // for ASCII inputs, but its DER serializer can emit byte sequences that Go's\n  // strict crypto/x509 parser flags (\"invalid PrintableString\"). UTF8String\n  // sidesteps the strict-mode check and is universally accepted.\n  // valueTagClass takes an asn1.Type value (the upstream @types annotation says\n  // asn1.Class but node-forge's x509.js reads it from asn1.Type at runtime).\n  const attrs = [\n    // @types/node-forge types valueTagClass as asn1.Class, but node-forge's\n    // x509.js reads it as an asn1.Type at runtime (see comment above). Cast to\n    // satisfy the too-narrow typing without changing runtime behaviour.\n    { name: 'commonName', value: opts.subjectCN, valueTagClass: forge.asn1.Type.UTF8 as unknown as forge.asn1.Class },\n  ]\n  cert.setSubject(attrs)\n  cert.setIssuer(attrs)\n  cert.setExtensions([\n    { name: 'basicConstraints', cA: true },\n    { name: 'keyUsage', keyCertSign: true, cRLSign: true },\n    { name: 'subjectKeyIdentifier' },\n  ])\n  cert.sign(keys.privateKey, forge.md.sha256.create())\n\n  const certPem = forge.pki.certificateToPem(cert)\n  const keyPem = forge.pki.privateKeyToPem(keys.privateKey)\n\n  mkdirSync(dirname(opts.certPath), { recursive: true, mode: 0o700 })\n  writeFileSync(opts.certPath, certPem, { mode: 0o600 })\n  writeFileSync(opts.keyPath, keyPem, { mode: 0o600 })\n\n  return { certPem, keyPem, created: true }\n}\n\nexport interface LeafCert {\n  certPem: string\n  keyPem: string\n  expiresAt: number\n}\n\nexport function mintLeafCert(ca: CaBundle, hostname: string): LeafCert {\n  const caCert = forge.pki.certificateFromPem(ca.certPem)\n  const caKey = forge.pki.privateKeyFromPem(ca.keyPem)\n\n  const keys = forge.pki.rsa.generateKeyPair({ bits: 2048 })\n  const cert = forge.pki.createCertificate()\n  cert.publicKey = keys.publicKey\n  cert.serialNumber = `${Date.now()}${Math.floor(Math.random() * 1e6)}`\n  cert.validity.notBefore = new Date()\n  const expiresAt = Date.now() + 24 * 3600_000\n  cert.validity.notAfter = new Date(expiresAt)\n  // Tag CN as UTF8String for the same reason as the CA — keeps Go's strict\n  // crypto/x509 parser happy. The issuer attributes come straight from the\n  // parsed CA, which is already UTF8-tagged.\n  cert.setSubject([\n    // See note in createCaCert: valueTagClass is an asn1.Type at runtime;\n    // cast around the too-narrow @types/node-forge annotation.\n    { name: 'commonName', value: hostname, valueTagClass: forge.asn1.Type.UTF8 as unknown as forge.asn1.Class },\n  ])\n  cert.setIssuer(caCert.subject.attributes)\n  cert.setExtensions([\n    { name: 'basicConstraints', cA: false },\n    { name: 'keyUsage', digitalSignature: true, keyEncipherment: true },\n    { name: 'extKeyUsage', serverAuth: true },\n    { name: 'subjectAltName', altNames: [{ type: 2, value: hostname }] },\n  ])\n  cert.sign(caKey, forge.md.sha256.create())\n\n  return {\n    certPem: forge.pki.certificateToPem(cert),\n    keyPem: forge.pki.privateKeyToPem(keys.privateKey),\n    expiresAt,\n  }\n}\n\nexport interface LeafCertCache {\n  get: (hostname: string) => LeafCert\n}\n\nexport function createLeafCertCache(ca: CaBundle, opts: { capacity: number }): LeafCertCache {\n  const cache = new Map<string, LeafCert>()\n  return {\n    get(hostname) {\n      const existing = cache.get(hostname)\n      if (existing && existing.expiresAt > Date.now()) {\n        cache.delete(hostname)\n        cache.set(hostname, existing)  // refresh LRU position\n        return existing\n      }\n      const fresh = mintLeafCert(ca, hostname)\n      cache.set(hostname, fresh)\n      while (cache.size > opts.capacity) {\n        const oldestKey = cache.keys().next().value\n        if (oldestKey === undefined) break\n        cache.delete(oldestKey)\n      }\n      return fresh\n    },\n  }\n}\n","import { readFileSync } from 'node:fs'\nimport { parse as parseTOML } from 'smol-toml'\nimport type { AgentConfig, MultiAgentProxyConfig } from './types.js'\n\n/**\n * Load config as multi-agent format.\n * If the config has an `agents` array, use it directly.\n * Otherwise, convert single-agent format to multi-agent for backward-compat.\n */\nexport function loadMultiAgentConfig(path: string, overrides?: { mandatoryAuth?: boolean }): MultiAgentProxyConfig {\n  const raw = readFileSync(path, 'utf-8')\n\n  let parsed: Record<string, unknown>\n  if (path.endsWith('.json')) {\n    parsed = JSON.parse(raw)\n  }\n  else {\n    parsed = parseTOML(raw) as Record<string, unknown>\n  }\n\n  const proxy = parsed.proxy as Record<string, unknown>\n  if (!proxy?.listen) {\n    throw new Error('Config must have [proxy] with listen')\n  }\n\n  const baseProxy: MultiAgentProxyConfig['proxy'] = {\n    listen: proxy.listen as string,\n    default_action: (proxy.default_action as MultiAgentProxyConfig['proxy']['default_action']) ?? 'block',\n    mandatory_auth: overrides?.mandatoryAuth ?? (proxy.mandatory_auth as boolean | undefined),\n  }\n\n  // Multi-agent format: has agents array\n  if (Array.isArray(parsed.agents)) {\n    return {\n      proxy: baseProxy,\n      agents: parsed.agents as AgentConfig[],\n    }\n  }\n\n  // Single-agent format: convert to multi-agent\n  const idpUrl = proxy.idp_url as string\n  const agentEmail = proxy.agent_email as string\n  if (!idpUrl || !agentEmail) {\n    throw new Error('Single-agent config requires proxy.idp_url and proxy.agent_email')\n  }\n\n  return {\n    proxy: baseProxy,\n    agents: [{\n      email: agentEmail,\n      idp_url: idpUrl,\n      allow: (parsed.allow ?? []) as AgentConfig['allow'],\n      deny: (parsed.deny ?? []) as AgentConfig['deny'],\n      grant_required: (parsed.grant_required ?? []) as AgentConfig['grant_required'],\n    }],\n  }\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { Socket } from 'node:net'\nimport { createHash } from 'node:crypto'\nimport type { AgentConfig, AuditEntry, MultiAgentProxyConfig, ProxyConfig, SecretsStore } from './types.js'\nimport type { LeafCertCache } from './ca-store.js'\nimport { evaluateRules } from './matcher.js'\nimport { AuthError, verifyAgentAuth } from './auth.js'\nimport { GrantsClient } from './grants-client.js'\nimport { writeAudit } from './audit.js'\nimport { checkEgress } from './ssrf.js'\nimport { handleConnect } from './connect.js'\n\n/**\n * Minimal fetch shape used for upstream calls. `typeof fetch` itself carries a\n * `preconnect` static (Node 22+) which we don't use, so we narrow to the call\n * signature to keep `MultiAgentProxyDeps.fetchImpl` easy to override in tests.\n */\nexport type UpstreamFetch = (input: Request | URL | string, init?: RequestInit) => Promise<Response>\n\n/**\n * Optional dependencies injected into `createMultiAgentProxy`. Kept additive so\n * existing single-call sites (legacy `createProxy`, `createNodeHandler`) keep\n * working without supplying any of these.\n */\nexport interface MultiAgentProxyDeps {\n  /**\n   * In-memory secret lookup. When set, the forward-proxy fetch path consults\n   * the store right before forwarding and injects a header on a target match.\n   */\n  secretsStore?: SecretsStore\n  /**\n   * Override the upstream fetch implementation. Defaults to `globalThis.fetch`.\n   * Tests can pass a stub here when they need to assert the outgoing request\n   * shape without relying on `vi.spyOn(globalThis, 'fetch')`.\n   */\n  fetchImpl?: UpstreamFetch\n  /**\n   * Daemon mode: identity is implicit (loaded from `~/.config/apes/auth.json`\n   * at startup) so per-request `Proxy-Authorization` JWT extraction is\n   * skipped. The daemon's identity = `config.agents[0].email`. Inline mode\n   * (`apes proxy --` ephemeral case) leaves this unset and keeps the existing\n   * JWT-required path.\n   */\n  daemonMode?: boolean\n}\n\n/**\n * Compute a request hash that uniquely identifies the intent.\n * hash = sha256(METHOD + \" \" + FULL_URL + \"\\n\" + BODY)\n * This binds the grant to the exact request — no bait-and-switch.\n */\nasync function computeRequestHash(method: string, targetUrl: string, body: ArrayBuffer | null): Promise<string> {\n  const hash = createHash('sha256')\n  hash.update(`${method} ${targetUrl}\\n`)\n  if (body && body.byteLength > 0) {\n    hash.update(new Uint8Array(body))\n  }\n  return hash.digest('hex')\n}\n\n/**\n * Build the per-agent GrantsClient map used by both the HTTP forward-proxy\n * handler (in this file's `createMultiAgentProxy`) and the CONNECT handler\n * (in `connect.ts`). Exposed so `createNodeHandler` can share a single map\n * instead of letting each handler construct its own — keeps any future\n * per-agent token state coherent.\n */\nexport function buildGrantsClients(config: MultiAgentProxyConfig): Map<string, GrantsClient> {\n  const grantsClients = new Map<string, GrantsClient>()\n  for (const agent of config.agents) {\n    grantsClients.set(agent.email, new GrantsClient(agent.idp_url))\n  }\n  return grantsClients\n}\n\n/** Multi-agent proxy with SSRF protection and mandatory auth */\nexport function createMultiAgentProxy(\n  config: MultiAgentProxyConfig,\n  grantsClients: Map<string, GrantsClient> = buildGrantsClients(config),\n  deps: MultiAgentProxyDeps = {},\n) {\n  // Backwards-compat: if caller didn't pre-build the map, we build our own.\n  // createNodeHandler always passes one in so the CONNECT handler can share it.\n  for (const agent of config.agents) {\n    if (!grantsClients.has(agent.email)) {\n      grantsClients.set(agent.email, new GrantsClient(agent.idp_url))\n    }\n  }\n\n  const mandatoryAuth = config.proxy.mandatory_auth ?? false\n  const secretsStore = deps.secretsStore\n  const daemonMode = deps.daemonMode ?? false\n  // Bind to globalThis so `vi.spyOn(globalThis, 'fetch')` in tests intercepts\n  // the upstream call. Resolved per-call so spies installed after construction\n  // still take effect.\n  const fetchImpl: UpstreamFetch = deps.fetchImpl ?? ((input, init) => globalThis.fetch(input, init))\n\n  return {\n    port: Number.parseInt(config.proxy.listen.split(':')[1] || '9090'),\n    hostname: config.proxy.listen.split(':')[0] || '127.0.0.1',\n\n    async fetch(req: Request): Promise<Response> {\n      const url = new URL(req.url)\n      const startTime = Date.now()\n\n      // Health endpoint\n      if (url.pathname === '/healthz') {\n        return Response.json({\n          status: 'ok',\n          agents: config.agents.map(a => a.email),\n        })\n      }\n\n      // Parse target URL from the path\n      const targetUrl = url.pathname.slice(1) + url.search\n      let targetParsed: URL\n      try {\n        targetParsed = new URL(targetUrl)\n      }\n      catch {\n        return new Response(\n          'Invalid target URL. Send requests as: http://proxy:port/https://target.com/path',\n          { status: 400 },\n        )\n      }\n\n      const domain = targetParsed.hostname\n      const method = req.method\n      const path = targetParsed.pathname\n\n      // SSRF / reachability check. Split outcomes so a non-existent host\n      // doesn't ship as a misleading 403:\n      //   - `private`      → policy refusal (403).\n      //   - `unresolvable` → upstream connectivity failure (502).\n      const egress = await checkEgress(domain)\n      if (egress.kind === 'private') {\n        return new Response('Blocked: private/loopback IP', { status: 403 })\n      }\n      if (egress.kind === 'unresolvable') {\n        return new Response(\n          `DNS lookup failed for ${domain} (${egress.reason}).`,\n          { status: 502 },\n        )\n      }\n\n      // Read body once (needed for hash + forwarding)\n      const bodyBuffer = req.body ? await req.arrayBuffer() : null\n\n      // Verify agent identity — find IdP URL from first agent (for JWKS verification)\n      // In multi-agent mode, we need the JWT to identify the agent first.\n      // We try verification against each agent's IdP until one succeeds.\n      let agentIdentity: { email: string, act: 'agent' } | null = null\n      if (daemonMode) {\n        // Identity is implicit — the daemon was started by/for one specific\n        // agent. The first (and only) agent in config.agents is the daemon's\n        // identity, loaded from `~/.config/apes/auth.json` at startup.\n        agentIdentity = { email: config.agents[0]!.email, act: 'agent' }\n      }\n      else {\n        try {\n          for (const agentConf of config.agents) {\n            agentIdentity = await verifyAgentAuth(\n              req.headers.get('proxy-authorization'),\n              agentConf.idp_url,\n              mandatoryAuth && config.agents.length === 1,\n            )\n            if (agentIdentity) break\n          }\n\n          // If mandatory auth and no identity found from any IdP\n          if (mandatoryAuth && !agentIdentity) {\n            throw new AuthError('JWT required')\n          }\n        }\n        catch (err) {\n          if (err instanceof AuthError) {\n            return new Response(`Unauthorized: ${err.message}`, { status: 401 })\n          }\n          throw err\n        }\n      }\n\n      // Find the matching agent config\n      const agentEmail = agentIdentity?.email\n      let agentConf: AgentConfig | undefined\n\n      if (agentEmail) {\n        agentConf = config.agents.find(a => a.email === agentEmail)\n        if (!agentConf) {\n          return new Response(`Forbidden: unknown agent ${agentEmail}`, { status: 403 })\n        }\n      }\n      else if (config.agents.length === 1) {\n        // Non-mandatory auth, single agent: use the only agent config\n        agentConf = config.agents[0]! // length === 1 checked above\n      }\n      else {\n        return new Response('Unauthorized: JWT required for multi-agent proxy', { status: 401 })\n      }\n\n      const effectiveEmail = agentEmail ?? agentConf.email\n      const grantsClient = grantsClients.get(agentConf.email)!\n      // The verified agent JWT, forwarded to the IdP on grant requests\n      // (#1276): the grants API requires bearer auth and binds the grant's\n      // requester to the token subject.\n      const rawAgentToken = agentIdentity\n        ? req.headers.get('proxy-authorization')?.match(/^Bearer (.+)$/i)?.[1]\n        : undefined\n\n      // Build a ProxyConfig-shaped object for evaluateRules\n      const rulesConfig: ProxyConfig = {\n        proxy: {\n          listen: config.proxy.listen,\n          idp_url: agentConf.idp_url,\n          agent_email: agentConf.email,\n          default_action: config.proxy.default_action,\n        },\n        allow: agentConf.allow ?? [],\n        deny: agentConf.deny ?? [],\n        grant_required: agentConf.grant_required ?? [],\n      }\n\n      // Evaluate rules\n      const action = evaluateRules(rulesConfig, domain, method, path)\n\n      const baseAudit: Omit<AuditEntry, 'action' | 'rule'> = {\n        ts: new Date().toISOString(),\n        agent: effectiveEmail,\n        domain,\n        method,\n        path,\n      }\n\n      // DENY\n      if (action.type === 'deny') {\n        writeAudit({ ...baseAudit, action: 'deny', rule: 'deny-list', grant_id: null })\n        return new Response(`Blocked: ${action.note || 'deny rule'}`, { status: 403 })\n      }\n\n      // ALLOW (no grant needed)\n      if (action.type === 'allow') {\n        writeAudit({ ...baseAudit, action: 'allow', rule: 'allow-list', grant_id: null })\n        return forwardRequest(req, targetUrl, targetParsed, bodyBuffer, secretsStore, fetchImpl)\n      }\n\n      // GRANT REQUIRED\n      const rule = action.rule\n      const permissions = rule.permissions ?? [`${method.toLowerCase()}:${domain}`]\n\n      // Compute request hash — binds grant to exact method + URL + body\n      const requestHash = await computeRequestHash(method, targetUrl, bodyBuffer)\n\n      // Check for existing grant\n      const existing = await grantsClient.findExistingGrant(\n        effectiveEmail,\n        domain,\n        'proxy',\n        permissions,\n      ).catch(() => null)\n\n      if (existing) {\n        writeAudit({\n          ...baseAudit,\n          action: 'grant_approved',\n          rule: 'standing-grant',\n          grant_id: existing.id,\n          request_hash: requestHash,\n        })\n        return forwardRequest(req, targetUrl, targetParsed, bodyBuffer, secretsStore, fetchImpl)\n      }\n\n      // No existing grant — behavior depends on default_action\n      if (config.proxy.default_action === 'block') {\n        writeAudit({ ...baseAudit, action: 'deny', rule: 'no-grant (block mode)', grant_id: null })\n        return new Response('No grant — blocked', { status: 403 })\n      }\n\n      if (config.proxy.default_action === 'request-async') {\n        // Create grant request, return 407 immediately\n        const grant = await grantsClient.requestGrant({\n          requester: effectiveEmail,\n          targetHost: domain,\n          audience: 'ape-proxy',\n          grantType: rule.grant_type,\n          permissions,\n          reason: `${method} ${targetUrl}`,\n          requestHash,\n          duration: rule.duration,\n          agentToken: rawAgentToken,\n        }).catch(() => null)\n\n        writeAudit({\n          ...baseAudit,\n          action: 'grant_denied',\n          rule: 'grant_required (async)',\n          grant_id: grant?.id ?? null,\n        })\n\n        return new Response(\n          JSON.stringify({\n            error: 'Grant required',\n            grant_id: grant?.id,\n            message: 'Grant request created. Retry after approval.',\n          }),\n          { status: 407, headers: { 'Content-Type': 'application/json' } },\n        )\n      }\n\n      // BLOCKING mode: create grant request and wait\n      console.error(`[proxy] Requesting grant for ${method} ${domain}${path} — waiting for approval...`)\n\n      try {\n        const grant = await grantsClient.requestGrant({\n          requester: effectiveEmail,\n          targetHost: domain,\n          audience: 'ape-proxy',\n          grantType: rule.grant_type,\n          permissions,\n          reason: `${method} ${targetUrl}`,\n          requestHash,\n          duration: rule.duration,\n          agentToken: rawAgentToken,\n        })\n\n        const approved = await grantsClient.waitForApproval(grant.id)\n\n        const waitedMs = Date.now() - startTime\n\n        if (approved.status === 'approved') {\n          writeAudit({\n            ...baseAudit,\n            action: 'grant_approved',\n            rule: 'grant_required',\n            grant_id: approved.id,\n            request_hash: requestHash,\n            waited_ms: waitedMs,\n          })\n          return forwardRequest(req, targetUrl, targetParsed, bodyBuffer, secretsStore, fetchImpl)\n        }\n\n        writeAudit({\n          ...baseAudit,\n          action: 'grant_denied',\n          rule: 'grant_required',\n          grant_id: approved.id,\n          waited_ms: waitedMs,\n        })\n        return new Response(`Grant denied by ${approved.decided_by}`, { status: 403 })\n      }\n      catch (err) {\n        const msg = err instanceof Error ? err.message : 'Unknown error'\n        writeAudit({\n          ...baseAudit,\n          action: 'grant_timeout',\n          rule: 'grant_required',\n          error: msg,\n        })\n        return new Response(`Grant request failed: ${msg}`, { status: 504 })\n      }\n    },\n  }\n}\n\n/**\n * Optional dependencies forwarded by `createNodeHandler` to both the\n * forward-proxy fetch path (`createMultiAgentProxy`) and the CONNECT path\n * (`handleConnect`). Kept optional so existing zero-arg callers (legacy\n * single-agent paths, simple multi-agent setups without secret injection or\n * MITM) keep working unchanged.\n */\nexport interface NodeHandlerDeps {\n  /** In-memory secret lookup, forwarded to both the fetch and CONNECT paths. */\n  secretsStore?: SecretsStore\n  /**\n   * Per-host leaf cert cache backed by the daemon's CA bundle. Required (in\n   * combination with `secretsStore`) for CONNECT-MITM secret injection on\n   * HTTPS targets; absent → CONNECT stays an opaque TCP tunnel.\n   */\n  leafCache?: LeafCertCache\n  /**\n   * Daemon mode: skip per-request `Proxy-Authorization` JWT extraction on\n   * both the forward-proxy fetch path and the CONNECT path. Forwarded to\n   * `createMultiAgentProxy` and `handleConnect`. Inline (ephemeral) mode\n   * leaves this unset.\n   */\n  daemonMode?: boolean\n}\n\n/**\n * Create a node:http compatible handler for use with http.createServer().\n * Returns both a request handler and a CONNECT handler.\n */\nexport function createNodeHandler(config: MultiAgentProxyConfig, deps: NodeHandlerDeps = {}): {\n  handleRequest: (req: IncomingMessage, res: ServerResponse) => void\n  handleConnect: (req: IncomingMessage, socket: Socket, head: Buffer) => void\n} {\n  // Build grantsClients once; share with both forward-proxy fetch path\n  // (createMultiAgentProxy) and the CONNECT path (handleConnect). Without\n  // sharing, CONNECT-time grant_required rules couldn't reach the IdP in\n  // multi-agent mode without duplicating constructor work.\n  const grantsClients = buildGrantsClients(config)\n  const proxy = createMultiAgentProxy(config, grantsClients, {\n    secretsStore: deps.secretsStore,\n    daemonMode: deps.daemonMode,\n  })\n\n  return {\n    handleRequest(req: IncomingMessage, res: ServerResponse) {\n      // Standard HTTP_PROXY clients (curl, gh, git, npm) send the target as\n      // an absolute URL in the request line for cleartext forward-proxying:\n      //   `GET http://example.com/path HTTP/1.1`\n      // node:http surfaces that absolute URL via `req.url`. The legacy\n      // `proxy.fetch` extraction expects a path-encoded form\n      // (`/<full-target-url>`), so we adapt here: when `req.url` is\n      // absolute, prefix it with a slash so `pathname.slice(1)` recovers\n      // the same target string. Path-form clients (legacy) keep working.\n      const reqUrl = req.url || '/'\n      const isAbsolute = reqUrl.startsWith('http://') || reqUrl.startsWith('https://')\n      const proxyHost = req.headers.host || 'localhost'\n      const url = isAbsolute\n        ? `http://${proxyHost}/${reqUrl}`\n        : `http://${proxyHost}${reqUrl}`\n      const chunks: Buffer[] = []\n\n      req.on('data', (chunk: Buffer) => chunks.push(chunk))\n      req.on('end', async () => {\n        try {\n          const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined\n          const headers = new Headers()\n          for (const [key, value] of Object.entries(req.headers)) {\n            if (value) {\n              headers.set(key, Array.isArray(value) ? value.join(', ') : value)\n            }\n          }\n\n          const request = new Request(url, {\n            method: req.method,\n            headers,\n            body: body && req.method !== 'GET' && req.method !== 'HEAD' ? body : undefined,\n            duplex: 'half',\n          } as RequestInit)\n\n          const response = await proxy.fetch(request)\n\n          res.writeHead(response.status, response.statusText, Object.fromEntries(response.headers))\n          if (response.body) {\n            const reader = response.body.getReader()\n            const pump = async (): Promise<void> => {\n              const { done, value } = await reader.read()\n              if (done) {\n                res.end()\n                return\n              }\n              res.write(value)\n              return pump()\n            }\n            await pump()\n          }\n          else {\n            res.end()\n          }\n        }\n        catch {\n          res.writeHead(502)\n          res.end('Proxy error')\n        }\n      })\n    },\n\n    handleConnect(req: IncomingMessage, socket: Socket, head: Buffer) {\n      handleConnect(config, grantsClients, req, socket, head, {\n        secretsStore: deps.secretsStore,\n        leafCache: deps.leafCache,\n        daemonMode: deps.daemonMode,\n      })\n    },\n  }\n}\n\n/**\n * Forward a request to the target URL.\n * Strips proxy-specific headers, preserves the rest.\n *\n * If a `secretsStore` is provided and a secret matches `targetParsed`, the\n * configured header is rendered from the entry's template and set on the\n * outgoing request (replacing any existing value with the same name).\n */\nasync function forwardRequest(\n  originalReq: Request,\n  targetUrl: string,\n  targetParsed: URL,\n  cachedBody: ArrayBuffer | null | undefined,\n  secretsStore: SecretsStore | undefined,\n  fetchImpl: UpstreamFetch,\n): Promise<Response> {\n  const headers = new Headers(originalReq.headers)\n  // Remove proxy-specific headers\n  headers.delete('proxy-authorization')\n  headers.delete('proxy-connection')\n  // Don't send host of the proxy\n  headers.delete('host')\n\n  // Inject hook: consult the secrets store after grant decisions and before\n  // forwarding. Logs are redacted — only name/header/method/url are printed,\n  // never the secret value or rendered template.\n  if (secretsStore) {\n    const match = secretsStore.findFor(targetParsed)\n    if (match) {\n      const rendered = match.template.replace(/\\$\\{value\\}/g, match.value)\n      headers.set(match.header, rendered)\n      console.error(\n        `[openape-proxy] injected secret '${match.name}' into ${match.header} for ${originalReq.method} ${targetUrl}`,\n      )\n    }\n  }\n\n  const body = cachedBody && cachedBody.byteLength > 0 ? cachedBody : null\n\n  try {\n    const upstreamReq = new Request(targetUrl, {\n      method: originalReq.method,\n      headers,\n      body,\n      duplex: 'half',\n      redirect: 'manual',\n    } as RequestInit)\n    const res = await fetchImpl(upstreamReq)\n\n    // Stream the response back\n    const responseHeaders = new Headers(res.headers)\n    // Remove hop-by-hop headers\n    responseHeaders.delete('transfer-encoding')\n    responseHeaders.delete('connection')\n\n    return new Response(res.body, {\n      status: res.status,\n      statusText: res.statusText,\n      headers: responseHeaders,\n    })\n  }\n  catch (err) {\n    const msg = err instanceof Error ? err.message : 'Upstream error'\n    return new Response(`Proxy error: ${msg}`, { status: 502 })\n  }\n}\n","import type { ProxyConfig, RuleAction, RuleEntry } from './types.js'\n\n/**\n * Match a glob pattern against a string.\n * Supports * (any segment) and ** (any number of segments).\n */\nfunction globMatch(pattern: string, value: string): boolean {\n  // Simple glob: convert * to regex\n  const regex = new RegExp(\n    `^${\n      pattern\n        .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')  // escape regex chars except *\n        .replace(/\\*\\*/g, '<<<DOUBLESTAR>>>')\n        .replace(/\\*/g, '[^/]*')\n        .replace(/<<<DOUBLESTAR>>>/g, '.*')\n    }$`,\n  )\n  return regex.test(value)\n}\n\nfunction matchesRule(rule: RuleEntry, domain: string, method: string, path: string): boolean {\n  // Domain match (supports wildcards like *.github.com)\n  if (!globMatch(rule.domain, domain)) return false\n\n  // Method match (if specified)\n  if (rule.methods && rule.methods.length > 0) {\n    if (!rule.methods.includes(method.toUpperCase())) return false\n  }\n\n  // Path match (if specified)\n  if (rule.path) {\n    if (!globMatch(rule.path, path)) return false\n  }\n\n  return true\n}\n\n/**\n * Evaluate rules in order: deny → allow → grant_required → default_action\n */\nexport function evaluateRules(\n  config: ProxyConfig,\n  domain: string,\n  method: string,\n  path: string,\n): RuleAction {\n  // 1. Check deny list first\n  for (const rule of config.deny) {\n    if (matchesRule(rule, domain, method, path)) {\n      return { type: 'deny', note: rule.note }\n    }\n  }\n\n  // 2. Check allow list\n  for (const rule of config.allow) {\n    if (matchesRule(rule, domain, method, path)) {\n      return { type: 'allow' }\n    }\n  }\n\n  // 3. Check grant_required rules (most specific first)\n  for (const rule of config.grant_required) {\n    if (matchesRule(rule, domain, method, path)) {\n      return { type: 'grant_required', rule }\n    }\n  }\n\n  // 4. Default action for unmatched hosts. Conceptually the proxy-side\n  // counterpart of the IdP's per-agent YOLO policy — both decide what\n  // happens when no specific rule matches, both live server-side (proxy or\n  // IdP), neither leaks the decision to the agent. Differences:\n  //   - IdP YOLO is per-agent, evaluated at grant time, can have deny-patterns\n  //     and an expiry window.\n  //   - Proxy default_action is per-proxy-instance, evaluated at request time,\n  //     binary outcome (allow/deny/request-grant).\n  //\n  // Modes:\n  //   - 'block': hard deny — paranoid agent profile.\n  //   - 'allow': hard pass — transparent-audit profile (log every call,\n  //     enforce nothing). Equivalent role to a YOLO policy without a\n  //     deny-list.\n  //   - 'request' / 'request-async' (OpenApe-default): treat as\n  //     grant_required with a once-grant catch-all so every new host\n  //     surfaces an interactive grant decision.\n  if (config.proxy.default_action === 'block') {\n    return { type: 'deny', note: 'No matching rule (default: block)' }\n  }\n  if (config.proxy.default_action === 'allow') {\n    return { type: 'allow' }\n  }\n\n  return {\n    type: 'grant_required',\n    rule: {\n      domain: '*',\n      grant_type: 'once',\n    },\n  }\n}\n","import { verifyJWT, createRemoteJWKS } from '@openape/core'\n\nexport interface AgentIdentity {\n  email: string\n  act: 'agent'\n}\n\nexport class AuthError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = 'AuthError'\n  }\n}\n\n/**\n * Verify agent JWT from Proxy-Authorization header.\n * Returns the agent identity or null if invalid/missing.\n * When mandatory is true, throws AuthError if no valid JWT is provided.\n */\nexport async function verifyAgentAuth(\n  authHeader: string | null,\n  idpUrl: string,\n  mandatory: boolean = false,\n): Promise<AgentIdentity | null> {\n  if (!authHeader) {\n    if (mandatory) throw new AuthError('JWT required')\n    return null\n  }\n\n  const match = authHeader.match(/^Bearer (.+)$/i)\n  if (!match) {\n    if (mandatory) throw new AuthError('Invalid authorization header')\n    return null\n  }\n\n  const token = match[1]! // capture group 1 is present whenever the regex matches\n\n  try {\n    const jwks = createRemoteJWKS(`${idpUrl}/.well-known/jwks.json`)\n    const { payload } = await verifyJWT(token, jwks, { issuer: idpUrl })\n\n    if (payload.act !== 'agent' || !payload.sub) {\n      if (mandatory) throw new AuthError('Invalid agent token')\n      return null\n    }\n\n    return {\n      email: payload.sub as string,\n      act: 'agent',\n    }\n  }\n  catch (err) {\n    if (err instanceof AuthError) throw err\n    if (mandatory) throw new AuthError('JWT verification failed')\n    return null\n  }\n}\n","import type { OpenApeGrant, GrantType } from '@openape/core'\n\n/**\n * Client for the IdP's grant management API.\n * Creates grant requests and polls for approval.\n */\nexport class GrantsClient {\n  private idpUrl: string\n  private agentToken: string | undefined\n\n  constructor(idpUrl: string) {\n    this.idpUrl = idpUrl.replace(/\\/$/, '')\n  }\n\n  setAgentToken(token: string): void {\n    this.agentToken = token\n  }\n\n  private headers(tokenOverride?: string): Record<string, string> {\n    const h: Record<string, string> = { 'Content-Type': 'application/json' }\n    const token = tokenOverride ?? this.agentToken\n    if (token) {\n      h.Authorization = `Bearer ${token}`\n    }\n    return h\n  }\n\n  /**\n   * Create a grant request on the IdP. `agentToken` is the requesting\n   * agent's verified JWT — the IdP requires it (#1276) and binds the\n   * grant's requester to the token subject.\n   */\n  async requestGrant(opts: {\n    requester: string\n    targetHost: string\n    audience: string\n    grantType: GrantType\n    permissions?: string[]\n    reason?: string\n    requestHash?: string\n    duration?: number\n    agentToken?: string\n  }): Promise<OpenApeGrant> {\n    const res = await fetch(`${this.idpUrl}/api/grants`, {\n      method: 'POST',\n      headers: this.headers(opts.agentToken),\n      body: JSON.stringify({\n        requester: opts.requester,\n        target_host: opts.targetHost,\n        audience: opts.audience,\n        grant_type: opts.grantType,\n        permissions: opts.permissions,\n        reason: opts.reason,\n        request_hash: opts.requestHash,\n        duration: opts.duration,\n      }),\n    })\n\n    if (!res.ok) {\n      throw new Error(`Grant request failed: ${res.status} ${await res.text()}`)\n    }\n\n    return res.json() as Promise<OpenApeGrant>\n  }\n\n  /**\n   * Poll a grant until it's approved, denied, or timeout.\n   */\n  async waitForApproval(\n    grantId: string,\n    timeoutMs: number = 300_000,\n    pollIntervalMs: number = 2_000,\n  ): Promise<OpenApeGrant> {\n    const deadline = Date.now() + timeoutMs\n\n    while (Date.now() < deadline) {\n      const res = await fetch(`${this.idpUrl}/api/grants/${grantId}`, {\n        headers: this.headers(),\n      })\n\n      if (!res.ok) {\n        throw new Error(`Grant poll failed: ${res.status}`)\n      }\n\n      const grant = await res.json() as OpenApeGrant\n      if (grant.status !== 'pending') {\n        return grant\n      }\n\n      await new Promise(r => setTimeout(r, pollIntervalMs))\n    }\n\n    throw new Error(`Grant approval timed out after ${timeoutMs}ms`)\n  }\n\n  /**\n   * Check if there's an existing approved grant for a host+audience+permissions combo.\n   * Ignores `once` grants (they're single-use).\n   */\n  async findExistingGrant(\n    requester: string,\n    targetHost: string,\n    audience: string,\n    permissions?: string[],\n  ): Promise<OpenApeGrant | null> {\n    const params = new URLSearchParams({\n      requester,\n      status: 'approved',\n    })\n\n    const res = await fetch(`${this.idpUrl}/api/grants?${params}`, {\n      headers: this.headers(),\n    })\n\n    if (!res.ok) return null\n\n    const grants = await res.json() as OpenApeGrant[]\n    const now = Math.floor(Date.now() / 1000)\n\n    return grants.find((g) => {\n      if (g.status !== 'approved') return false\n      if (g.expires_at && g.expires_at <= now) return false\n      if (g.request?.grant_type === 'once') return false\n      if (g.request?.target_host !== targetHost) return false\n      if (g.request?.audience !== audience) return false\n      if (permissions?.length && g.request?.permissions?.length) {\n        const grantedPerms = new Set(g.request.permissions)\n        if (!permissions.every(p => grantedPerms.has(p))) return false\n      }\n      return true\n    }) ?? null\n  }\n}\n","import type { AuditEntry } from './types.js'\n\n/**\n * Format the request target for the stderr summary line. For HTTP forward-proxy\n * the path starts with `/` (so `${domain}${path}` reads `example.com/foo`), but\n * for CONNECT the path field already carries `host:port` and concatenating\n * with `domain` would print `example.comexample.com:443`.\n */\nfunction formatTarget(entry: AuditEntry): string {\n  return entry.path.startsWith('/') ? `${entry.domain}${entry.path}` : entry.path\n}\n\n/**\n * Emit one operator-readable audit summary line to stderr. Intentionally NOT a\n * tamper-proof audit trail: anything written on the user's machine is also\n * writable by the user, so there's no integrity story we'd be willing to put\n * in front of a reviewer. The trustworthy audit lives server-side, recorded\n * by the IdP every time it processes a grant request — see the planned\n * per-agent audit route on `id.openape.ai`.\n *\n * Stderr here is purely a debugging convenience for the operator running\n * `apes proxy --` interactively. Persist nothing locally.\n */\nexport function writeAudit(entry: AuditEntry): void {\n  const grantSuffix = entry.grant_id ? ` grant=${entry.grant_id}` : ''\n  console.error(`[audit] ${entry.action} ${entry.method} ${formatTarget(entry)}${grantSuffix}`)\n}\n","import { resolve4, resolve6 } from 'node:dns/promises'\nimport { isIP } from 'node:net'\n\nconst PRIVATE_RANGES_V4 = [\n  { prefix: 0x7F000000, mask: 0xFF000000 }, // 127.0.0.0/8\n  { prefix: 0x0A000000, mask: 0xFF000000 }, // 10.0.0.0/8\n  { prefix: 0xAC100000, mask: 0xFFF00000 }, // 172.16.0.0/12\n  { prefix: 0xC0A80000, mask: 0xFFFF0000 }, // 192.168.0.0/16\n  { prefix: 0xA9FE0000, mask: 0xFFFF0000 }, // 169.254.0.0/16\n  { prefix: 0x00000000, mask: 0xFF000000 }, // 0.0.0.0/8\n]\n\nfunction ipv4ToNumber(ip: string): number {\n  const [a, b, c, d] = ip.split('.').map(Number)\n  if (a === undefined || b === undefined || c === undefined || d === undefined)\n    throw new Error(`Invalid IPv4 address: ${ip}`)\n  return ((a << 24) | (b << 16) | (c << 8) | d) >>> 0\n}\n\nfunction isPrivateIPv4(ip: string): boolean {\n  const num = ipv4ToNumber(ip)\n  return PRIVATE_RANGES_V4.some(r => ((num & r.mask) >>> 0) === r.prefix)\n}\n\nfunction isPrivateIPv6(ip: string): boolean {\n  const normalized = ip.toLowerCase()\n\n  // Loopback ::1\n  if (normalized === '::1') return true\n\n  // Unspecified ::\n  if (normalized === '::') return true\n\n  // Link-local fe80::/10\n  if (normalized.startsWith('fe8') || normalized.startsWith('fe9')\n    || normalized.startsWith('fea') || normalized.startsWith('feb')) {\n    return true\n  }\n\n  // Unique local fd00::/8\n  if (normalized.startsWith('fd')) return true\n\n  // IPv4-mapped ::ffff:x.x.x.x\n  const v4mapped = normalized.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/)\n  if (v4mapped?.[1]) return isPrivateIPv4(v4mapped[1])\n\n  return false\n}\n\nfunction isPrivateIP(ip: string): boolean {\n  if (isIP(ip) === 4) return isPrivateIPv4(ip)\n  if (isIP(ip) === 6) return isPrivateIPv6(ip)\n  return false\n}\n\n/**\n * Result of resolving a hostname for egress safety.\n *\n * - `ok` — resolved to at least one address, none of them private/loopback.\n *   Caller forwards.\n * - `private` — at least one resolved address is private/loopback. Caller\n *   refuses with a policy response (403).\n * - `unresolvable` — DNS returned NXDOMAIN, NODATA, or a query error. Caller\n *   responds with an upstream-failure code (502). Distinct from `private`\n *   because the host doesn't exist (or can't be reached) — that's not a\n *   policy decision, it's a connectivity problem, and conflating the two\n *   ships misleading 403s for typos and DNS hiccups.\n */\nexport type EgressCheckResult =\n  | { kind: 'ok' }\n  | { kind: 'private' }\n  | { kind: 'unresolvable', reason: 'no-records' | 'dns-error' }\n\n/**\n * Check whether forwarding a connection to `hostname` is safe.\n *\n * IP literals are checked directly; hostnames are resolved via DNS (A and\n * AAAA in parallel) and every returned address is screened against the\n * private-range list. If any address is private the result is `private`.\n *\n * Note on DNS-rebinding: a careful attacker could return a public IP to our\n * pre-flight resolution and a private one to the kernel's `connect()`. The\n * proper fix for that is pinning the resolved IP across the actual socket\n * call, not blocking on uncertainty — so we no longer conflate \"I couldn't\n * resolve\" with \"this is private\". Callers can layer pinning on top.\n */\nexport async function checkEgress(hostname: string): Promise<EgressCheckResult> {\n  if (isIP(hostname)) {\n    return isPrivateIP(hostname) ? { kind: 'private' } : { kind: 'ok' }\n  }\n\n  if (hostname === 'localhost') return { kind: 'private' }\n\n  let settled: PromiseSettledResult<string[]>[]\n  try {\n    settled = await Promise.allSettled([resolve4(hostname), resolve6(hostname)])\n  }\n  catch {\n    return { kind: 'unresolvable', reason: 'dns-error' }\n  }\n\n  const addrs: string[] = []\n  for (const r of settled) {\n    if (r.status === 'fulfilled') addrs.push(...r.value)\n  }\n\n  if (addrs.length === 0) {\n    return { kind: 'unresolvable', reason: 'no-records' }\n  }\n\n  return addrs.some(addr => isPrivateIP(addr)) ? { kind: 'private' } : { kind: 'ok' }\n}\n\n/**\n * Backwards-compatible boolean shim. Returns true for both `private` and\n * `unresolvable` because that matches the previous (overly conservative)\n * behaviour. New code should call `checkEgress` and distinguish.\n *\n * @deprecated Use `checkEgress` so the caller can return 502 for unresolvable\n * hosts and 403 only for actual private/loopback IPs.\n */\nexport async function isPrivateOrLoopback(hostname: string): Promise<boolean> {\n  const result = await checkEgress(hostname)\n  return result.kind !== 'ok'\n}\n","import type { IncomingMessage } from 'node:http'\nimport type { Socket } from 'node:net'\nimport { connect } from 'node:net'\nimport type { AgentConfig, MultiAgentProxyConfig, ProxyConfig, SecretsStore } from './types.js'\nimport { AuthError, verifyAgentAuth } from './auth.js'\nimport { checkEgress } from './ssrf.js'\nimport { writeAudit } from './audit.js'\nimport { evaluateRules } from './matcher.js'\nimport type { GrantsClient } from './grants-client.js'\nimport type { LeafCertCache } from './ca-store.js'\nimport { handleMitmConnect } from './mitm-connect.js'\n\n/**\n * Optional MITM injection deps. When BOTH `secretsStore` and `leafCache` are\n * present we terminate TLS in-process (CONNECT-MITM mode), inspect the inner\n * HTTPS request, and inject the matching secret header before forwarding.\n * When either is absent we fall back to the legacy raw TCP tunnel — opaque\n * pipe, no secret injection (cleartext-only inject still happens via the\n * forward-proxy fetch path).\n */\nexport interface ConnectMitmDeps {\n  secretsStore?: SecretsStore\n  leafCache?: LeafCertCache\n  upstreamRejectUnauthorized?: boolean\n  /**\n   * Daemon mode: skip per-request `Proxy-Authorization` JWT extraction on\n   * the CONNECT path. Identity is implicit — `config.agents[0]` is the\n   * daemon's loaded identity. Inline (`apes proxy --` ephemeral) mode keeps\n   * the existing JWT-required path.\n   */\n  daemonMode?: boolean\n}\n\n/**\n * Handle HTTP CONNECT requests for tunneling (used by HTTP_PROXY clients).\n * Flow: Auth → SSRF → host-based rule evaluation (allow / deny / grant_required)\n *  → TCP connect → bidirectional pipe.\n *\n * For HTTPS via CONNECT we only see the hostname (the TLS payload is opaque).\n * Rules with `methods` or `path` filters cannot be enforced at CONNECT time and\n * are skipped — they'd only match if the client also carried the same hostname\n * over cleartext-HTTP forward-proxy. This is intentional: there's no honest way\n * to gate a method we can't observe.\n */\nexport async function handleConnect(\n  config: MultiAgentProxyConfig,\n  grantsClients: Map<string, GrantsClient>,\n  req: IncomingMessage,\n  clientSocket: Socket,\n  head: Buffer,\n  deps?: ConnectMitmDeps,\n): Promise<void> {\n  const target = req.url ?? ''\n  const [host, portStr] = target.split(':')\n  const port = Number.parseInt(portStr || '443')\n\n  if (!host || !port) {\n    clientSocket.write('HTTP/1.1 400 Bad Request\\r\\n\\r\\n')\n    clientSocket.destroy()\n    return\n  }\n\n  // SYSTEM BYPASS: outbound to any configured IdP host is unconditionally\n  // allowed. The proxy itself talks to the IdP for JWT verification + grant\n  // approval, and any process inside the proxy boundary may need to call the\n  // IdP for `apes login` / `apes whoami` / token-exchange BEFORE it can ever\n  // produce a valid Proxy-Authorization JWT. Blocking IdP traffic would\n  // either deadlock the grant flow or lock users out of authentication.\n  // We therefore skip auth (no JWT yet for first-login), SSRF (local-dev IdPs\n  // can live at 127.0.0.1), and policy rules (operator must not be able to\n  // override this system invariant).\n  const idpHosts = new Set(\n    config.agents\n      .map((a) => {\n        try {\n          return new URL(a.idp_url).hostname.toLowerCase()\n        }\n        catch {\n          return ''\n        }\n      })\n      .filter(h => h.length > 0),\n  )\n  if (idpHosts.has(host.toLowerCase())) {\n    writeAudit({\n      ts: new Date().toISOString(),\n      agent: 'system',\n      action: 'allow',\n      domain: host,\n      method: 'CONNECT',\n      path: target,\n      rule: 'idp-system-bypass',\n    })\n    tunnel(host, port, clientSocket)\n    return\n  }\n\n  const mandatoryAuth = config.proxy.mandatory_auth ?? false\n  const daemonMode = deps?.daemonMode ?? false\n\n  // Auth check — CONNECT always requires auth in mandatory mode\n  let agentEmail: string | undefined\n  if (daemonMode) {\n    // Identity is implicit — the daemon was started by/for one specific\n    // agent. The first (and only) agent in config.agents is the daemon's\n    // identity, loaded from `~/.config/apes/auth.json` at startup.\n    agentEmail = config.agents[0]?.email\n  }\n  else {\n    try {\n      const authHeader = req.headers['proxy-authorization'] as string | undefined\n      let identity: { email: string, act: 'agent' } | null = null\n\n      for (const agentConf of config.agents) {\n        identity = await verifyAgentAuth(\n          authHeader ?? null,\n          agentConf.idp_url,\n          mandatoryAuth && config.agents.length === 1,\n        )\n        if (identity) break\n      }\n\n      if (mandatoryAuth && !identity) {\n        throw new AuthError('JWT required')\n      }\n\n      agentEmail = identity?.email\n\n      // Verify agent is known\n      if (agentEmail) {\n        const known = config.agents.find(a => a.email === agentEmail)\n        if (!known) {\n          clientSocket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n')\n          clientSocket.destroy()\n          return\n        }\n      }\n      else if (config.agents.length > 1) {\n        throw new AuthError('JWT required for multi-agent proxy')\n      }\n    }\n    catch (err) {\n      if (err instanceof AuthError) {\n        clientSocket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n')\n        clientSocket.destroy()\n        return\n      }\n      throw err\n    }\n  }\n\n  // SSRF / reachability check. We split the two outcomes:\n  //   - `private`        → policy refusal, 403 (the proxy will not forward).\n  //   - `unresolvable`   → upstream not reachable, 502 (DNS NXDOMAIN /\n  //     NODATA / query error — distinct from \"I refuse on policy grounds\";\n  //     conflating them shipped misleading 403s for typos like\n  //     `apes proxy -- curl https://example.at`).\n  const egress = await checkEgress(host)\n  const auditAgent = agentEmail ?? config.agents[0]?.email ?? 'unknown'\n  if (egress.kind === 'private') {\n    writeAudit({\n      ts: new Date().toISOString(),\n      agent: auditAgent,\n      action: 'deny',\n      domain: host,\n      method: 'CONNECT',\n      path: target,\n      rule: 'ssrf-blocked',\n    })\n    clientSocket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n')\n    clientSocket.destroy()\n    return\n  }\n  if (egress.kind === 'unresolvable') {\n    writeAudit({\n      ts: new Date().toISOString(),\n      agent: auditAgent,\n      action: 'error',\n      domain: host,\n      method: 'CONNECT',\n      path: target,\n      rule: `dns-unresolvable (${egress.reason})`,\n    })\n    clientSocket.write(\n      `HTTP/1.1 502 Bad Gateway\\r\\nContent-Type: text/plain\\r\\n\\r\\nDNS lookup failed for ${host} (${egress.reason}).\\r\\n`,\n    )\n    clientSocket.destroy()\n    return\n  }\n\n  // Host-based rule evaluation. Pick the agent's config: in single-agent or\n  // unauth mode this is just config.agents[0]; in multi-agent mode we use the\n  // identity established above.\n  const agentConf: AgentConfig | undefined = agentEmail\n    ? config.agents.find(a => a.email === agentEmail)\n    : config.agents[0]\n  if (!agentConf) {\n    clientSocket.write('HTTP/1.1 403 Forbidden\\r\\n\\r\\n')\n    clientSocket.destroy()\n    return\n  }\n  const effectiveEmail = agentEmail ?? agentConf.email\n\n  const rulesConfig: ProxyConfig = {\n    proxy: {\n      listen: config.proxy.listen,\n      idp_url: agentConf.idp_url,\n      agent_email: agentConf.email,\n      default_action: config.proxy.default_action,\n    },\n    allow: agentConf.allow ?? [],\n    deny: agentConf.deny ?? [],\n    grant_required: agentConf.grant_required ?? [],\n  }\n\n  // CONNECT carries no method/path beyond host:port. Pass 'CONNECT' as method\n  // and '/' as path so rules with method-filters (which we can't enforce here)\n  // simply don't match — operator must specify method-less rules to gate\n  // HTTPS hosts.\n  const action = evaluateRules(rulesConfig, host, 'CONNECT', '/')\n  const baseAudit = {\n    ts: new Date().toISOString(),\n    agent: effectiveEmail,\n    domain: host,\n    method: 'CONNECT',\n    path: target,\n  } as const\n\n  if (action.type === 'deny') {\n    writeAudit({ ...baseAudit, action: 'deny', rule: 'deny-list' })\n    const note = action.note ? ` ${action.note}` : ''\n    clientSocket.write(`HTTP/1.1 403 Forbidden\\r\\nContent-Type: text/plain\\r\\n\\r\\nBlocked:${note}\\r\\n`)\n    clientSocket.destroy()\n    return\n  }\n\n  if (action.type === 'grant_required') {\n    const grantsClient = grantsClients.get(agentConf.email)\n    if (!grantsClient) {\n      writeAudit({ ...baseAudit, action: 'deny', rule: 'grant_required (no client)' })\n      clientSocket.write('HTTP/1.1 500 Internal Server Error\\r\\n\\r\\nNo grants client for agent\\r\\n')\n      clientSocket.destroy()\n      return\n    }\n\n    // Async-mode (`request-async`) is meaningful for HTTP forward-proxy where\n    // the client can re-issue the request after approval. CONNECT clients\n    // (curl, gh, …) won't transparently retry on 407 mid-handshake, so we\n    // always block the tunnel until the grant resolves. Operator can shorten\n    // the wait via per-rule `duration` or via the IdP's grant TTL.\n    const startTs = Date.now()\n    try {\n      const grant = await grantsClient.requestGrant({\n        requester: effectiveEmail,\n        targetHost: host,\n        audience: 'ape-proxy',\n        grantType: action.rule.grant_type,\n        permissions: action.rule.permissions,\n        reason: `CONNECT ${host}:${port}`,\n        duration: action.rule.duration,\n      })\n      const decided = await grantsClient.waitForApproval(grant.id)\n      const waitedMs = Date.now() - startTs\n      if (decided.status === 'approved') {\n        writeAudit({ ...baseAudit, action: 'grant_approved', rule: 'grant_required', grant_id: decided.id, waited_ms: waitedMs })\n        // Fall through to the TCP connect below.\n      }\n      else {\n        writeAudit({ ...baseAudit, action: 'grant_denied', rule: 'grant_required', grant_id: decided.id, waited_ms: waitedMs })\n        clientSocket.write(`HTTP/1.1 403 Forbidden\\r\\n\\r\\nGrant denied by ${decided.decided_by ?? 'policy'}\\r\\n`)\n        clientSocket.destroy()\n        return\n      }\n    }\n    catch (err) {\n      const msg = err instanceof Error ? err.message : 'Unknown error'\n      writeAudit({ ...baseAudit, action: 'grant_timeout', rule: 'grant_required', error: msg })\n      clientSocket.write(`HTTP/1.1 504 Gateway Timeout\\r\\n\\r\\nGrant request failed: ${msg}\\r\\n`)\n      clientSocket.destroy()\n      return\n    }\n  }\n  else {\n    // 'allow' — log and continue.\n    writeAudit({ ...baseAudit, action: 'allow', rule: 'allow-list' })\n  }\n\n  // CONNECT-MITM mode: when both a secrets store and a leaf-cert cache are\n  // wired in, terminate TLS in-process so we can inspect the inner request\n  // and inject the matching secret header before forwarding upstream. The\n  // 200-Established line is OUR responsibility here — `handleMitmConnect`\n  // assumes the client is already in TLS-handshake mode on the socket.\n  // Without both deps we keep the legacy opaque TCP pipe (inline mode); the\n  // IdP system-bypass branch above also stays on the legacy path so we never\n  // MITM the proxy's own auth traffic.\n  if (deps?.secretsStore && deps?.leafCache) {\n    // Pause to avoid data races between our 200-write and TLSSocket wrap. The\n    // TLSSocket constructor in `handleMitmConnect` calls `resume()` once it has\n    // attached its read pipeline.\n    clientSocket.pause()\n    clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n    // Push any bytes the http parser already captured after the CONNECT headers\n    // back into the socket so the TLSSocket sees them as the start of the\n    // ClientHello. Rare for CONNECT but possible if the client pipelines.\n    if (head.length > 0) {\n      clientSocket.unshift(head)\n    }\n    const store = deps.secretsStore\n    handleMitmConnect({\n      clientSocket,\n      host,\n      port,\n      leafCache: deps.leafCache,\n      upstreamRejectUnauthorized: deps.upstreamRejectUnauthorized,\n      onRequest: (mreq) => {\n        // `mreq.host` is the SNI hostname only — `port` is carried separately\n        // because handleMitmConnect splits CONNECT host:port at the boundary.\n        // Reattach a non-default port so secret target globs like\n        // `host:port/*` can match (the matcher's `targetString` keeps explicit\n        // non-default ports verbatim).\n        const portSuffix = port === 443 ? '' : `:${port}`\n        const targetUrl = new URL(`https://${mreq.host}${portSuffix}${mreq.path}`)\n        const match = store.findFor(targetUrl)\n        if (!match) return { type: 'forward', mutatedHeaders: new Map() }\n        const rendered = match.template.replace(/\\$\\{value\\}/g, match.value)\n        // Redacted log line — only name/header/method/url, never the secret.\n        console.error(\n          `[openape-proxy] injected secret '${match.name}' into ${match.header} for ${mreq.method} ${targetUrl.href}`,\n        )\n        return {\n          type: 'forward',\n          mutatedHeaders: new Map([[match.header.toLowerCase(), rendered]]),\n        }\n      },\n    })\n    return\n  }\n\n  tunnel(host, port, clientSocket)\n}\n\n/**\n * Open a TCP socket to host:port and bidirectionally pipe it with the client\n * socket. Used by both the policy-pass path (auth + rules approved) and the\n * IdP system-bypass path (no auth/policy involved).\n */\nfunction tunnel(host: string, port: number, clientSocket: Socket): void {\n  const targetSocket = connect(port, host, () => {\n    clientSocket.write('HTTP/1.1 200 Connection Established\\r\\n\\r\\n')\n    targetSocket.pipe(clientSocket)\n    clientSocket.pipe(targetSocket)\n  })\n\n  targetSocket.on('error', () => {\n    clientSocket.write('HTTP/1.1 502 Bad Gateway\\r\\n\\r\\n')\n    clientSocket.destroy()\n  })\n\n  clientSocket.on('error', () => {\n    targetSocket.destroy()\n  })\n\n  clientSocket.on('close', () => targetSocket.destroy())\n  targetSocket.on('close', () => clientSocket.destroy())\n}\n","import { TLSSocket, createSecureContext, connect as tlsConnect } from 'node:tls'\nimport type { Socket } from 'node:net'\nimport type { LeafCertCache } from './ca-store.js'\n\ninterface MitmRequest {\n  method: string\n  host: string\n  path: string\n  headers: Map<string, string>\n  body: Buffer | null\n}\n\ntype MitmDecision =\n  | { type: 'short-circuit', status: number, body: string }\n  | { type: 'forward', mutatedHeaders: Map<string, string> }\n\nexport interface MitmConnectOpts {\n  clientSocket: Socket\n  host: string\n  port: number\n  leafCache: LeafCertCache\n  onRequest: (req: MitmRequest) => MitmDecision\n  upstreamRejectUnauthorized?: boolean\n}\n\nexport function handleMitmConnect(opts: MitmConnectOpts): void {\n  const leaf = opts.leafCache.get(opts.host)\n  const ctx = createSecureContext({ cert: leaf.certPem, key: leaf.keyPem })\n  // The CONNECT 200 response is the caller's responsibility (see `connect.ts`).\n  // By the time we get here the client is already in TLS-handshake mode on the\n  // socket, so we must not inject any plaintext bytes before TLS termination.\n  const tls = new TLSSocket(opts.clientSocket, { isServer: true, secureContext: ctx })\n  // Resume the underlying socket now that TLSSocket is attached so any paused\n  // data starts flowing into the TLS layer. Safe even if the socket wasn't\n  // paused — `resume()` is a no-op in that case.\n  opts.clientSocket.resume()\n\n  let buffer = Buffer.alloc(0)\n  let dispatched = false\n  const onData = (chunk: Buffer) => {\n    if (dispatched) return // short-circuit path already wrote the response and ended the socket\n    buffer = Buffer.concat([buffer, chunk])\n    const headerEnd = buffer.indexOf('\\r\\n\\r\\n')\n    if (headerEnd < 0) return // incomplete\n\n    const headerBlock = buffer.subarray(0, headerEnd).toString('utf-8')\n    const lines = headerBlock.split('\\r\\n')\n    const requestLine = lines[0] ?? ''\n    const [method, path] = requestLine.split(' ')\n    const headers = new Map<string, string>()\n    for (const line of lines.slice(1)) {\n      const i = line.indexOf(':')\n      if (i > 0) headers.set(line.slice(0, i).trim().toLowerCase(), line.slice(i + 1).trim())\n    }\n\n    const decision = opts.onRequest({\n      method: method ?? '',\n      host: opts.host,\n      path: path ?? '/',\n      headers,\n      // inject decisions use only target+headers; raw body bytes still flow through to upstream below\n      body: null,\n    })\n\n    if (decision.type === 'short-circuit') {\n      dispatched = true\n      const body = Buffer.from(decision.body, 'utf-8')\n      tls.write(`HTTP/1.1 ${decision.status} OK\\r\\nContent-Length: ${body.length}\\r\\n\\r\\n`)\n      tls.write(body)\n      tls.end()\n      return\n    }\n\n    // forward path: open upstream TLS, write the mutated request + any body bytes already buffered,\n    // then pipe upstream ↔ client. Subsequent client bytes (request bodies for streaming uploads,\n    // pipelined requests) are forwarded raw via tls.pipe(upstream).\n    //\n    // Race guard: the upstream TLS handshake is async; while we wait for\n    // `secureConnect`, the client may send additional body chunks (think\n    // `curl --data-binary @big.bin`). Without pausing, those chunks would\n    // fire this same `data` listener again and be dropped. Pausing here\n    // keeps the chunks buffered inside the TLSSocket; we resume them only\n    // after `tls.pipe(upstream)` is wired *and* this listener is detached,\n    // so they flow straight through the pipe instead of re-entering this\n    // handler.\n    dispatched = true\n    tls.pause()\n    const upstream = tlsConnect({\n      host: opts.host,\n      port: opts.port,\n      servername: opts.host,\n      rejectUnauthorized: opts.upstreamRejectUnauthorized ?? true,\n    })\n    upstream.once('secureConnect', () => {\n      // Re-serialize the request: keep all original header lines except the ones being mutated;\n      // append mutated headers at the end with canonical capitalization.\n      const mutated = decision.mutatedHeaders\n      const newHeaderLines: string[] = []\n      for (const line of lines.slice(1)) {\n        const i = line.indexOf(':')\n        if (i <= 0) continue\n        const lower = line.slice(0, i).trim().toLowerCase()\n        if (mutated.has(lower)) continue // we'll write the mutated version below\n        newHeaderLines.push(line)\n      }\n      for (const [name, value] of mutated.entries()) {\n        newHeaderLines.push(`${capitalizeHeader(name)}: ${value}`)\n      }\n      const fullRequest = [requestLine, ...newHeaderLines, '', ''].join('\\r\\n')\n      upstream.write(fullRequest)\n      // body bytes that arrived in the same chunk as the header block:\n      const remainder = buffer.subarray(headerEnd + 4)\n      if (remainder.length > 0) upstream.write(remainder)\n      upstream.pipe(tls)\n      // detach this handler before resuming so paused chunks land in the\n      // pipe rather than firing onData again (which would early-return on\n      // `dispatched` and drop them).\n      tls.removeListener('data', onData)\n      // any further client-side bytes (streaming uploads / pipelined requests) flow upstream raw\n      tls.pipe(upstream)\n      tls.resume()\n    })\n    upstream.on('error', () => tls.end())\n  }\n  tls.on('data', onData)\n  tls.on('error', () => opts.clientSocket.destroy())\n}\n\nfunction capitalizeHeader(name: string): string {\n  return name\n    .split('-')\n    .map(p => (p[0]?.toUpperCase() ?? '') + p.slice(1))\n    .join('-')\n}\n","import { parse as parseTOML } from 'smol-toml'\nimport type { SecretEntry, SecretsStore } from './types.js'\nimport { matchSecret } from './secrets-match.js'\n\nconst MAX_BLOB_BYTES = 4 * 1024\nconst SUPPORTED_VERSION = '1'\n\nexport function parseSecretsBlob(toml: string): SecretsStore {\n  if (Buffer.byteLength(toml, 'utf-8') > MAX_BLOB_BYTES) {\n    throw new Error(`Secrets blob too large (max ${MAX_BLOB_BYTES} bytes / 4 KiB)`)\n  }\n\n  const parsed = parseTOML(toml) as Record<string, unknown>\n  const version = parsed.version\n  if (version !== SUPPORTED_VERSION) {\n    throw new Error(`Unsupported or missing version (expected \"${SUPPORTED_VERSION}\", got ${JSON.stringify(version)})`)\n  }\n\n  const secretsBlock = parsed.secrets as Record<string, Partial<SecretEntry>> | undefined\n  const entries: SecretEntry[] = []\n  if (secretsBlock) {\n    for (const [name, raw] of Object.entries(secretsBlock)) {\n      const required: (keyof SecretEntry)[] = ['target', 'header', 'template', 'value']\n      for (const field of required) {\n        if (!raw[field] || typeof raw[field] !== 'string') {\n          throw new Error(`Secret '${name}' is missing required field '${field}'`)\n        }\n      }\n      entries.push({\n        name,\n        target: raw.target!,\n        header: raw.header!,\n        template: raw.template!,\n        value: raw.value!,\n      })\n    }\n  }\n\n  // Reject duplicate-specificity targets.\n  const literalPrefix = (glob: string): string => {\n    const i = glob.indexOf('*')\n    return i < 0 ? glob : glob.slice(0, i)\n  }\n  const seen = new Map<string, string>()\n  for (const e of entries) {\n    const key = `${literalPrefix(e.target)}|${e.target}`\n    if (seen.has(key)) {\n      throw new Error(`Duplicate target with identical specificity: '${e.target}' (entries '${seen.get(key)}' and '${e.name}')`)\n    }\n    seen.set(key, e.name)\n  }\n\n  return {\n    entries,\n    findFor: target => matchSecret(target, entries),\n  }\n}\n","import type { SecretEntry } from './types.js'\n\n/** Compile a glob pattern to a RegExp. Supports `*` (any segment) only. */\nfunction compileGlob(glob: string): RegExp {\n  const escaped = glob.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '.*')\n  return new RegExp(`^${escaped}$`)\n}\n\nfunction literalPrefixLen(glob: string): number {\n  const i = glob.indexOf('*')\n  return i < 0 ? glob.length : i\n}\n\nfunction targetString(url: URL): string {\n  // host[:port]/path — port included only when explicit and non-default.\n  const port = url.port ? `:${url.port}` : ''\n  const path = url.pathname === '/' ? '' : url.pathname\n  return `${url.hostname}${port}${path}`\n}\n\nexport function matchSecret(target: URL, entries: readonly SecretEntry[]): SecretEntry | null {\n  const targetStr = targetString(target)\n  let best: { entry: SecretEntry, prefix: number } | null = null\n\n  for (const entry of entries) {\n    const re = compileGlob(entry.target)\n    if (!re.test(targetStr) && !re.test(`${targetStr}/`)) continue\n    const prefix = literalPrefixLen(entry.target)\n    if (!best || prefix > best.prefix) {\n      best = { entry, prefix }\n    }\n  }\n  return best?.entry ?? null\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","forge","import_node_fs","parseTOML","import_node_net","tlsConnect","agentConf","agentConf","import_smol_toml","parseTOML"]}