45 lines
2.1 KiB
TypeScript
45 lines
2.1 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import test from "node:test";
|
|
import { parseConfig } from "../src/config.js";
|
|
import { assertOperationalConfig, loadConfigFile, writeConfigFile } from "../src/cli/config-file.js";
|
|
|
|
const config = parseConfig({
|
|
configVersion: 3,
|
|
bot: { id: "file-bot", workspace: "/tmp", persona: "", agent: { id: "node", command: process.execPath, args: ["acp"] }, permissions: { mode: "deny" } },
|
|
gateway: { platform: { type: "webhook", secret: "secret" } },
|
|
runtime: {}
|
|
});
|
|
|
|
test("runtime config loading fails closed instead of seeding example", () => {
|
|
const missing = path.join(os.tmpdir(), `gori-missing-${Date.now()}`, "config.json");
|
|
assert.throws(() => loadConfigFile(missing), /documentation only/);
|
|
});
|
|
|
|
test("config writes are atomic and mode 0600", async () => {
|
|
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "gori-config-write-"));
|
|
const file = path.join(dir, "config.json");
|
|
writeConfigFile(file, config);
|
|
assert.equal((await fs.promises.stat(dir)).mode & 0o777, 0o700);
|
|
assert.equal((await fs.promises.stat(file)).mode & 0o777, 0o600);
|
|
assert.equal(loadConfigFile(file).config.bot.id, "file-bot");
|
|
assert.equal((await fs.promises.readdir(dir)).some((name) => name.endsWith(".tmp")), false);
|
|
});
|
|
|
|
test("operational validation rejects placeholders for every credential family", () => {
|
|
assert.doesNotThrow(() => assertOperationalConfig(config));
|
|
const platforms = [
|
|
{ type: "qq", appId: "QQ_APP_ID", clientSecret: "QQ_CLIENT_SECRET", botNames: ["QQ_BOT_NAME"] },
|
|
{ type: "feishu", appId: "FEISHU_APP_ID", appSecret: "FEISHU_APP_SECRET" },
|
|
{ type: "wecom", corpId: "WECOM_CORP_ID", agentId: "WECOM_AGENT_ID", secret: "WECOM_SECRET" },
|
|
{ type: "webhook", secret: "WEBHOOK_SECRET" },
|
|
{ type: "weixin", secret: "WEIXIN_SECRET" }
|
|
];
|
|
for (const platform of platforms) {
|
|
const candidate = parseConfig({ ...config, gateway: { ...config.gateway, platform } });
|
|
assert.throws(() => assertOperationalConfig(candidate), /missing or placeholder/);
|
|
}
|
|
});
|