File size: 3,508 Bytes
fc93158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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",
    ]);
  });
});