From 67bccc1fa02ec15d6989d12a9a6aad5d56c13028 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 23 Feb 2026 13:18:03 +0000 Subject: [PATCH] test: merge allow-from trigger shard and dedupe inline cases --- ...s-activation-from-allowfrom-groups.test.ts | 146 -------------- ...ne-commands-strips-it-before-agent.test.ts | 189 +++++++++++++----- 2 files changed, 140 insertions(+), 195 deletions(-) delete mode 100644 src/auto-reply/reply.triggers.trigger-handling.allows-activation-from-allowfrom-groups.test.ts diff --git a/src/auto-reply/reply.triggers.trigger-handling.allows-activation-from-allowfrom-groups.test.ts b/src/auto-reply/reply.triggers.trigger-handling.allows-activation-from-allowfrom-groups.test.ts deleted file mode 100644 index 1b4866aad34..00000000000 --- a/src/auto-reply/reply.triggers.trigger-handling.allows-activation-from-allowfrom-groups.test.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { describe, expect, it } from "vitest"; -import { - getRunEmbeddedPiAgentMock, - installTriggerHandlingReplyHarness, - makeCfg, - runGreetingPromptForBareNewOrReset, - withTempHome, -} from "./reply.triggers.trigger-handling.test-harness.js"; - -let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig; -installTriggerHandlingReplyHarness((loader) => { - getReplyFromConfig = loader; -}); - -async function expectResetBlockedForNonOwner(params: { - home: string; - commandAuthorized: boolean; - getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig; -}): Promise { - const { home, commandAuthorized, getReplyFromConfig } = params; - const cfg = makeCfg(home); - cfg.channels ??= {}; - cfg.channels.whatsapp = { - ...cfg.channels.whatsapp, - allowFrom: ["+1999"], - }; - cfg.session = { - ...cfg.session, - store: join(tmpdir(), `openclaw-session-test-${Date.now()}.json`), - }; - const res = await getReplyFromConfig( - { - Body: "/reset", - From: "+1003", - To: "+2000", - CommandAuthorized: commandAuthorized, - }, - {}, - cfg, - ); - expect(res).toBeUndefined(); - expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled(); -} - -describe("trigger handling", () => { - it("allows /activation from allowFrom in groups", async () => { - await withTempHome(async (home) => { - const cfg = makeCfg(home); - const res = await getReplyFromConfig( - { - Body: "/activation mention", - From: "123@g.us", - To: "+2000", - ChatType: "group", - Provider: "whatsapp", - SenderE164: "+999", - CommandAuthorized: true, - }, - {}, - cfg, - ); - const text = Array.isArray(res) ? res[0]?.text : res?.text; - expect(text).toBe("⚙️ Group activation set to mention."); - expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled(); - }); - }); - - it("injects group activation context into the system prompt", async () => { - await withTempHome(async (home) => { - getRunEmbeddedPiAgentMock().mockResolvedValue({ - payloads: [{ text: "ok" }], - meta: { - durationMs: 1, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); - const cfg = makeCfg(home); - cfg.channels ??= {}; - cfg.channels.whatsapp = { - ...cfg.channels.whatsapp, - allowFrom: ["*"], - groups: { "*": { requireMention: false } }, - }; - cfg.messages = { - ...cfg.messages, - groupChat: {}, - }; - - const res = await getReplyFromConfig( - { - Body: "hello group", - From: "123@g.us", - To: "+2000", - ChatType: "group", - Provider: "whatsapp", - SenderE164: "+2000", - GroupSubject: "Test Group", - GroupMembers: "Alice (+1), Bob (+2)", - }, - {}, - cfg, - ); - - const text = Array.isArray(res) ? res[0]?.text : res?.text; - expect(text).toBe("ok"); - expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce(); - const extra = getRunEmbeddedPiAgentMock().mock.calls[0]?.[0]?.extraSystemPrompt ?? ""; - expect(extra).toContain('"chat_type": "group"'); - expect(extra).toContain("Activation: always-on"); - }); - }); - - it("runs a greeting prompt for a bare /reset", async () => { - await withTempHome(async (home) => { - await runGreetingPromptForBareNewOrReset({ home, body: "/reset", getReplyFromConfig }); - }); - }); - - it("runs a greeting prompt for a bare /new", async () => { - await withTempHome(async (home) => { - await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig }); - }); - }); - - it("does not reset for unauthorized /reset", async () => { - await withTempHome(async (home) => { - await expectResetBlockedForNonOwner({ - home, - commandAuthorized: false, - getReplyFromConfig, - }); - }); - }); - - it("blocks /reset for non-owner senders", async () => { - await withTempHome(async (home) => { - await expectResetBlockedForNonOwner({ - home, - commandAuthorized: true, - getReplyFromConfig, - }); - }); - }); -}); diff --git a/src/auto-reply/reply.triggers.trigger-handling.handles-inline-commands-strips-it-before-agent.test.ts b/src/auto-reply/reply.triggers.trigger-handling.handles-inline-commands-strips-it-before-agent.test.ts index 08d80e03c58..3f92d80c11e 100644 --- a/src/auto-reply/reply.triggers.trigger-handling.handles-inline-commands-strips-it-before-agent.test.ts +++ b/src/auto-reply/reply.triggers.trigger-handling.handles-inline-commands-strips-it-before-agent.test.ts @@ -1,4 +1,6 @@ import fs from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { beforeAll, describe, expect, it } from "vitest"; import { expectInlineCommandHandledAndStripped, @@ -7,6 +9,9 @@ import { loadGetReplyFromConfig, MAIN_SESSION_KEY, makeCfg, + mockRunEmbeddedPiAgentOk, + requireSessionStorePath, + runGreetingPromptForBareNewOrReset, withTempHome, } from "./reply.triggers.trigger-handling.test-harness.js"; @@ -30,12 +35,33 @@ function makeUnauthorizedWhatsAppCfg(home: string) { }; } -function requireSessionStorePath(cfg: { session?: { store?: string } }): string { - const storePath = cfg.session?.store; - if (!storePath) { - throw new Error("expected session store path"); - } - return storePath; +async function expectResetBlockedForNonOwner(params: { + home: string; + commandAuthorized: boolean; +}): Promise { + const { home } = params; + const cfg = makeCfg(home); + cfg.channels ??= {}; + cfg.channels.whatsapp = { + ...cfg.channels.whatsapp, + allowFrom: ["+1999"], + }; + cfg.session = { + ...cfg.session, + store: join(tmpdir(), `openclaw-session-test-${Date.now()}.json`), + }; + const res = await getReplyFromConfig( + { + Body: "/reset", + From: "+1003", + To: "+2000", + CommandAuthorized: params.commandAuthorized, + }, + {}, + cfg, + ); + expect(res).toBeUndefined(); + expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled(); } async function expectUnauthorizedCommandDropped(home: string, body: "/status" | "/whoami") { @@ -59,15 +85,7 @@ async function expectUnauthorizedCommandDropped(home: string, body: "/status" | } function mockEmbeddedOk() { - const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock(); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "ok" }], - meta: { - durationMs: 1, - agentMeta: { sessionId: "s", provider: "p", model: "m" }, - }, - }); - return runEmbeddedPiAgentMock; + return mockRunEmbeddedPiAgentOk("ok"); } async function runInlineUnauthorizedCommand(params: { @@ -90,6 +108,96 @@ async function runInlineUnauthorizedCommand(params: { } describe("trigger handling", () => { + it("allows /activation from allowFrom in groups", async () => { + await withTempHome(async (home) => { + const cfg = makeCfg(home); + const res = await getReplyFromConfig( + { + Body: "/activation mention", + From: "123@g.us", + To: "+2000", + ChatType: "group", + Provider: "whatsapp", + SenderE164: "+999", + CommandAuthorized: true, + }, + {}, + cfg, + ); + const text = Array.isArray(res) ? res[0]?.text : res?.text; + expect(text).toBe("⚙️ Group activation set to mention."); + expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled(); + }); + }); + + it("injects group activation context into the system prompt", async () => { + await withTempHome(async (home) => { + getRunEmbeddedPiAgentMock().mockResolvedValue({ + payloads: [{ text: "ok" }], + meta: { + durationMs: 1, + agentMeta: { sessionId: "s", provider: "p", model: "m" }, + }, + }); + const cfg = makeCfg(home); + cfg.channels ??= {}; + cfg.channels.whatsapp = { + ...cfg.channels.whatsapp, + allowFrom: ["*"], + groups: { "*": { requireMention: false } }, + }; + cfg.messages = { + ...cfg.messages, + groupChat: {}, + }; + + const res = await getReplyFromConfig( + { + Body: "hello group", + From: "123@g.us", + To: "+2000", + ChatType: "group", + Provider: "whatsapp", + SenderE164: "+2000", + GroupSubject: "Test Group", + GroupMembers: "Alice (+1), Bob (+2)", + }, + {}, + cfg, + ); + + const text = Array.isArray(res) ? res[0]?.text : res?.text; + expect(text).toBe("ok"); + expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce(); + const extra = getRunEmbeddedPiAgentMock().mock.calls[0]?.[0]?.extraSystemPrompt ?? ""; + expect(extra).toContain('"chat_type": "group"'); + expect(extra).toContain("Activation: always-on"); + }); + }); + + it("runs a greeting prompt for a bare /reset", async () => { + await withTempHome(async (home) => { + await runGreetingPromptForBareNewOrReset({ home, body: "/reset", getReplyFromConfig }); + }); + }); + + it("runs a greeting prompt for a bare /new", async () => { + await withTempHome(async (home) => { + await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig }); + }); + }); + + it("blocks /reset for unauthorized sender scenarios", async () => { + await withTempHome(async (home) => { + for (const commandAuthorized of [false, true]) { + await expectResetBlockedForNonOwner({ + home, + commandAuthorized, + }); + } + }); + }); + it("handles inline /commands and strips it before the agent", async () => { await withTempHome(async (home) => { await expectInlineCommandHandledAndStripped({ @@ -129,45 +237,28 @@ describe("trigger handling", () => { }); }); - it("drops /status for unauthorized senders", async () => { + it("drops top-level restricted commands for unauthorized senders", async () => { await withTempHome(async (home) => { - await expectUnauthorizedCommandDropped(home, "/status"); + for (const command of ["/status", "/whoami"] as const) { + await expectUnauthorizedCommandDropped(home, command); + } }); }); - it("drops /whoami for unauthorized senders", async () => { + it("keeps inline commands for unauthorized senders", async () => { await withTempHome(async (home) => { - await expectUnauthorizedCommandDropped(home, "/whoami"); - }); - }); - - it("keeps inline /status for unauthorized senders", async () => { - await withTempHome(async (home) => { - const runEmbeddedPiAgentMock = mockEmbeddedOk(); - const res = await runInlineUnauthorizedCommand({ - home, - command: "/status", - }); - const text = Array.isArray(res) ? res[0]?.text : res?.text; - expect(text).toBe("ok"); - expect(runEmbeddedPiAgentMock).toHaveBeenCalled(); - const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? ""; - expect(prompt).toContain("/status"); - }); - }); - - it("keeps inline /help for unauthorized senders", async () => { - await withTempHome(async (home) => { - const runEmbeddedPiAgentMock = mockEmbeddedOk(); - const res = await runInlineUnauthorizedCommand({ - home, - command: "/help", - }); - const text = Array.isArray(res) ? res[0]?.text : res?.text; - expect(text).toBe("ok"); - expect(runEmbeddedPiAgentMock).toHaveBeenCalled(); - const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? ""; - expect(prompt).toContain("/help"); + for (const command of ["/status", "/help"] as const) { + const runEmbeddedPiAgentMock = mockEmbeddedOk(); + const res = await runInlineUnauthorizedCommand({ + home, + command, + }); + const text = Array.isArray(res) ? res[0]?.text : res?.text; + expect(text).toBe("ok"); + expect(runEmbeddedPiAgentMock).toHaveBeenCalled(); + const prompt = runEmbeddedPiAgentMock.mock.calls.at(-1)?.[0]?.prompt ?? ""; + expect(prompt).toContain(command); + } }); });