diff --git a/gateway/config.py b/gateway/config.py index a1b61fed5..f130fa7da 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -843,6 +843,25 @@ def load_gateway_config() -> GatewayConfig: if plat == Platform.LOCAL: continue platform_cfg = yaml_cfg.get(plat.value) + _cfg_toplevel = isinstance(platform_cfg, dict) + # Fall back to the platform's block under ``platforms`` / + # ``gateway.platforms`` so shared-key bridging (allow_from, + # require_mention, free_response_channels, …) still runs when + # the user configured the platform only under those nested paths + # and not via a top-level block. Mirrors the identical fallback + # already applied to the apply_yaml_config_fn dispatch below + # (#44f3e51). + # Note: ``enabled`` is only written to plat_data from a + # top-level block (``_cfg_toplevel``); for nested-only configs + # ``_merge_platform_map`` already merged it with the correct + # precedence, so re-applying it here would overwrite that. + if not _cfg_toplevel: + for _src in (gateway_platforms, yaml_cfg.get("platforms")): + if isinstance(_src, dict): + _candidate = _src.get(plat.value) + if isinstance(_candidate, dict): + platform_cfg = _candidate + break if not isinstance(platform_cfg, dict): continue # Collect bridgeable keys from this platform section @@ -903,7 +922,7 @@ def load_gateway_config() -> GatewayConfig: bridged["channel_prompts"] = channel_prompts if "gateway_restart_notification" in platform_cfg: bridged["gateway_restart_notification"] = platform_cfg["gateway_restart_notification"] - enabled_was_explicit = "enabled" in platform_cfg + enabled_was_explicit = _cfg_toplevel and "enabled" in platform_cfg if not bridged and not enabled_was_explicit: continue plat_data, extra = _ensure_platform_extra_dict(platforms_data, plat.value) diff --git a/tests/gateway/test_config.py b/tests/gateway/test_config.py index 9950f967f..4f2756dba 100644 --- a/tests/gateway/test_config.py +++ b/tests/gateway/test_config.py @@ -477,6 +477,69 @@ class TestLoadGatewayConfig: assert telegram.token == "top-token" assert telegram.extra["reply_prefix"] == "top" + def test_shared_key_loop_bridges_allow_from_from_nested_platforms(self, tmp_path, monkeypatch): + """Regression: shared-key loop must bridge allow_from / require_mention + into PlatformConfig.extra even when the platform is configured only + under ``platforms:`` (no top-level ``telegram:`` block). + + Before the fix, ``platform_cfg = yaml_cfg.get('telegram')`` returned + None for nested-only configs, so the loop skipped the platform entirely + and allow_from was silently ignored. The apply_yaml_config_fn dispatch + received the same fix in #44f3e51; the shared-key loop now mirrors it. + """ + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "platforms:\n" + " telegram:\n" + " allow_from:\n" + " - \"111222333\"\n" + " - \"444555666\"\n" + " require_mention: true\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + telegram = config.platforms[Platform.TELEGRAM] + assert telegram.extra.get("allow_from") == ["111222333", "444555666"], ( + "allow_from configured under platforms.telegram must be bridged " + "into PlatformConfig.extra by the shared-key loop" + ) + assert telegram.extra.get("require_mention") is True, ( + "require_mention configured under platforms.telegram must be " + "bridged into PlatformConfig.extra by the shared-key loop" + ) + + def test_shared_key_loop_bridges_allow_from_from_nested_gateway_platforms(self, tmp_path, monkeypatch): + """Same regression check for ``gateway.platforms:`` path.""" + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "gateway:\n" + " platforms:\n" + " telegram:\n" + " allow_from:\n" + " - \"777888999\"\n" + " require_mention: false\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + telegram = config.platforms[Platform.TELEGRAM] + assert telegram.extra.get("allow_from") == ["777888999"], ( + "allow_from configured under gateway.platforms.telegram must be " + "bridged into PlatformConfig.extra by the shared-key loop" + ) + assert telegram.extra.get("require_mention") is False + def test_bridges_quoted_false_session_notify_from_config_yaml(self, tmp_path, monkeypatch): hermes_home = tmp_path / ".hermes" hermes_home.mkdir()