Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions gateway/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -6802,10 +6802,11 @@ def _get_unauthorized_dm_behavior(self, platform: Optional[Platform]) -> str:
2. Explicit global ``unauthorized_dm_behavior`` in config — wins when no per-platform.
3. When an allowlist (``PLATFORM_ALLOWED_USERS``,
``PLATFORM_GROUP_ALLOWED_USERS`` / ``PLATFORM_GROUP_ALLOWED_CHATS``,
or ``GATEWAY_ALLOWED_USERS``) is configured, default to ``"ignore"`` —
the allowlist signals that the owner has deliberately restricted
access; spamming unknown contacts with pairing codes is both noisy
and a potential info-leak. (#9337)
or ``GATEWAY_ALLOWED_USERS``) or a config-driven own-policy
gateway restriction is configured, default to ``"ignore"`` — the
operator has deliberately restricted access, so spamming unknown
contacts with pairing codes is both noisy and a potential
info-leak. (#9337)
4. No allowlist and no explicit config → ``"pair"`` (open-gateway default).
"""
config = getattr(self, "config", None)
Expand All @@ -6822,10 +6823,11 @@ def _get_unauthorized_dm_behavior(self, platform: Optional[Platform]) -> str:
if config.unauthorized_dm_behavior != "pair": # non-default → explicit override
return config.unauthorized_dm_behavior

# Config-driven dm_policy (WeCom / Weixin / Yuanbao / QQBot). An
# allowlist or disabled DM policy means the operator restricted access,
# so unauthorized DMs should be dropped silently rather than answered
# with a pairing code. An explicit pairing policy opts back into codes.
# Config-driven own-policy access control (WeCom / Weixin / Yuanbao /
# QQBot). Restrictive DM or group policies mean the operator narrowed
# access, so unauthorized DMs should be dropped silently rather than
# answered with a pairing code. An explicit pairing policy still opts
# back into codes.
if platform and config and hasattr(config, "platforms"):
platform_cfg = config.platforms.get(platform)
extra = getattr(platform_cfg, "extra", None) if platform_cfg else None
Expand All @@ -6835,6 +6837,10 @@ def _get_unauthorized_dm_behavior(self, platform: Optional[Platform]) -> str:
return "pair"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current main moved this resolver to gateway/authz_mixin.py and made it profile-aware. When salvaging, use _adapter_group_policy(platform, profile=profile) behind _adapter_enforces_own_access_policy(..., profile=profile) rather than reading only config.extra, so multiplexed and environment-resolved adapter policies are honored.

if dm_policy in {"allowlist", "disabled"}:
return "ignore"
if self._adapter_enforces_own_access_policy(platform):
group_policy = str(extra.get("group_policy") or "").strip().lower()
if group_policy in {"allowlist", "disabled"}:
return "ignore"

# No explicit override. Fall back to allowlist-aware default:
# if any allowlist is configured for this platform, silently drop
Expand Down
37 changes: 36 additions & 1 deletion tests/gateway/test_config_driven_access_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def test_unknown_adapter_does_not_crash_trust_check(monkeypatch):


# ---------------------------------------------------------------------------
# Layer 3: unauthorized-DM behavior reads config dm_policy
# Layer 3: unauthorized-DM behavior reads config dm/group policy
# ---------------------------------------------------------------------------


Expand All @@ -222,6 +222,41 @@ def test_unauthorized_dm_behavior_follows_config_dm_policy(monkeypatch, dm_polic
assert runner._get_unauthorized_dm_behavior(Platform.WECOM) == expected


@pytest.mark.parametrize("platform", _OWN_POLICY_PLATFORMS)
@pytest.mark.parametrize("group_policy", ["allowlist", "disabled"])
def test_unauthorized_dm_behavior_follows_config_group_policy(monkeypatch, platform, group_policy):
"""Restrictive own-policy group configs should silence stranger DMs too."""
_clear_auth_env(monkeypatch)
config = GatewayConfig(
platforms={
platform: PlatformConfig(enabled=True, extra={"group_policy": group_policy})
}
)
runner, _adapter = _make_runner(platform, config, enforces=True)

assert runner._get_unauthorized_dm_behavior(platform) == "ignore"


@pytest.mark.parametrize("platform", _OWN_POLICY_PLATFORMS)
def test_explicit_pair_override_beats_group_policy_default(monkeypatch, platform):
"""Per-platform pairing overrides the restrictive group-policy default."""
_clear_auth_env(monkeypatch)
config = GatewayConfig(
platforms={
platform: PlatformConfig(
enabled=True,
extra={
"group_policy": "allowlist",
"unauthorized_dm_behavior": "pair",
},
)
}
)
runner, _adapter = _make_runner(platform, config, enforces=True)

assert runner._get_unauthorized_dm_behavior(platform) == "pair"


def test_unauthorized_dm_behavior_open_policy_keeps_default(monkeypatch):
"""``dm_policy: open`` is not restrictive → falls through to the default."""
_clear_auth_env(monkeypatch)
Expand Down
Loading