fix(discord): explain fail-closed allowlist default

Log a one-shot structured warning when Discord denies traffic because
no allowlist/policy is configured, and correct the setup wizard's
inverted warning text. The fail-closed default itself is unchanged.

Fixes #58682.
This commit is contained in:
yungchentang 2026-07-07 16:42:47 -07:00 committed by Teknium
parent c3808cfc14
commit 3e7ade418d
2 changed files with 126 additions and 2 deletions

View file

@ -900,6 +900,7 @@ class DiscordAdapter(BasePlatformAdapter):
# rate limit (~1 edit per stream tick for the rest of a long reply).
# Mirrors the Telegram #58563 fix. Entries are dropped on finalize.
self._last_overflow_preview: Dict[tuple, str] = {}
self._warned_fail_closed_default = False
def _handle_bot_task_done(self, task: asyncio.Task) -> None:
"""Surface post-startup discord.py task exits to the gateway supervisor.
@ -1160,6 +1161,7 @@ class DiscordAdapter(BasePlatformAdapter):
is_dm=_is_dm,
channel_ids=_msg_channel_ids,
):
self._warn_if_fail_closed_default()
return
_role_authorized = bool(getattr(self, "_allowed_role_ids", set()))
@ -3355,6 +3357,28 @@ class DiscordAdapter(BasePlatformAdapter):
m_roles = getattr(m, "roles", None) or []
return any(getattr(r, "id", None) in allowed_roles for r in m_roles)
def _warn_if_fail_closed_default(self) -> None:
"""Log once when Discord is rejecting traffic with no allowlist set."""
if getattr(self, "_warned_fail_closed_default", False):
return
allowed_users = getattr(self, "_allowed_user_ids", set()) or set()
allowed_roles = getattr(self, "_allowed_role_ids", set()) or set()
if allowed_users or allowed_roles:
return
if os.getenv("DISCORD_ALLOWED_CHANNELS", "").strip():
return
if os.getenv("DISCORD_ALLOW_ALL_USERS", "").strip().lower() in {"true", "1", "yes"}:
return
if os.getenv("GATEWAY_ALLOW_ALL_USERS", "").strip().lower() in {"true", "1", "yes"}:
return
self._warned_fail_closed_default = True
logger.warning(
"[%s] Discord messages are being denied because no allowlist is configured. "
"Set DISCORD_ALLOWED_USERS, DISCORD_ALLOWED_ROLES, or "
"DISCORD_ALLOWED_CHANNELS, or set DISCORD_ALLOW_ALL_USERS=true for open access.",
self.name,
)
# ── Slash command authorization ─────────────────────────────────────
# Slash commands (``_run_simple_slash`` and ``_handle_thread_create_slash``)
# are a separate Discord interaction surface from regular messages and
@ -8121,7 +8145,11 @@ def interactive_setup() -> None:
print_info("Discord: already configured")
if not prompt_yes_no("Reconfigure Discord?", False):
if not get_env_value("DISCORD_ALLOWED_USERS"):
print_info("⚠️ Discord has no user allowlist - anyone can use your bot!")
print_info(
"⚠️ Discord has no user allowlist. With the fail-closed default, "
"messages are denied unless you configure allowed users, roles, "
"or channels, or set DISCORD_ALLOW_ALL_USERS=true."
)
if prompt_yes_no("Add allowed users now?", True):
print_info(" To find Discord ID: Enable Developer Mode, right-click name → Copy ID")
allowed_users = prompt("Allowed user IDs (comma-separated)")
@ -8154,7 +8182,11 @@ def interactive_setup() -> None:
save_env_value("DISCORD_ALLOWED_USERS", ",".join(cleaned_ids))
print_success("Discord allowlist configured")
else:
print_info("⚠️ No allowlist set - anyone in servers with your bot can use it!")
print_info(
"⚠️ No allowlist set. Discord will deny messages until you set "
"DISCORD_ALLOWED_USERS, DISCORD_ALLOWED_ROLES, DISCORD_ALLOWED_CHANNELS, "
"or DISCORD_ALLOW_ALL_USERS=true for open access."
)
print()
print_info("📬 Home Channel: where Hermes delivers cron job results,")