fix(wecom): scope WECOM_BOT_ID reads to the active profile under multiplexing
WeComAdapter.__init__ read WECOM_BOT_ID via a raw os.getenv() call, while the immediately adjacent line for WECOM_SECRET already used the module's _get_scoped_secret() helper. Under gateway.multiplex_profiles, a secondary profile's adapter is constructed inside a scoped context where os.environ still holds the DEFAULT profile's env-bridge output -- so a secondary profile's bot would silently connect using the default profile's bot_id while (correctly) using its own secret, or vice versa on a scope miss. Switch the bot_id read to _get_scoped_secret(), matching the sibling _secret/_dm_policy/_group_policy/allow_from reads in the same __init__ that were already migrated in #76664/#93545. _standalone_send's out-of-process fallback branch constructs a fresh WeComAdapter(pconfig) and therefore inherits this fix automatically -- no separate change needed there. Adds two regression tests to the existing TestWeComAdapterAuthzScope class (already covering dm_policy/allow_from scoping per #93522), mirroring its established fixture/assertion style. Mutation-verified: both fail against the pre-fix code (asserting the default profile's bot_id leaks into a secondary profile's scope) and pass with the fix.
This commit is contained in:
@@ -318,7 +318,7 @@ class WeComAdapter(BasePlatformAdapter):
|
||||
super().__init__(config, Platform.WECOM)
|
||||
|
||||
extra = config.extra or {}
|
||||
self._bot_id = str(extra.get("bot_id") or os.getenv("WECOM_BOT_ID", "")).strip()
|
||||
self._bot_id = str(extra.get("bot_id") or _get_scoped_secret("WECOM_BOT_ID", "")).strip()
|
||||
self._secret = str(extra.get("secret") or _get_scoped_secret("WECOM_SECRET", "")).strip()
|
||||
self._ws_url = str(
|
||||
extra.get("websocket_url")
|
||||
|
||||
@@ -76,6 +76,38 @@ class TestWeComAdapterAuthzScope:
|
||||
assert adapter._dm_policy == "pairing"
|
||||
assert adapter._allow_from == []
|
||||
|
||||
def test_scoped_construction_reads_bot_id_from_scope_not_environ(self, multiplex_on, monkeypatch):
|
||||
"""bot_id must honor the same scope as its neighboring _secret read
|
||||
(both are read on adjacent lines in __init__) -- a secondary profile's
|
||||
own bot_id must never fall back to the default profile's os.environ
|
||||
value."""
|
||||
from agent import secret_scope
|
||||
from plugins.platforms.wecom.adapter import WeComAdapter
|
||||
|
||||
monkeypatch.setenv("WECOM_BOT_ID", "default-profile-bot-id")
|
||||
monkeypatch.setenv("WECOM_SECRET", "default-profile-secret")
|
||||
token = secret_scope.set_secret_scope(
|
||||
{"WECOM_BOT_ID": "scoped-bot-id", "WECOM_SECRET": "scoped-secret"}
|
||||
)
|
||||
try:
|
||||
adapter = WeComAdapter(PlatformConfig(enabled=True))
|
||||
finally:
|
||||
secret_scope.reset_secret_scope(token)
|
||||
assert adapter._bot_id == "scoped-bot-id"
|
||||
assert adapter._secret == "scoped-secret"
|
||||
|
||||
def test_scoped_miss_does_not_leak_default_profiles_bot_id(self, multiplex_on, monkeypatch):
|
||||
from agent import secret_scope
|
||||
from plugins.platforms.wecom.adapter import WeComAdapter
|
||||
|
||||
monkeypatch.setenv("WECOM_BOT_ID", "default-profile-bot-id")
|
||||
token = secret_scope.set_secret_scope({"SOMETHING_ELSE": "x"})
|
||||
try:
|
||||
adapter = WeComAdapter(PlatformConfig(enabled=True))
|
||||
finally:
|
||||
secret_scope.reset_secret_scope(token)
|
||||
assert adapter._bot_id == ""
|
||||
|
||||
|
||||
class TestWeComConnect:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user