


























@@ -1,5 +1,105 @@
11import { describe, expect, it, vi } from "vitest";
2-import { handleSignalDirectMessageAccess } from "./access-policy.js";
2+import { handleSignalDirectMessageAccess, resolveSignalAccessState } from "./access-policy.js";
3+4+vi.mock("openclaw/plugin-sdk/security-runtime", async (importOriginal) => ({
5+ ...(await importOriginal<typeof import("openclaw/plugin-sdk/security-runtime")>()),
6+readStoreAllowFromForDmPolicy: vi.fn(async () => []),
7+}));
8+9+const SIGNAL_GROUP_ID = "signal-group-id";
10+const OTHER_SIGNAL_GROUP_ID = "other-signal-group-id";
11+const SIGNAL_SENDER = {
12+kind: "phone" as const,
13+e164: "+15551230000",
14+raw: "+15551230000",
15+};
16+17+async function resolveGroupAccess(params: {
18+allowFrom?: string[];
19+groupAllowFrom?: string[];
20+groupId?: string;
21+}) {
22+const access = await resolveSignalAccessState({
23+accountId: "default",
24+dmPolicy: "allowlist",
25+groupPolicy: "allowlist",
26+allowFrom: params.allowFrom ?? [],
27+groupAllowFrom: params.groupAllowFrom ?? [],
28+sender: SIGNAL_SENDER,
29+groupId: params.groupId,
30+});
31+return {
32+ ...access,
33+groupDecision: access.resolveAccessDecision(true),
34+};
35+}
36+37+describe("resolveSignalAccessState", () => {
38+it("allows group messages when groupAllowFrom contains the inbound Signal group id", async () => {
39+const { groupDecision } = await resolveGroupAccess({
40+groupAllowFrom: [SIGNAL_GROUP_ID],
41+groupId: SIGNAL_GROUP_ID,
42+});
43+44+expect(groupDecision.decision).toBe("allow");
45+});
46+47+it("allows Signal group target forms in groupAllowFrom", async () => {
48+const groupTargetDecision = await resolveGroupAccess({
49+groupAllowFrom: [`group:${SIGNAL_GROUP_ID}`],
50+groupId: SIGNAL_GROUP_ID,
51+});
52+const signalGroupTargetDecision = await resolveGroupAccess({
53+groupAllowFrom: [`signal:group:${SIGNAL_GROUP_ID}`],
54+groupId: SIGNAL_GROUP_ID,
55+});
56+57+expect(groupTargetDecision.groupDecision.decision).toBe("allow");
58+expect(signalGroupTargetDecision.groupDecision.decision).toBe("allow");
59+});
60+61+it("blocks group messages when groupAllowFrom contains a different Signal group id", async () => {
62+const { groupDecision } = await resolveGroupAccess({
63+groupAllowFrom: [OTHER_SIGNAL_GROUP_ID],
64+groupId: SIGNAL_GROUP_ID,
65+});
66+67+expect(groupDecision.decision).toBe("block");
68+});
69+70+it("keeps sender allowlist compatibility for Signal group messages", async () => {
71+const { groupDecision } = await resolveGroupAccess({
72+groupAllowFrom: [SIGNAL_SENDER.e164],
73+groupId: SIGNAL_GROUP_ID,
74+});
75+76+expect(groupDecision.decision).toBe("allow");
77+});
78+79+it("does not match group ids against direct-message allowFrom entries", async () => {
80+const { dmAccess } = await resolveSignalAccessState({
81+accountId: "default",
82+dmPolicy: "allowlist",
83+groupPolicy: "allowlist",
84+allowFrom: [SIGNAL_GROUP_ID],
85+groupAllowFrom: [],
86+sender: SIGNAL_SENDER,
87+groupId: SIGNAL_GROUP_ID,
88+});
89+90+expect(dmAccess.decision).toBe("block");
91+});
92+93+it("does not let group ids in allowFrom satisfy an explicit groupAllowFrom mismatch", async () => {
94+const { groupDecision } = await resolveGroupAccess({
95+allowFrom: [SIGNAL_GROUP_ID],
96+groupAllowFrom: [OTHER_SIGNAL_GROUP_ID],
97+groupId: SIGNAL_GROUP_ID,
98+});
99+100+expect(groupDecision.decision).toBe("block");
101+});
102+});
31034104describe("handleSignalDirectMessageAccess", () => {
5105it("returns true for already-allowed direct messages", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。