From 3910edff0720d08242ac7f99a559d37c0dfc9b95 Mon Sep 17 00:00:00 2001 From: Sarah Fortune Date: Wed, 12 Aug 2026 20:18:52 -0700 Subject: [PATCH] fix(slack): normalize enterprise owner ids --- extensions/slack/src/monitor/allow-list.ts | 3 ++- extensions/slack/src/monitor/auth.test.ts | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/extensions/slack/src/monitor/allow-list.ts b/extensions/slack/src/monitor/allow-list.ts index 932c83d9754d..08cf09b2f2e4 100644 --- a/extensions/slack/src/monitor/allow-list.ts +++ b/extensions/slack/src/monitor/allow-list.ts @@ -13,6 +13,7 @@ import { import { parseSlackTarget } from "../target-parsing.js"; const SLACK_SLUG_CACHE_MAX = 512; +const SLACK_STABLE_USER_ID_RE = /^[ubw][a-z0-9]+$/; const slackSlugCache = new Map(); export function normalizeSlackSlug(raw?: string) { @@ -54,7 +55,7 @@ export function normalizeSlackAllowOwnerEntry(entry: string): string | undefined return undefined; } const withoutPrefix = trimmed.replace(/^(slack:|user:)/, ""); - return /^u[a-z0-9]+$/.test(withoutPrefix) ? withoutPrefix : undefined; + return SLACK_STABLE_USER_ID_RE.test(withoutPrefix) ? withoutPrefix : undefined; } export type SlackAllowListMatch = AllowlistMatch< diff --git a/extensions/slack/src/monitor/auth.test.ts b/extensions/slack/src/monitor/auth.test.ts index 58d86d89a258..a737711e361a 100644 --- a/extensions/slack/src/monitor/auth.test.ts +++ b/extensions/slack/src/monitor/auth.test.ts @@ -119,6 +119,7 @@ function interactiveRequest( function makeChannelMemberAuth( conversationsMembers = vi.fn(async () => ({ members: ["UOWNER"], response_metadata: {} })), + allowFromLower = ["uowner"], ) { const ctx = { allowFrom: [], @@ -132,7 +133,7 @@ function makeChannelMemberAuth( ctx, channelId: "C1", senderId: "U_BOT", - allowFromLower: ["uowner"], + allowFromLower, }); return { authorize, conversationsMembers }; } @@ -359,6 +360,24 @@ describe("authorizeSlackSystemEventSender", () => { ]); }); + it.each([ + ["an org-wide user ID", "w01234567", "W01234567"], + ["a prefixed org-wide user ID", "slack:w01234567", "W01234567"], + ["a bot ID", "b01234567", "B01234567"], + ["a prefixed bot ID", "user:b01234567", "B01234567"], + ])( + "authorizes bot room messages when %s identifies a present owner", + async (_name, entry, id) => { + const conversationsMembers = vi.fn(async () => ({ + members: [id], + response_metadata: {}, + })); + const { authorize } = makeChannelMemberAuth(conversationsMembers, [entry]); + + await expect(authorize()).resolves.toBe(true); + }, + ); + it.each([ ["a repeated cursor", ["cursor-a", "cursor-a"]], ["a cursor cycle", ["cursor-a", "cursor-b", "cursor-a"]],