from __future__ import annotations import pytest from yuxi.channels.adapters.wechat.security import ( check_dm_policy, check_group_policy, is_bot_mentioned, should_require_mention, ) from yuxi.channels.adapters.wechat.security import WeChatSecurityAdapter class TestCheckDmPolicy: def test_open_policy_allows(self): assert check_dm_policy({"dm_policy": "open"}, "user123") is True def test_disabled_policy_denies(self): assert check_dm_policy({"dm_policy": "disabled"}, "user123") is False def test_allowlist_user_in_list(self): config = {"dm_policy": "allowlist", "allow_from": ["wx:user123"]} assert check_dm_policy(config, "user123") is True def test_allowlist_user_not_in_list(self): config = {"dm_policy": "allowlist", "allow_from": ["wx:other"]} assert check_dm_policy(config, "other_user") is False def test_allowlist_empty(self): config = {"dm_policy": "allowlist", "allow_from": []} assert check_dm_policy(config, "anyone") is False def test_unknown_policy_denies(self): assert check_dm_policy({"dm_policy": "unknown_policy"}, "user") is False def test_no_policy_defaults_to_open(self): assert check_dm_policy({}, "user") is True class TestCheckGroupPolicy: def test_open_policy(self): config = {"group_policy": "open"} assert check_group_policy(config, "chat1", "user1") is True def test_disabled_policy(self): config = {"group_policy": "disabled"} assert check_group_policy(config, "chat1", "user1") is False def test_global_allowlist_match(self): config = {"group_policy": "allowlist", "group_allow_from": ["wx:user1"]} assert check_group_policy(config, "chat1", "user1") is True def test_global_allowlist_no_match(self): config = {"group_policy": "allowlist", "group_allow_from": ["wx:other"]} assert check_group_policy(config, "chat1", "user1") is False def test_per_group_allowlist_match(self): config = { "group_policy": "allowlist", "groups": {"chat1": {"allow_from": ["wx:user1"]}}, } assert check_group_policy(config, "chat1", "user1") is True def test_per_group_allowlist_no_match(self): config = { "group_policy": "allowlist", "groups": {"chat1": {"allow_from": ["wx:other"]}}, } assert check_group_policy(config, "chat1", "user1") is False def test_no_policy(self): assert check_group_policy({}, "chat1", "user1") is False class TestIsBotMentioned: def test_wecom_with_at_and_name(self): config = {"agent_name": "小助手"} payload = {"Content": "@小助手 你好"} assert is_bot_mentioned(config, payload, "wecom") is True def test_wecom_at_only_no_name(self): config = {"agent_name": "小助手"} payload = {"Content": "@someone 你好"} assert is_bot_mentioned(config, payload, "wecom") is True def test_wecom_no_at(self): config = {"agent_name": "小助手"} payload = {"Content": "你好"} assert is_bot_mentioned(config, payload, "wecom") is False def test_wecom_empty_content(self): config = {"agent_name": "小助手"} payload = {"Content": ""} assert is_bot_mentioned(config, payload, "wecom") is False def test_mp_with_at(self): config = {} payload = {"Content": "@bot help"} assert is_bot_mentioned(config, payload, "mp") is True def test_mp_without_at(self): config = {} payload = {"Content": "help"} assert is_bot_mentioned(config, payload, "mp") is False def test_personal_with_at_list(self): config = {} payload = {"at_list": ["user1"]} assert is_bot_mentioned(config, payload, "personal") is True def test_personal_empty_at_list(self): config = {} payload = {"at_list": []} assert is_bot_mentioned(config, payload, "personal") is False def test_unknown_mode(self): assert is_bot_mentioned({}, {}, "unknown") is False class TestShouldRequireMention: def test_group_requires_mention_default(self): config = {"groups": {"chat1": {}}} assert should_require_mention(config, "chat1") is True def test_group_requires_mention_explicit_true(self): config = {"groups": {"chat1": {"require_mention": True}}} assert should_require_mention(config, "chat1") is True def test_group_requires_mention_explicit_false(self): config = {"groups": {"chat1": {"require_mention": False}}} assert should_require_mention(config, "chat1") is False def test_group_not_configured(self): assert should_require_mention({}, "nonexistent") is True class TestWeChatSecurityAdapter: def test_resolve_dm_policy_default(self): result = WeChatSecurityAdapter.resolve_dm_policy({}) assert result == "pairing" def test_resolve_dm_policy_from_root(self): result = WeChatSecurityAdapter.resolve_dm_policy({"dm_policy": "allowlist"}) assert result == "allowlist" def test_resolve_dm_policy_from_account(self): config = {"accounts": {"acc1": {"dm_policy": "open"}}} result = WeChatSecurityAdapter.resolve_dm_policy(config, "acc1") assert result == "open" def test_resolve_dm_policy_account_not_found_falls_back(self): config = {"dm_policy": "disabled", "accounts": {}} result = WeChatSecurityAdapter.resolve_dm_policy(config, "missing") assert result == "disabled" def test_resolve_dm_allow_from_root(self): result = WeChatSecurityAdapter.resolve_dm_allow_from({"allow_from": ["wx:a"]}) assert result == ["wx:a"] def test_resolve_dm_allow_from_account(self): config = {"accounts": {"acc1": {"allow_from": ["wx:b"]}}} result = WeChatSecurityAdapter.resolve_dm_allow_from(config, "acc1") assert result == ["wx:b"] def test_resolve_dm_allow_from_empty(self): assert WeChatSecurityAdapter.resolve_dm_allow_from({}) == [] def test_resolve_group_policy_default(self): assert WeChatSecurityAdapter.resolve_group_policy({}) == "allowlist" def test_resolve_group_policy_from_account(self): config = {"accounts": {"acc1": {"group_policy": "open"}}} result = WeChatSecurityAdapter.resolve_group_policy(config, "acc1") assert result == "open" def test_resolve_group_allow_from_combined(self): config = { "group_allow_from": ["wx:global"], "groups": {"chat1": {"allow_from": ["wx:local"]}}, } result = WeChatSecurityAdapter.resolve_group_allow_from(config, "chat1") assert "wx:global" in result assert "wx:local" in result def test_resolve_group_allow_from_no_duplicates(self): config = { "group_allow_from": ["wx:a"], "groups": {"chat1": {"allow_from": ["wx:a", "wx:b"]}}, } result = WeChatSecurityAdapter.resolve_group_allow_from(config, "chat1") assert result.count("wx:a") == 1 assert "wx:b" in result def test_collect_warnings_open_dm_policy(self): warnings = WeChatSecurityAdapter.collect_warnings({"dm_policy": "open"}) assert any("dm_policy='open'" in w for w in warnings) def test_collect_warnings_empty_allowlist(self): warnings = WeChatSecurityAdapter.collect_warnings({"dm_policy": "allowlist", "allow_from": []}) assert any("allowlist 为空" in w for w in warnings) def test_collect_warnings_empty_group_allowlist(self): warnings = WeChatSecurityAdapter.collect_warnings({"group_policy": "allowlist"}) assert any("群组 allowlist 为空" in w for w in warnings) def test_collect_warnings_no_pairing(self): warnings = WeChatSecurityAdapter.collect_warnings({"dm_policy": "open"}) assert any("配对机制" in w for w in warnings) def test_collect_warnings_with_pairing_ok(self): warnings = WeChatSecurityAdapter.collect_warnings({ "dm_policy": "pairing", "accounts": {"acc1": {"dm_policy": "pairing"}}, }) assert not any("配对机制" in w for w in warnings) def test_collect_audit_findings_normal(self): findings = WeChatSecurityAdapter.collect_audit_findings({"allow_from": ["wx:a"]}) assert len(findings) == 0 def test_collect_audit_findings_large_allowlist(self): large_list = [f"wx:{i}" for i in range(2000)] findings = WeChatSecurityAdapter.collect_audit_findings({"allow_from": large_list}) assert len(findings) > 0 assert findings[0]["category"] == "allowlist_size"