import assert from "node:assert/strict"; import fs from "node:fs"; import os from "node:os"; import net from "node:net"; import path from "node:path"; import test from "node:test"; import { parseConfig } from "../src/config.js"; import { createGatewayRuntime, startServer } from "../src/server.js"; const fixture = path.resolve("test/fixtures/fake-acp-agent.mjs"); test("server mounts only selected platform and exposes non-secret identity health", { concurrency: false }, async () => { const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-")); const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home; const secret = "never-expose-this-secret"; const config = parseConfig({ configVersion: 3, bot: { id: "route-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } }, gateway: { platform: { type: "webhook", secret } }, runtime: {} }); const runtime = await createGatewayRuntime(config); const server = runtime.app.listen(0, "127.0.0.1"); await new Promise((resolve) => server.once("listening", resolve)); try { const address = server.address(); assert.ok(address && typeof address !== "string"); const base = `http://127.0.0.1:${address.port}`; const health = await (await fetch(`${base}/health`)).text(); assert.match(health, /"configVersion":3/); assert.match(health, /"botId":"route-bot"/); assert.match(health, /"platform":"webhook"/); assert.doesNotMatch(health, new RegExp(secret)); assert.equal((await fetch(`${base}/webhook/qq`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" })).status, 404); assert.notEqual((await fetch(`${base}/webhook/generic`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" })).status, 404); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); await runtime.shutdown(); if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous; } }); test("QQ websocket mode does not mount the QQ webhook route", { concurrency: false }, async () => { const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-qq-")); const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home; const config = parseConfig({ configVersion: 3, bot: { id: "qq-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } }, gateway: { platform: { type: "qq", connectionMode: "websocket", appId: "id", clientSecret: "secret", botNames: ["Bot"] } }, runtime: {} }); const runtime = await createGatewayRuntime(config); const server = runtime.app.listen(0, "127.0.0.1"); await new Promise((resolve) => server.once("listening", resolve)); try { const address = server.address(); assert.ok(address && typeof address !== "string"); const response = await fetch(`http://127.0.0.1:${address.port}/webhook/qq`, { method: "POST", headers: { "content-type": "application/json" }, body: "{}" }); assert.equal(response.status, 404); } finally { await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())); await runtime.shutdown(); if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous; } }); test("listen failure releases the session state lock", { concurrency: false }, async () => { const home = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-server-conflict-")); const previous = process.env.GORI_AGENT_HOME; process.env.GORI_AGENT_HOME = home; const occupied = net.createServer(); await new Promise((resolve) => occupied.listen(0, "127.0.0.1", resolve)); const address = occupied.address(); assert.ok(address && typeof address !== "string"); const config = parseConfig({ configVersion: 3, bot: { id: "conflict-bot", workspace: path.resolve("."), persona: "", agent: { id: "fake", command: process.execPath, args: [fixture] }, permissions: { mode: "deny" } }, gateway: { server: { host: "127.0.0.1", port: address.port }, platform: { type: "webhook", secret: "secret" } }, runtime: {} }); try { await assert.rejects(startServer(config), /EADDRINUSE/); const runtime = await createGatewayRuntime(config); await runtime.shutdown(); } finally { await new Promise((resolve, reject) => occupied.close((error) => error ? reject(error) : resolve())); if (previous === undefined) delete process.env.GORI_AGENT_HOME; else process.env.GORI_AGENT_HOME = previous; } });