fix(telegram): let an explicit TELEGRAM_REACTIONS beat the materialized YAML default
545e74d0ea made _reactions_enabled consult extra.reactions before the env
var, and _apply_yaml_config seeds extra["reactions"] whenever the YAML key
is present — including the stock reactions: false every install
materializes. The documented TELEGRAM_REACTIONS=true switch therefore
became a silent no-op after the 0.21.2 update (#109032), contradicting
yaml_env_setter's "explicit env wins over YAML" contract.
Read the scoped env first and fall back to the profile's own YAML: under
multiplex a scoped miss returns the default instead of another profile's
process-env value (#72348), so only a scoped/env hit counts as explicit
and per-profile isolation is unchanged.
Fixes #109032
(cherry picked from commit 2bd5a0a5c0a5f9630fd82f133def65f225f653a3)
This commit is contained in:
@@ -6392,10 +6392,19 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||
# -- Message reactions (processing lifecycle) --
|
||||
|
||||
def _reactions_enabled(self) -> bool:
|
||||
"""Reactions enabled via ``extra.reactions`` (YAML, per profile) or TELEGRAM_REACTIONS."""
|
||||
configured = self.config.extra.get("reactions")
|
||||
"""Reactions enabled via TELEGRAM_REACTIONS or ``extra.reactions`` (YAML, per profile).
|
||||
|
||||
An explicitly set env var wins over YAML — the same rule ``yaml_env_setter`` documents for
|
||||
the YAML→env bridge — so the stock ``reactions: false`` every install materializes cannot
|
||||
silently kill a documented ``TELEGRAM_REACTIONS=true`` (#109032). Under multiplex a scoped
|
||||
miss returns the default instead of another profile's process-env value (#72348), so only
|
||||
a scoped/env hit counts as explicit; otherwise the profile's own YAML decides.
|
||||
"""
|
||||
configured = _scoped_gate_env("TELEGRAM_REACTIONS", "")
|
||||
if not configured:
|
||||
configured = self.config.extra.get("reactions")
|
||||
if configured is None:
|
||||
configured = _scoped_gate_env("TELEGRAM_REACTIONS", "false")
|
||||
return False
|
||||
return str(configured).lower() not in {"false", "0", "no"}
|
||||
|
||||
async def _set_reaction(self, chat_id: str, message_id: str, emoji: Optional[str]) -> bool:
|
||||
|
||||
@@ -53,6 +53,75 @@ def test_reactions_enabled_when_set_true(monkeypatch):
|
||||
assert adapter._reactions_enabled() is True
|
||||
|
||||
|
||||
def test_explicit_env_wins_over_materialized_yaml_default(monkeypatch):
|
||||
"""TELEGRAM_REACTIONS=true must beat the stock ``reactions: false`` in config.yaml (#109032).
|
||||
|
||||
Fresh installs materialize the whole default config tree, so ``_apply_yaml_config`` seeds
|
||||
``extra["reactions"] = False`` even when the user never chose a value; the reader must still
|
||||
honour the explicitly set env var, like ``yaml_env_setter`` documents for the bridge.
|
||||
"""
|
||||
monkeypatch.setenv("TELEGRAM_REACTIONS", "true")
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = False
|
||||
assert adapter._reactions_enabled() is True
|
||||
|
||||
|
||||
def test_bridged_yaml_false_without_explicit_env_still_disables(monkeypatch):
|
||||
"""With no explicit env the YAML→env bridge writes 'false'; reactions stay off."""
|
||||
monkeypatch.setenv("TELEGRAM_REACTIONS", "false")
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = False
|
||||
assert adapter._reactions_enabled() is False
|
||||
|
||||
|
||||
def test_yaml_true_enables_when_env_unset(monkeypatch):
|
||||
"""An explicit ``reactions: true`` in config.yaml enables reactions without any env var."""
|
||||
monkeypatch.delenv("TELEGRAM_REACTIONS", raising=False)
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = True
|
||||
assert adapter._reactions_enabled() is True
|
||||
|
||||
|
||||
def test_explicit_env_false_wins_over_yaml_true(monkeypatch):
|
||||
"""An explicit TELEGRAM_REACTIONS=false also wins over a YAML ``reactions: true``."""
|
||||
monkeypatch.setenv("TELEGRAM_REACTIONS", "false")
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = True
|
||||
assert adapter._reactions_enabled() is False
|
||||
|
||||
|
||||
def test_scoped_miss_does_not_leak_default_profile_env(monkeypatch):
|
||||
"""Under multiplex a scoped miss must not read another profile's process-env value (#72348)."""
|
||||
from agent.secret_scope import reset_secret_scope, set_multiplex_active, set_secret_scope
|
||||
|
||||
monkeypatch.setenv("TELEGRAM_REACTIONS", "true") # default profile's bridged value
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = False # this profile's own YAML
|
||||
set_multiplex_active(True)
|
||||
token = set_secret_scope({"TELEGRAM_BOT_TOKEN": "222:b2"})
|
||||
try:
|
||||
assert adapter._reactions_enabled() is False
|
||||
finally:
|
||||
reset_secret_scope(token)
|
||||
set_multiplex_active(False)
|
||||
|
||||
|
||||
def test_scoped_env_hit_wins_over_own_yaml(monkeypatch):
|
||||
"""A secondary profile's own scoped TELEGRAM_REACTIONS=true beats its YAML ``reactions: false``."""
|
||||
from agent.secret_scope import reset_secret_scope, set_multiplex_active, set_secret_scope
|
||||
|
||||
monkeypatch.setenv("TELEGRAM_REACTIONS", "false") # default profile's value
|
||||
adapter = _make_adapter()
|
||||
adapter.config.extra["reactions"] = False
|
||||
set_multiplex_active(True)
|
||||
token = set_secret_scope({"TELEGRAM_BOT_TOKEN": "222:b2", "TELEGRAM_REACTIONS": "true"})
|
||||
try:
|
||||
assert adapter._reactions_enabled() is True
|
||||
finally:
|
||||
reset_secret_scope(token)
|
||||
set_multiplex_active(False)
|
||||
|
||||
|
||||
# ── _set_reaction ────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user