fix(discord): honor wildcard '*' in ignored_channels and free_response_channels

Follow-up to the allowed_channels wildcard fix in the preceding commit.
The same '*' literal trap affected two other Discord channel config lists:

- DISCORD_IGNORED_CHANNELS: '*' was stored as the literal string in the
  ignored set, and the intersection check never matched real channel IDs,
  so '*' was a no-op instead of silencing every channel.
- DISCORD_FREE_RESPONSE_CHANNELS: same shape — '*' never matched, so
  the bot still required a mention everywhere.

Add a '*' short-circuit to both checks, matching the allowed_channels
semantics. Extend tests/gateway/test_discord_allowed_channels.py with
regression coverage for all three lists.

Refs: #14920
This commit is contained in:
Teknium 2026-04-24 02:57:59 -07:00 committed by Teknium
parent 8598746e86
commit 8a1e247c6c
2 changed files with 74 additions and 9 deletions

View file

@ -1,10 +1,13 @@
"""Regression guard for #14920: DISCORD_ALLOWED_CHANNELS="*" should allow all channels.
"""Regression guard for #14920: wildcard "*" in Discord channel config lists.
Setting allowed_channels: "*" in config (or DISCORD_ALLOWED_CHANNELS="*" as env var)
must behave as a wildcard i.e. the bot responds in every channel. Previously the
literal string "*" was placed into the set and compared against numeric channel IDs via
set-intersection, which always produced an empty set, causing every message to be
silently dropped.
Setting ``allowed_channels: "*"``, ``free_response_channels: "*"``, or
``ignored_channels: "*"`` in config (or their ``DISCORD_*_CHANNELS`` env var
equivalents) must behave as a wildcard i.e. the bot responds in every
channel (or is silenced in every channel, for the ignored list). Previously
the literal string "*" was placed into a set and compared against numeric
channel IDs via set-intersection, which always produced an empty set and
caused every message to be silently dropped (for ``allowed_channels``) or
every ``free_response`` / ``ignored`` check to fail open.
"""
import unittest
@ -20,6 +23,22 @@ def _channel_is_allowed(channel_id: str, allowed_channels_raw: str) -> bool:
return bool({channel_id} & allowed_channels)
def _channel_is_ignored(channel_id: str, ignored_channels_raw: str) -> bool:
"""Replicate the ignored-channel check from discord.py on_message."""
ignored_channels = {
ch.strip() for ch in ignored_channels_raw.split(",") if ch.strip()
}
return "*" in ignored_channels or bool({channel_id} & ignored_channels)
def _channel_is_free_response(channel_id: str, free_channels_raw: str) -> bool:
"""Replicate the free-response-channel check from discord.py on_message."""
free_channels = {
ch.strip() for ch in free_channels_raw.split(",") if ch.strip()
}
return "*" in free_channels or bool({channel_id} & free_channels)
class TestDiscordAllowedChannelsWildcard(unittest.TestCase):
"""Wildcard and channel-list behaviour for DISCORD_ALLOWED_CHANNELS."""
@ -46,3 +65,40 @@ class TestDiscordAllowedChannelsWildcard(unittest.TestCase):
def test_whitespace_only_entry_ignored(self):
"""Entries that are only whitespace are stripped and ignored."""
self.assertFalse(_channel_is_allowed("1234567890", " , "))
class TestDiscordIgnoredChannelsWildcard(unittest.TestCase):
"""Wildcard and channel-list behaviour for DISCORD_IGNORED_CHANNELS."""
def test_wildcard_silences_every_channel(self):
"""'*' in ignored_channels silences the bot everywhere."""
self.assertTrue(_channel_is_ignored("1234567890", "*"))
def test_empty_ignored_list_silences_nothing(self):
self.assertFalse(_channel_is_ignored("1234567890", ""))
def test_exact_match_is_ignored(self):
self.assertTrue(_channel_is_ignored("111", "111,222"))
def test_non_match_not_ignored(self):
self.assertFalse(_channel_is_ignored("333", "111,222"))
class TestDiscordFreeResponseChannelsWildcard(unittest.TestCase):
"""Wildcard and channel-list behaviour for DISCORD_FREE_RESPONSE_CHANNELS."""
def test_wildcard_makes_every_channel_free_response(self):
"""'*' in free_response_channels exempts every channel from mention-required."""
self.assertTrue(_channel_is_free_response("1234567890", "*"))
def test_wildcard_in_list_applies_everywhere(self):
self.assertTrue(_channel_is_free_response("9999999999", "111,*,222"))
def test_exact_match_is_free_response(self):
self.assertTrue(_channel_is_free_response("111", "111,222"))
def test_non_match_not_free_response(self):
self.assertFalse(_channel_is_free_response("333", "111,222"))
def test_empty_list_no_free_response(self):
self.assertFalse(_channel_is_free_response("111", ""))