





















@@ -3,7 +3,7 @@ import type { OpenClawConfig, PluginRuntime } from "../runtime-api.js";
33import "./monitor.send-mocks.js";
44import "./zalo-js.test-mocks.js";
55import { resolveZalouserAccountSync } from "./accounts.js";
6-import { __testing } from "./monitor.js";
6+import { __testing, monitorZalouserProvider } from "./monitor.js";
77import {
88sendDeliveredZalouserMock,
99sendMessageZalouserMock,
@@ -13,6 +13,11 @@ import {
1313import { setZalouserRuntime } from "./runtime.js";
1414import { createZalouserRuntimeEnv } from "./test-helpers.js";
1515import type { ResolvedZalouserAccount, ZaloInboundMessage } from "./types.js";
16+import {
17+listZaloFriendsMock,
18+listZaloGroupsMock,
19+startZaloListenerMock,
20+} from "./zalo-js.test-mocks.js";
16211722function createAccount(): ResolvedZalouserAccount {
1823return {
@@ -341,6 +346,12 @@ describe("zalouser monitor group mention gating", () => {
341346sendTypingZalouserMock.mockClear();
342347sendDeliveredZalouserMock.mockClear();
343348sendSeenZalouserMock.mockClear();
349+listZaloFriendsMock.mockReset();
350+listZaloFriendsMock.mockResolvedValue([]);
351+listZaloGroupsMock.mockReset();
352+listZaloGroupsMock.mockResolvedValue([]);
353+startZaloListenerMock.mockReset();
354+startZaloListenerMock.mockResolvedValue({ stop: vi.fn() });
344355});
345356346357async function processMessageWithDefaults(params: {
@@ -374,6 +385,23 @@ describe("zalouser monitor group mention gating", () => {
374385expect(sendTypingZalouserMock).not.toHaveBeenCalled();
375386}
376387388+async function startMonitorForStartupResolution(
389+accountConfig: ResolvedZalouserAccount["config"],
390+) {
391+installRuntime({ commandAuthorized: false });
392+const abortController = new AbortController();
393+abortController.abort();
394+await monitorZalouserProvider({
395+account: {
396+ ...createAccount(),
397+config: accountConfig,
398+},
399+config: createConfig(),
400+runtime: createRuntimeEnv(),
401+abortSignal: abortController.signal,
402+});
403+}
404+377405async function expectGroupCommandAuthorizers(params: {
378406accountConfig: ResolvedZalouserAccount["config"];
379407expectedAuthorizers: Array<{ configured: boolean; allowed: boolean }>;
@@ -669,6 +697,45 @@ describe("zalouser monitor group mention gating", () => {
669697expect(callArg?.ctx?.To).toBe("zalouser:group:g-attacker-001");
670698});
671699700+it("does not resolve mutable allowlist or group names at startup by default", async () => {
701+listZaloFriendsMock.mockResolvedValue([{ userId: "999", displayName: "Alice" }]);
702+listZaloGroupsMock.mockResolvedValue([{ groupId: "g-other", name: "Trusted Team" }]);
703+704+await startMonitorForStartupResolution({
705+ ...createAccount().config,
706+dmPolicy: "allowlist",
707+allowFrom: ["Alice"],
708+groupPolicy: "allowlist",
709+groupAllowFrom: ["Alice"],
710+groups: {
711+"Trusted Team": { enabled: true },
712+},
713+});
714+715+expect(listZaloFriendsMock).not.toHaveBeenCalled();
716+expect(listZaloGroupsMock).not.toHaveBeenCalled();
717+});
718+719+it("resolves mutable allowlist and group names at startup when enabled", async () => {
720+listZaloFriendsMock.mockResolvedValue([{ userId: "123", displayName: "Alice" }]);
721+listZaloGroupsMock.mockResolvedValue([{ groupId: "g-trusted", name: "Trusted Team" }]);
722+723+await startMonitorForStartupResolution({
724+ ...createAccount().config,
725+dangerouslyAllowNameMatching: true,
726+dmPolicy: "allowlist",
727+allowFrom: ["Alice"],
728+groupPolicy: "allowlist",
729+groupAllowFrom: ["Alice"],
730+groups: {
731+"Trusted Team": { enabled: true },
732+},
733+});
734+735+expect(listZaloFriendsMock).toHaveBeenCalledWith("default");
736+expect(listZaloGroupsMock).toHaveBeenCalledWith("default");
737+});
738+672739it("allows group control commands when sender is in groupAllowFrom", async () => {
673740await expectGroupCommandAuthorizers({
674741accountConfig: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。