fix(gateway): honor empty WhatsApp allow_from over env grants

Select allowlist source by config key presence so allow_from: [] does not fall through to WHATSAPP_* env carriers on Baileys or Cloud.
This commit is contained in:
fangliquanflq 2026-08-02 04:16:10 +00:00 committed by kshitij
parent b35f219aed
commit f5ca0e2f0b
5 changed files with 60 additions and 12 deletions

View File

@ -1 +1 @@
fangliquanflq
fangliquanflq

View File

@ -255,13 +255,16 @@ class WhatsAppCloudAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter):
self._reply_prefix: Optional[str] = extra.get("reply_prefix")
# Allowlist: honor the *documented* WHATSAPP_CLOUD_ALLOWED_USERS (the
# var the setup wizard writes) in addition to WHATSAPP_CLOUD_ALLOW_FROM.
# Precedence matches construction forever: explicit config, then legacy
# ALLOW_FROM, then ALLOWED_USERS. Track the winning source so live DM
# checks do not let a lower-precedence env broaden access.
explicit_allow = extra.get("allow_from") or extra.get("allowFrom")
if explicit_allow:
# Precedence matches construction forever: explicit config (by key
# presence, including empty []), then legacy ALLOW_FROM, then
# ALLOWED_USERS. Track the winning source so live DM checks do not let
# a lower-precedence env broaden access.
if "allow_from" in extra:
self._dm_allowlist_source = "config"
allow_raw = explicit_allow
allow_raw = extra.get("allow_from")
elif "allowFrom" in extra:
self._dm_allowlist_source = "config"
allow_raw = extra.get("allowFrom")
elif os.getenv("WHATSAPP_CLOUD_ALLOW_FROM"):
self._dm_allowlist_source = "WHATSAPP_CLOUD_ALLOW_FROM"
allow_raw = os.getenv("WHATSAPP_CLOUD_ALLOW_FROM")

View File

@ -409,12 +409,16 @@ class WhatsAppAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter):
self._reply_prefix: Optional[str] = config.extra.get("reply_prefix")
self._dm_policy = str(config.extra.get("dm_policy") or os.getenv("WHATSAPP_DM_POLICY", "pairing")).strip().lower()
# Prefer config.extra, then the documented WHATSAPP_ALLOWED_USERS env
# (setup wizard / pairing mirror). Track which source won so live DM
# checks preserve that precedence (env must not override explicit config).
explicit_allow = config.extra.get("allow_from") or config.extra.get("allowFrom")
if explicit_allow:
# (setup wizard / pairing mirror). Select by key *presence* so an
# explicit empty allow_from: [] stays authoritative and does not fall
# through to a lower-precedence env grant. Track which source won so
# live DM checks preserve that precedence.
if "allow_from" in config.extra:
self._dm_allowlist_source = "config"
allow_raw = explicit_allow
allow_raw = config.extra.get("allow_from")
elif "allowFrom" in config.extra:
self._dm_allowlist_source = "config"
allow_raw = config.extra.get("allowFrom")
elif os.getenv("WHATSAPP_ALLOWED_USERS"):
self._dm_allowlist_source = "WHATSAPP_ALLOWED_USERS"
allow_raw = os.getenv("WHATSAPP_ALLOWED_USERS")

View File

@ -337,6 +337,28 @@ def test_whatsapp_live_allowlist_keeps_explicit_config_over_env(monkeypatch):
assert adapter._is_dm_intake_allowed("15550000003") is False
def test_whatsapp_explicit_empty_allow_from_blocks_env_grant(monkeypatch):
"""allow_from: [] is present config — must not fall through to env grants."""
from gateway.config import PlatformConfig
from plugins.platforms.whatsapp.adapter import WhatsAppAdapter
monkeypatch.setenv("WHATSAPP_ALLOWED_USERS", "15550000002")
adapter = WhatsAppAdapter(
PlatformConfig(
enabled=True,
extra={
"dm_policy": "allowlist",
"allow_from": [],
},
)
)
assert adapter._dm_allowlist_source == "config"
assert adapter._allow_from == set()
assert adapter._is_dm_intake_allowed("15550000002") is False
assert adapter._is_dm_allowed("15550000002") is False
def test_whatsapp_live_allowlist_rereads_env_when_env_seeded(monkeypatch):
"""Env-seeded adapters still pick up pairing allowlist mutations live."""
from gateway.config import PlatformConfig

View File

@ -103,6 +103,25 @@ def test_explicit_config_beats_cloud_env_on_live_checks(monkeypatch):
assert adapter._is_dm_allowed("15550000004") is False
def test_explicit_empty_allow_from_blocks_cloud_env_grants(monkeypatch):
"""allow_from: [] is present config — conflicting cloud env must not authorize."""
adapter = _build_adapter(
monkeypatch,
{
"WHATSAPP_CLOUD_ALLOW_FROM": "15550000002",
"WHATSAPP_CLOUD_ALLOWED_USERS": "15550000003",
},
extra={"dm_policy": "allowlist", "allow_from": []},
)
assert adapter._dm_allowlist_source == "config"
assert adapter._allow_from == set()
assert adapter._is_dm_allowed("15550000002") is False
assert adapter._is_dm_allowed("15550000003") is False
assert adapter._is_dm_intake_allowed("15550000002") is False
assert adapter._is_dm_intake_allowed("15550000003") is False
def test_cloud_allowed_users_live_reread_when_env_seeded(monkeypatch):
adapter = _build_adapter(
monkeypatch,