mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
fix(slack): scope assistant self-event bypass
This commit is contained in:
@@ -16,6 +16,14 @@ type SlackSocketShutdownClient = {
|
||||
shuttingDown?: boolean;
|
||||
};
|
||||
type Constructor = abstract new (...args: never[]) => unknown;
|
||||
type SlackSelfFilterArgs = {
|
||||
context?: {
|
||||
botId?: string;
|
||||
botUserId?: string;
|
||||
};
|
||||
event?: unknown;
|
||||
message?: unknown;
|
||||
};
|
||||
|
||||
function isConstructorFunction<
|
||||
// oxlint-disable-next-line typescript/no-unnecessary-type-parameters -- Constructor guard preserves the requested concrete Slack constructor type.
|
||||
@@ -118,6 +126,39 @@ export function publishSlackDisconnectedStatus(
|
||||
});
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function shouldSkipOpenClawSlackSelfEvent(args: SlackSelfFilterArgs): boolean {
|
||||
const botId = args.context?.botId;
|
||||
const botUserId = args.context?.botUserId;
|
||||
const message = asRecord(args.message);
|
||||
if (message?.subtype === "bot_message" && botId && message.bot_id === botId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const event = asRecord(args.event);
|
||||
if (
|
||||
event?.type === "message" &&
|
||||
event.subtype === "message_changed" &&
|
||||
event.user === botUserId
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const eventsWhichShouldBeKept = new Set(["member_joined_channel", "member_left_channel"]);
|
||||
return Boolean(
|
||||
botUserId &&
|
||||
event &&
|
||||
event.user === botUserId &&
|
||||
typeof event.type === "string" &&
|
||||
!eventsWhichShouldBeKept.has(event.type),
|
||||
);
|
||||
}
|
||||
|
||||
export function createSlackBoltApp(params: {
|
||||
interop: SlackBoltResolvedExports;
|
||||
slackMode: "socket" | "http";
|
||||
@@ -146,6 +187,12 @@ export function createSlackBoltApp(params: {
|
||||
clientOptions: params.clientOptions,
|
||||
ignoreSelf: false,
|
||||
});
|
||||
app.use(async (args) => {
|
||||
if (shouldSkipOpenClawSlackSelfEvent(args)) {
|
||||
return;
|
||||
}
|
||||
await args.next();
|
||||
});
|
||||
return { app, receiver };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createSlackBoltApp, resolveSlackBoltInterop } from "./provider-support.js";
|
||||
import {
|
||||
createSlackBoltApp,
|
||||
resolveSlackBoltInterop,
|
||||
shouldSkipOpenClawSlackSelfEvent,
|
||||
} from "./provider-support.js";
|
||||
|
||||
describe("resolveSlackBoltInterop", () => {
|
||||
function FakeApp() {}
|
||||
@@ -107,10 +111,16 @@ describe("resolveSlackBoltInterop", () => {
|
||||
describe("createSlackBoltApp", () => {
|
||||
class FakeApp {
|
||||
args: Record<string, unknown>;
|
||||
middleware: unknown[] = [];
|
||||
|
||||
constructor(args: Record<string, unknown>) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
use(middleware: unknown) {
|
||||
this.middleware.push(middleware);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeHTTPReceiver {
|
||||
@@ -159,6 +169,7 @@ describe("createSlackBoltApp", () => {
|
||||
clientOptions,
|
||||
ignoreSelf: false,
|
||||
});
|
||||
expect((app as unknown as FakeApp).middleware).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("uses HTTPReceiver for webhook mode", () => {
|
||||
@@ -188,5 +199,37 @@ describe("createSlackBoltApp", () => {
|
||||
clientOptions,
|
||||
ignoreSelf: false,
|
||||
});
|
||||
expect((app as unknown as FakeApp).middleware).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("keeps Bolt self filtering except assistant message_changed events", () => {
|
||||
expect(
|
||||
shouldSkipOpenClawSlackSelfEvent({
|
||||
context: { botUserId: "U_BOT", botId: "B_BOT" },
|
||||
event: { type: "reaction_added", user: "U_BOT" },
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
shouldSkipOpenClawSlackSelfEvent({
|
||||
context: { botUserId: "U_BOT", botId: "B_BOT" },
|
||||
event: { type: "message", subtype: "message_changed", user: "U_BOT" },
|
||||
}),
|
||||
).toBe(false);
|
||||
|
||||
expect(
|
||||
shouldSkipOpenClawSlackSelfEvent({
|
||||
context: { botUserId: "U_BOT", botId: "B_BOT" },
|
||||
event: { type: "message", user: "U_BOT" },
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
expect(
|
||||
shouldSkipOpenClawSlackSelfEvent({
|
||||
context: { botUserId: "U_BOT", botId: "B_BOT" },
|
||||
event: { type: "message", user: "U_OTHER" },
|
||||
message: { subtype: "bot_message", bot_id: "B_BOT" },
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user