Files
openclaw/src/plugin-sdk/channel-policy.test.ts
2026-04-06 19:36:01 +01:00

136 lines
4.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { formatPairingApproveHint } from "../channels/plugins/helpers.js";
import type { GroupPolicy } from "../config/types.base.js";
import {
coerceNativeSetting,
createDangerousNameMatchingMutableAllowlistWarningCollector,
createRestrictSendersChannelSecurity,
normalizeAllowFromList,
} from "./channel-policy.js";
describe("createRestrictSendersChannelSecurity", () => {
it("builds dm policy resolution and open-group warnings from one descriptor", async () => {
const security = createRestrictSendersChannelSecurity<{
accountId: string;
allowFrom?: string[];
dmPolicy?: string;
groupPolicy?: GroupPolicy;
}>({
channelKey: "line",
resolveDmPolicy: (account) => account.dmPolicy,
resolveDmAllowFrom: (account) => account.allowFrom,
resolveGroupPolicy: (account) => account.groupPolicy,
surface: "LINE groups",
openScope: "any member in groups",
groupPolicyPath: "channels.line.groupPolicy",
groupAllowFromPath: "channels.line.groupAllowFrom",
mentionGated: false,
policyPathSuffix: "dmPolicy",
});
expect(
security.resolveDmPolicy?.({
cfg: { channels: {} } as never,
accountId: "default",
account: {
accountId: "default",
dmPolicy: "allowlist",
allowFrom: ["line:user:abc"],
},
}),
).toEqual({
policy: "allowlist",
allowFrom: ["line:user:abc"],
policyPath: "channels.line.dmPolicy",
allowFromPath: "channels.line.",
approveHint: formatPairingApproveHint("line"),
normalizeEntry: undefined,
});
expect(
security.collectWarnings?.({
cfg: { channels: { line: {} } } as never,
accountId: "default",
account: {
accountId: "default",
groupPolicy: "open",
},
}),
).toEqual([
'- LINE groups: groupPolicy="open" allows any member in groups to trigger. Set channels.line.groupPolicy="allowlist" + channels.line.groupAllowFrom to restrict senders.',
]);
});
});
describe("createDangerousNameMatchingMutableAllowlistWarningCollector", () => {
const collectWarnings = createDangerousNameMatchingMutableAllowlistWarningCollector({
channel: "irc",
detector: (entry) => !entry.includes("@"),
collectLists: (scope) => [
{
pathLabel: `${scope.prefix}.allowFrom`,
list: scope.account.allowFrom,
},
],
});
it("collects mutable entries while dangerous matching is disabled", () => {
expect(
collectWarnings({
cfg: {
channels: {
irc: {
allowFrom: ["charlie"],
},
},
} as never,
}),
).toEqual(
expect.arrayContaining([
expect.stringContaining("mutable allowlist entry"),
expect.stringContaining("channels.irc.allowFrom: charlie"),
]),
);
});
it("skips scopes that explicitly allow dangerous name matching", () => {
expect(
collectWarnings({
cfg: {
channels: {
irc: {
dangerouslyAllowNameMatching: true,
allowFrom: ["charlie"],
},
},
} as never,
}),
).toEqual([]);
});
});
describe("normalizeAllowFromList", () => {
it("normalizes strings and numbers into trimmed entries", () => {
expect(normalizeAllowFromList([" abc ", 42, "", " "])).toEqual(["abc", "42"]);
});
it("returns an empty list for non-arrays", () => {
expect(normalizeAllowFromList(undefined)).toEqual([]);
expect(normalizeAllowFromList(null)).toEqual([]);
});
});
describe("coerceNativeSetting", () => {
it("keeps boolean and auto values", () => {
expect(coerceNativeSetting(true)).toBe(true);
expect(coerceNativeSetting(false)).toBe(false);
expect(coerceNativeSetting("auto")).toBe("auto");
});
it("drops unsupported values", () => {
expect(coerceNativeSetting("true")).toBeUndefined();
expect(coerceNativeSetting("on")).toBeUndefined();
expect(coerceNativeSetting(1)).toBeUndefined();
});
});