From 8d682b74bd90727de6a4db09da4e4a9c98df8db2 Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Mon, 27 Jul 2026 21:17:16 -0500 Subject: [PATCH] test(messages): lock external alias authorization order --- ...sage-action-runner.plugin-dispatch.test.ts | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/infra/outbound/message-action-runner.plugin-dispatch.test.ts b/src/infra/outbound/message-action-runner.plugin-dispatch.test.ts index 40c8577d5397..0f75bdfdd08f 100644 --- a/src/infra/outbound/message-action-runner.plugin-dispatch.test.ts +++ b/src/infra/outbound/message-action-runner.plugin-dispatch.test.ts @@ -890,6 +890,70 @@ describe("runMessageAction plugin dispatch", () => { }, ); + it("rejects directory-only external aliases before resolver or plugin code", async () => { + const looksLikeId = vi.fn(() => false); + const resolveTarget = vi.fn(async () => ({ + to: "actionhub:current", + kind: "group" as const, + })); + const listGroups = vi.fn(async () => [ + { kind: "group" as const, id: "actionhub:current", name: "current-room" }, + ]); + const listGroupsLive = vi.fn(async () => [ + { kind: "group" as const, id: "actionhub:current", name: "current-room" }, + ]); + setActivePluginRegistry( + createTestRegistry([ + { + pluginId: "actionhub", + source: "test", + origin: "config", + plugin: { + ...actionHubPlugin, + messaging: { + ...actionHubPlugin.messaging, + targetResolver: { looksLikeId, resolveTarget }, + }, + directory: { listGroups, listGroupsLive }, + }, + }, + ]), + ); + + await expect( + runMessageAction({ + cfg: { + channels: { + actionhub: { + enabled: true, + }, + }, + } as OpenClawConfig, + action: "pin", + params: { + channel: "actionhub", + target: "current-room", + messageId: "om_123", + }, + defaultAccountId: "default", + requesterAccountId: "default", + conversationReadOrigin: "delegated", + toolContext: { + currentChannelId: "actionhub:current", + currentChannelProvider: "actionhub", + currentChatType: "group", + }, + dryRun: false, + }), + ).rejects.toThrow("requires the exact current conversation and account"); + + expect(looksLikeId).not.toHaveBeenCalled(); + expect(resolveTarget).not.toHaveBeenCalled(); + expect(listGroups).not.toHaveBeenCalled(); + expect(listGroupsLive).not.toHaveBeenCalled(); + expect(handleAction).not.toHaveBeenCalled(); + }); + it("preserves no-context owner Discord admin actions through the shared runner", async () => { const handleDiscordAction = vi.fn(async (ctx: ChannelMessageActionContext) => { const currentProvider = ctx.toolContext?.currentChannelProvider?.trim().toLowerCase();