mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-02 05:24:51 +00:00
Followup nits from the #84711 review: - Narrow the inspectTokenFile catch in extensions/telegram/src/account-inspect.ts to FsSafeError so only fs-safe validation throws map to configured_unavailable; any other throw (programmer error, unexpected I/O) is rethrown. - Add a regression test for the IRC NickServ password file symlink rejection path (extensions/irc/src/accounts.ts:118), paralleling the existing top-level passwordFile test. - Add a regression test for the Telegram account-level tokenFile symlink rejection path (extensions/telegram/src/token.ts:149), paralleling the existing channel-level tokenFile test. Behavior was already correct after #84711; this just locks coverage and tightens the catch.
224 lines
5.8 KiB
TypeScript
224 lines
5.8 KiB
TypeScript
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { listIrcAccountIds, resolveDefaultIrcAccountId, resolveIrcAccount } from "./accounts.js";
|
|
import type { CoreConfig } from "./types.js";
|
|
|
|
function asConfig(value: unknown): CoreConfig {
|
|
return value as CoreConfig;
|
|
}
|
|
|
|
describe("listIrcAccountIds", () => {
|
|
it("returns default when no accounts are configured", () => {
|
|
expect(listIrcAccountIds(asConfig({}))).toEqual(["default"]);
|
|
});
|
|
|
|
it("normalizes, deduplicates, and sorts configured account ids", () => {
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
accounts: {
|
|
"Ops Team": {},
|
|
"ops-team": {},
|
|
Work: {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(listIrcAccountIds(cfg)).toEqual(["ops-team", "work"]);
|
|
});
|
|
|
|
it("keeps the implicit default account when named accounts are added to top-level connection config", () => {
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
accounts: {
|
|
work: {
|
|
enabled: false,
|
|
host: "irc-work.example.com",
|
|
nick: "claw-work",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(listIrcAccountIds(cfg)).toEqual(["default", "work"]);
|
|
expect(resolveDefaultIrcAccountId(cfg)).toBe("default");
|
|
});
|
|
});
|
|
|
|
describe("resolveDefaultIrcAccountId", () => {
|
|
it("prefers configured defaultAccount when it matches", () => {
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
defaultAccount: "Ops Team",
|
|
accounts: {
|
|
default: {},
|
|
"ops-team": {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(resolveDefaultIrcAccountId(cfg)).toBe("ops-team");
|
|
});
|
|
|
|
it("falls back to default when configured defaultAccount is missing", () => {
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
defaultAccount: "missing",
|
|
accounts: {
|
|
default: {},
|
|
work: {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(resolveDefaultIrcAccountId(cfg)).toBe("default");
|
|
});
|
|
|
|
it("falls back to first sorted account when default is absent", () => {
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
accounts: {
|
|
zzz: {},
|
|
aaa: {},
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(resolveDefaultIrcAccountId(cfg)).toBe("aaa");
|
|
});
|
|
});
|
|
|
|
describe("resolveIrcAccount", () => {
|
|
it("matches normalized configured account ids", () => {
|
|
const account = resolveIrcAccount({
|
|
cfg: asConfig({
|
|
channels: {
|
|
irc: {
|
|
accounts: {
|
|
"Ops Team": {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
accountId: "ops-team",
|
|
});
|
|
|
|
expect(account.accountId).toBe("ops-team");
|
|
expect(account.host).toBe("irc.example.com");
|
|
expect(account.nick).toBe("claw");
|
|
expect(account.configured).toBe(true);
|
|
});
|
|
|
|
it("parses delimited IRC_CHANNELS env values for the default account", () => {
|
|
vi.stubEnv("IRC_CHANNELS", "alpha, beta\ngamma; delta");
|
|
|
|
try {
|
|
const account = resolveIrcAccount({
|
|
cfg: asConfig({
|
|
channels: {
|
|
irc: {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
},
|
|
},
|
|
}),
|
|
});
|
|
|
|
expect(account.config.channels).toEqual(["alpha", "beta", "gamma", "delta"]);
|
|
} finally {
|
|
vi.unstubAllEnvs();
|
|
}
|
|
});
|
|
|
|
it.runIf(process.platform !== "win32")("rejects symlinked password files", () => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-irc-account-"));
|
|
const passwordFile = path.join(dir, "password.txt");
|
|
const passwordLink = path.join(dir, "password-link.txt");
|
|
fs.writeFileSync(passwordFile, "secret-pass\n", "utf8");
|
|
fs.symlinkSync(passwordFile, passwordLink);
|
|
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
passwordFile: passwordLink,
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(() => resolveIrcAccount({ cfg })).toThrow(/IRC password file.*must not be a symlink/);
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
|
|
it.runIf(process.platform !== "win32")("rejects symlinked NickServ password files", () => {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-irc-nickserv-"));
|
|
const passwordFile = path.join(dir, "nickserv-password.txt");
|
|
const passwordLink = path.join(dir, "nickserv-password-link.txt");
|
|
fs.writeFileSync(passwordFile, "nickserv-pass\n", "utf8");
|
|
fs.symlinkSync(passwordFile, passwordLink);
|
|
|
|
const cfg = asConfig({
|
|
channels: {
|
|
irc: {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
nickserv: {
|
|
passwordFile: passwordLink,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(() => resolveIrcAccount({ cfg })).toThrow(
|
|
/IRC NickServ password file.*must not be a symlink/,
|
|
);
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("preserves shared NickServ config when an account overrides one NickServ field", () => {
|
|
const account = resolveIrcAccount({
|
|
cfg: asConfig({
|
|
channels: {
|
|
irc: {
|
|
host: "irc.example.com",
|
|
nick: "claw",
|
|
nickserv: {
|
|
service: "NickServ",
|
|
},
|
|
accounts: {
|
|
work: {
|
|
nickserv: {
|
|
registerEmail: "work@example.com",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
accountId: "work",
|
|
});
|
|
|
|
expect(account.config.nickserv).toEqual({
|
|
service: "NickServ",
|
|
registerEmail: "work@example.com",
|
|
});
|
|
});
|
|
});
|