diff --git a/extensions/discord/src/monitor/channel-access.ts b/extensions/discord/src/monitor/channel-access.ts index 0d1a2ba27ed..81569ef80be 100644 --- a/extensions/discord/src/monitor/channel-access.ts +++ b/extensions/discord/src/monitor/channel-access.ts @@ -1,8 +1,11 @@ function readDiscordChannelPropertySafe(channel: unknown, key: string): unknown { - if (!channel || typeof channel !== "object" || !(key in channel)) { + if (!channel || typeof channel !== "object") { return undefined; } try { + if (!(key in channel)) { + return undefined; + } return (channel as Record)[key]; } catch { return undefined; diff --git a/extensions/discord/src/monitor/native-command.commands-allowfrom.test.ts b/extensions/discord/src/monitor/native-command.commands-allowfrom.test.ts index c289ec66eda..7b1a6eae90f 100644 --- a/extensions/discord/src/monitor/native-command.commands-allowfrom.test.ts +++ b/extensions/discord/src/monitor/native-command.commands-allowfrom.test.ts @@ -215,6 +215,31 @@ describe("Discord native slash commands with commands.allowFrom", () => { expectNotUnauthorizedReply(interaction); }); + it("tolerates guild thread channels exposed through a Proxy whose has trap throws", async () => { + const { dispatchSpy, interaction } = await runGuildSlashCommand({ + mutateInteraction: (currentInteraction) => { + const baseChannel = { + type: ChannelType.PublicThread, + id: currentInteraction.channel.id, + }; + currentInteraction.channel = new Proxy(baseChannel, { + has(target, key) { + if (key === "parentId") { + throw new Error("has-trap denied"); + } + return key in target; + }, + get(target, key, receiver) { + return Reflect.get(target, key, receiver); + }, + }) as MockCommandInteraction["channel"]; + }, + }); + expect(interaction.defer).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expectNotUnauthorizedReply(interaction); + }); + it("authorizes guild slash commands from an allowlisted channel when commands.allowFrom is not configured", async () => { const { dispatchSpy, interaction } = await runGuildSlashCommand({ mutateConfig: (cfg) => {