diff --git a/src/slack/monitor/context.test.ts b/src/slack/monitor/context.test.ts index c52c5e919..d63b1c71a 100644 --- a/src/slack/monitor/context.test.ts +++ b/src/slack/monitor/context.test.ts @@ -60,3 +60,61 @@ describe("resolveSlackSystemEventSessionKey", () => { ); }); }); + +describe("isChannelAllowed with groupPolicy and channelsConfig", () => { + it("allows unlisted channels when groupPolicy is open even with channelsConfig entries", () => { + // Bug fix: when groupPolicy="open" and channels has some entries, + // unlisted channels should still be allowed (not blocked) + const ctx = createSlackMonitorContext({ + ...baseParams(), + groupPolicy: "open", + channelsConfig: { + C_LISTED: { requireMention: true }, + }, + }); + // Listed channel should be allowed + expect(ctx.isChannelAllowed({ channelId: "C_LISTED", channelType: "channel" })).toBe(true); + // Unlisted channel should ALSO be allowed when policy is "open" + expect(ctx.isChannelAllowed({ channelId: "C_UNLISTED", channelType: "channel" })).toBe(true); + }); + + it("blocks unlisted channels when groupPolicy is allowlist", () => { + const ctx = createSlackMonitorContext({ + ...baseParams(), + groupPolicy: "allowlist", + channelsConfig: { + C_LISTED: { requireMention: true }, + }, + }); + // Listed channel should be allowed + expect(ctx.isChannelAllowed({ channelId: "C_LISTED", channelType: "channel" })).toBe(true); + // Unlisted channel should be blocked when policy is "allowlist" + expect(ctx.isChannelAllowed({ channelId: "C_UNLISTED", channelType: "channel" })).toBe(false); + }); + + it("blocks explicitly denied channels even when groupPolicy is open", () => { + const ctx = createSlackMonitorContext({ + ...baseParams(), + groupPolicy: "open", + channelsConfig: { + C_ALLOWED: { allow: true }, + C_DENIED: { allow: false }, + }, + }); + // Explicitly allowed channel + expect(ctx.isChannelAllowed({ channelId: "C_ALLOWED", channelType: "channel" })).toBe(true); + // Explicitly denied channel should be blocked even with open policy + expect(ctx.isChannelAllowed({ channelId: "C_DENIED", channelType: "channel" })).toBe(false); + // Unlisted channel should be allowed with open policy + expect(ctx.isChannelAllowed({ channelId: "C_UNLISTED", channelType: "channel" })).toBe(true); + }); + + it("allows all channels when groupPolicy is open and channelsConfig is empty", () => { + const ctx = createSlackMonitorContext({ + ...baseParams(), + groupPolicy: "open", + channelsConfig: undefined, + }); + expect(ctx.isChannelAllowed({ channelId: "C_ANY", channelType: "channel" })).toBe(true); + }); +}); diff --git a/src/slack/monitor/context.ts b/src/slack/monitor/context.ts index bd2425103..83acfbae6 100644 --- a/src/slack/monitor/context.ts +++ b/src/slack/monitor/context.ts @@ -327,7 +327,11 @@ export function createSlackMonitorContext(params: { ); return false; } - if (!channelAllowed) { + // When groupPolicy is "open", only block channels that are EXPLICITLY denied + // (i.e., have a matching config entry with allow:false). Channels not in the + // config (matchSource undefined) should be allowed under open policy. + const hasExplicitConfig = Boolean(channelConfig?.matchSource); + if (!channelAllowed && (params.groupPolicy !== "open" || hasExplicitConfig)) { logVerbose(`slack: drop channel ${p.channelId} (${channelMatchMeta})`); return false; }