From 0cd5867bbba69140ee5d4cb9f7e992734e7edde4 Mon Sep 17 00:00:00 2001 From: Zyrixtrex Date: Tue, 2 Jun 2026 02:33:49 +0300 Subject: [PATCH] fix(whatsapp): honor dm_policy and group_policy open at the gateway --- gateway/platforms/base.py | 4 ++-- gateway/platforms/whatsapp.py | 5 +++++ gateway/run.py | 4 ++-- tests/gateway/test_config_driven_access_policy.py | 13 +++++++++---- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index e8a700876..543e6177a 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -1750,8 +1750,8 @@ class BasePlatformAdapter(ABC): def enforces_own_access_policy(self) -> bool: """Whether this adapter gates inbound access before dispatch. - Some adapters (WeCom, Weixin, Yuanbao, QQBot) implement a documented - config-driven access surface — ``dm_policy`` / ``group_policy`` / + Some adapters (WeCom, Weixin, Yuanbao, QQBot, WhatsApp) implement a + documented config-driven access surface — ``dm_policy`` / ``group_policy`` / ``allow_from`` / ``group_allow_from`` in ``PlatformConfig.extra`` — and enforce it at intake: a message is dropped inside the adapter and never reaches the gateway unless it already passed that policy. diff --git a/gateway/platforms/whatsapp.py b/gateway/platforms/whatsapp.py index 703f77432..7ece37dbc 100644 --- a/gateway/platforms/whatsapp.py +++ b/gateway/platforms/whatsapp.py @@ -379,6 +379,11 @@ class WhatsAppAdapter(BasePlatformAdapter): return True return False + @property + def enforces_own_access_policy(self) -> bool: + """WhatsApp gates DM/group access at intake via dm_policy/group_policy.""" + return True + def _is_dm_allowed(self, sender_id: str) -> bool: """Check whether a DM from the given sender should be processed.""" if self._dm_policy == "disabled": diff --git a/gateway/run.py b/gateway/run.py index 64eb8eb56..50462318a 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -6820,8 +6820,8 @@ class GatewayRunner: """Whether the adapter for *platform* gates access at intake itself. Mirrors ``BasePlatformAdapter.enforces_own_access_policy``. Adapters - such as WeCom, Weixin, Yuanbao, and QQBot evaluate their documented - ``dm_policy`` / ``group_policy`` / ``allow_from`` config before a + such as WeCom, Weixin, Yuanbao, QQBot, and WhatsApp evaluate their + documented ``dm_policy`` / ``group_policy`` / ``allow_from`` config before a message is dispatched to the gateway, so a message that reaches ``_is_user_authorized`` has already been authorized by the adapter. Defaults to ``False`` when the adapter is unknown or doesn't expose diff --git a/tests/gateway/test_config_driven_access_policy.py b/tests/gateway/test_config_driven_access_policy.py index 8659fb884..e5972aa65 100644 --- a/tests/gateway/test_config_driven_access_policy.py +++ b/tests/gateway/test_config_driven_access_policy.py @@ -1,8 +1,9 @@ """Tests for config-driven platform access policies at the gateway layer. -Background (#34515): WeCom, Weixin, Yuanbao, and QQBot expose a documented -config-driven access surface (``dm_policy`` / ``group_policy`` / ``allow_from`` -/ ``group_allow_from`` in ``PlatformConfig.extra``) and enforce it at intake — +Background (#34515): WeCom, Weixin, Yuanbao, QQBot, and WhatsApp expose a +documented config-driven access surface (``dm_policy`` / ``group_policy`` / +``allow_from`` / ``group_allow_from`` in ``PlatformConfig.extra``) and enforce +it at intake — a message is dropped inside the adapter and never reaches the gateway unless it already passed that policy. @@ -34,6 +35,7 @@ _OWN_POLICY_PLATFORMS = [ Platform.WEIXIN, Platform.YUANBAO, Platform.QQBOT, + Platform.WHATSAPP, ] @@ -44,6 +46,7 @@ def _clear_auth_env(monkeypatch) -> None: "YUANBAO_ALLOWED_USERS", "QQ_ALLOWED_USERS", "QQ_GROUP_ALLOWED_USERS", + "WHATSAPP_ALLOWED_USERS", "TELEGRAM_ALLOWED_USERS", "GATEWAY_ALLOWED_USERS", "GATEWAY_ALLOW_ALL_USERS", @@ -51,6 +54,7 @@ def _clear_auth_env(monkeypatch) -> None: "WEIXIN_ALLOW_ALL_USERS", "YUANBAO_ALLOW_ALL_USERS", "QQ_ALLOW_ALL_USERS", + "WHATSAPP_ALLOW_ALL_USERS", ): monkeypatch.delenv(key, raising=False) @@ -103,10 +107,11 @@ def test_base_adapter_defaults_to_not_owning_access_policy(): ("gateway.platforms.weixin", "WeixinAdapter"), ("gateway.platforms.yuanbao", "YuanbaoAdapter"), ("gateway.platforms.qqbot.adapter", "QQAdapter"), + ("gateway.platforms.whatsapp", "WhatsAppAdapter"), ], ) def test_own_policy_adapters_declare_the_flag(module_path, class_name): - """The four config-policy adapters override the flag to True.""" + """The config-policy adapters override the flag to True.""" import importlib module = importlib.import_module(module_path)