Files
hermes-agent/tests/gateway/test_yuanbao_secret_scope.py
teknium1 8185834bc9 refactor(gateway): one OwnAccessPolicyMixin replaces five copied DM/group intake predicates
Weixin, WeCom, QQBot, WhatsApp (common + cloud) and Yuanbao's AccessPolicy each carried
their own `_open_dm_opted_in` / `_is_dm_allowed` / `_is_dm_intake_allowed` /
`_is_group_allowed`, differing only in the platform prefix of the allow-all env var and in
small drifts. The same "allow-all must be scoped / fail closed" fix has landed on this trio
at least four times; a shared rule means it lands once.

gateway/platforms/access_policy_mixin.py::OwnAccessPolicyMixin owns the predicates,
reads every env name through the scoped `get_scoped_secret` and exposes two hooks:
`_entry_matches` (platform allowlist matching) and `_live_dm_allow_from` (env-seeded
lists re-read live). `ALLOW_ALL_ENV_PREFIX` is the only per-adapter datum.

Retained overrides (behavior genuinely differs):
- whatsapp_cloud `_allow_all_env_names` adds WHATSAPP_CLOUD_ALLOW_ALL_USERS;
  `_is_dm_allowed` keeps its bare-wa_id normalisation.
- whatsapp_common `_entry_matches` -> phone/LID alias matching; `_live_dm_allow_from`.
- wecom `_is_group_allowed(chat_id, sender_id)` adds the per-group sender allowlist on
  top of the shared chat-level rule; `_entry_matches` strips `wecom:user:` prefixes.
- qqbot `_entry_matches` (case-insensitive, `*`).
- yuanbao `AccessPolicy.is_group_allowed`: `open` groups still require the allow-all
  opt-in (no runner-side mention gate), so it wraps the shared rule.

Behavior change: Weixin `_is_dm_intake_allowed` now denies a blank/whitespace principal
(the other four already did; safe variant chosen). Weixin's inline group gate now goes
through `_is_group_allowed` with identical verdicts.
2026-09-13 05:32:38 -07:00

73 lines
3.1 KiB
Python

"""Yuanbao authorization-scope regression tests (#93522).
``dm_policy``/``group_policy``/allowlist reads and the ``AccessPolicy``
allow-all opt-in must honor the active profile secret scope under
multiplexing: a secondary profile's own scope is authoritative and must
not inherit the default profile's process-env authorization config.
"""
import pytest
from agent import secret_scope
from gateway.config import PlatformConfig
from gateway.platforms.yuanbao import AccessPolicy, YuanbaoAdapter
@pytest.fixture()
def multiplex_on():
previous = secret_scope.is_multiplex_active()
secret_scope.set_multiplex_active(True)
try:
yield
finally:
secret_scope.set_multiplex_active(previous)
class TestYuanbaoAdapterAuthzScope:
def test_scoped_construction_reads_authz_from_scope_not_environ(self, multiplex_on, monkeypatch):
monkeypatch.setenv("YUANBAO_DM_POLICY", "pairing")
monkeypatch.setenv("YUANBAO_DM_ALLOW_FROM", "default-user")
token = secret_scope.set_secret_scope(
{"YUANBAO_DM_POLICY": "allowlist", "YUANBAO_DM_ALLOW_FROM": "scoped-user"}
)
try:
adapter = YuanbaoAdapter(PlatformConfig(enabled=True))
finally:
secret_scope.reset_secret_scope(token)
assert adapter._access_policy._dm_policy == "allowlist"
assert adapter._access_policy._allow_from == ["scoped-user"]
def test_scoped_miss_does_not_admit_default_profiles_allowlist(self, multiplex_on, monkeypatch):
monkeypatch.setenv("YUANBAO_DM_POLICY", "allowlist")
monkeypatch.setenv("YUANBAO_DM_ALLOW_FROM", "default-user")
token = secret_scope.set_secret_scope({"SOMETHING_ELSE": "x"})
try:
adapter = YuanbaoAdapter(PlatformConfig(enabled=True))
finally:
secret_scope.reset_secret_scope(token)
assert adapter._access_policy._dm_policy == "pairing"
assert adapter._access_policy._allow_from == []
class TestYuanbaoAccessPolicyOpenDmOptIn:
def test_scoped_allow_all_admits(self, multiplex_on, monkeypatch):
monkeypatch.delenv("GATEWAY_ALLOW_ALL_USERS", raising=False)
monkeypatch.delenv("YUANBAO_ALLOW_ALL_USERS", raising=False)
policy = AccessPolicy(dm_policy="open", dm_allow_from=[], group_policy="pairing", group_allow_from=[])
token = secret_scope.set_secret_scope({"YUANBAO_ALLOW_ALL_USERS": "true"})
try:
assert policy._open_dm_opted_in() is True
finally:
secret_scope.reset_secret_scope(token)
def test_default_profiles_allow_all_does_not_leak_into_scoped_miss(self, multiplex_on, monkeypatch):
"""The default profile's env-only GATEWAY_ALLOW_ALL_USERS must not
admit a secondary profile that never opted in."""
monkeypatch.setenv("GATEWAY_ALLOW_ALL_USERS", "true")
policy = AccessPolicy(dm_policy="open", dm_allow_from=[], group_policy="pairing", group_allow_from=[])
token = secret_scope.set_secret_scope({"SOMETHING_ELSE": "x"})
try:
assert policy._open_dm_opted_in() is False
finally:
secret_scope.reset_secret_scope(token)