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:
nftpoetrist
2026-09-01 22:23:10 +03:00
committed by Teknium
parent 56d869d2d9
commit 07ee457a21
2 changed files with 33 additions and 1 deletions

View File

@@ -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")

View File

@@ -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: