| import { describe, expect, it } from "vitest"; |
| import type { OpenClawConfig } from "../../config/config.js"; |
| import { |
| buildAccountScopedDmSecurityPolicy, |
| formatPairingApproveHint, |
| parseOptionalDelimitedEntries, |
| } from "./helpers.js"; |
|
|
| function cfgWithChannel(channelKey: string, accounts?: Record<string, unknown>): OpenClawConfig { |
| return { |
| channels: { |
| [channelKey]: accounts ? { accounts } : {}, |
| }, |
| } as unknown as OpenClawConfig; |
| } |
|
|
| describe("buildAccountScopedDmSecurityPolicy", () => { |
| it("builds top-level dm policy paths when no account config exists", () => { |
| expect( |
| buildAccountScopedDmSecurityPolicy({ |
| cfg: cfgWithChannel("telegram"), |
| channelKey: "telegram", |
| fallbackAccountId: "default", |
| policy: "pairing", |
| allowFrom: ["123"], |
| policyPathSuffix: "dmPolicy", |
| }), |
| ).toEqual({ |
| policy: "pairing", |
| allowFrom: ["123"], |
| policyPath: "channels.telegram.dmPolicy", |
| allowFromPath: "channels.telegram.", |
| approveHint: formatPairingApproveHint("telegram"), |
| normalizeEntry: undefined, |
| }); |
| }); |
|
|
| it("uses account-scoped paths when account config exists", () => { |
| expect( |
| buildAccountScopedDmSecurityPolicy({ |
| cfg: cfgWithChannel("signal", { work: {} }), |
| channelKey: "signal", |
| accountId: "work", |
| fallbackAccountId: "default", |
| policy: "allowlist", |
| allowFrom: ["+12125551212"], |
| policyPathSuffix: "dmPolicy", |
| }), |
| ).toEqual({ |
| policy: "allowlist", |
| allowFrom: ["+12125551212"], |
| policyPath: "channels.signal.accounts.work.dmPolicy", |
| allowFromPath: "channels.signal.accounts.work.", |
| approveHint: formatPairingApproveHint("signal"), |
| normalizeEntry: undefined, |
| }); |
| }); |
|
|
| it("supports nested dm paths without explicit policyPath", () => { |
| expect( |
| buildAccountScopedDmSecurityPolicy({ |
| cfg: cfgWithChannel("discord", { work: {} }), |
| channelKey: "discord", |
| accountId: "work", |
| policy: "pairing", |
| allowFrom: [], |
| allowFromPathSuffix: "dm.", |
| }), |
| ).toEqual({ |
| policy: "pairing", |
| allowFrom: [], |
| policyPath: undefined, |
| allowFromPath: "channels.discord.accounts.work.dm.", |
| approveHint: formatPairingApproveHint("discord"), |
| normalizeEntry: undefined, |
| }); |
| }); |
|
|
| it("supports custom defaults and approve hints", () => { |
| expect( |
| buildAccountScopedDmSecurityPolicy({ |
| cfg: cfgWithChannel("synology-chat"), |
| channelKey: "synology-chat", |
| fallbackAccountId: "default", |
| allowFrom: ["user-1"], |
| defaultPolicy: "allowlist", |
| policyPathSuffix: "dmPolicy", |
| approveHint: "openclaw pairing approve synology-chat <code>", |
| }), |
| ).toEqual({ |
| policy: "allowlist", |
| allowFrom: ["user-1"], |
| policyPath: "channels.synology-chat.dmPolicy", |
| allowFromPath: "channels.synology-chat.", |
| approveHint: "openclaw pairing approve synology-chat <code>", |
| normalizeEntry: undefined, |
| }); |
| }); |
| }); |
|
|
| describe("parseOptionalDelimitedEntries", () => { |
| it("returns undefined for empty input", () => { |
| expect(parseOptionalDelimitedEntries(" ")).toBeUndefined(); |
| }); |
|
|
| it("splits comma, newline, and semicolon separated entries", () => { |
| expect(parseOptionalDelimitedEntries("alpha, beta\ngamma; delta")).toEqual([ |
| "alpha", |
| "beta", |
| "gamma", |
| "delta", |
| ]); |
| }); |
| }); |
|
|