mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(telegram): address review findings from PR #67816
- Update test_observed_group_context_preserves_slash_command_text_for_dispatch to assert user_id is preserved for COMMAND messages (new correct behavior) - Add _coerce_allow_set helper to handle both list and comma-separated string allowlist inputs (prevents character-by-character iteration bug) - Include 'channel' in chat_type checks for group-scoped authorization - Add _telegram_extra fallback for group_allowed_chats (consistent with group_allow_from fallback) - Add AUTHOR_MAP entry for nyaruko@hermes -> tsuk1nose
This commit is contained in:
parent
45fce38b9e
commit
7078430934
4 changed files with 26 additions and 7 deletions
1
contributors/emails/nyaruko@hermes
Normal file
1
contributors/emails/nyaruko@hermes
Normal file
|
|
@ -0,0 +1 @@
|
|||
tsuk1nose
|
||||
|
|
@ -43,6 +43,21 @@ def _auth_env(name: str, default: str = "") -> str:
|
|||
return (os.getenv(name) or default).strip()
|
||||
|
||||
|
||||
def _coerce_allow_set(raw) -> set[str]:
|
||||
"""Parse allowlist values from config or env var into a set of strings.
|
||||
|
||||
Handles both list inputs (YAML sequences) and comma-separated string
|
||||
inputs (env vars or scalar YAML values). A scalar string is split on
|
||||
commas so ``allow_from: "123,456"`` yields ``{"123", "456"}``, not
|
||||
``{"1", "2", "3", ",", ...}``.
|
||||
"""
|
||||
if raw is None:
|
||||
return set()
|
||||
if isinstance(raw, list):
|
||||
return {str(part).strip() for part in raw if str(part).strip()}
|
||||
return {part.strip() for part in str(raw).split(",") if part.strip()}
|
||||
|
||||
|
||||
class GatewayAuthorizationMixin:
|
||||
"""User/chat authorization methods for ``GatewayRunner``."""
|
||||
|
||||
|
|
@ -369,7 +384,7 @@ class GatewayAuthorizationMixin:
|
|||
extra = getattr(getattr(adapter, "config", None), "extra", None) or {}
|
||||
adapter_group_allowed = extra.get("group_allowed_chats")
|
||||
if adapter_group_allowed:
|
||||
allowed = {str(c).strip() for c in adapter_group_allowed if str(c).strip()}
|
||||
allowed = _coerce_allow_set(adapter_group_allowed)
|
||||
if "*" in allowed or source.chat_id in allowed:
|
||||
return True
|
||||
except Exception:
|
||||
|
|
@ -550,12 +565,12 @@ class GatewayAuthorizationMixin:
|
|||
adapter = self._adapter_for_source(source)
|
||||
if adapter is not None:
|
||||
extra = getattr(getattr(adapter, "config", None), "extra", None) or {}
|
||||
if source.chat_type in {"group", "forum"}:
|
||||
if source.chat_type in {"group", "forum", "channel"}:
|
||||
adapter_allow = extra.get("group_allow_from")
|
||||
else:
|
||||
adapter_allow = extra.get("allow_from")
|
||||
if adapter_allow:
|
||||
allowed = {str(u).strip() for u in adapter_allow if str(u).strip()}
|
||||
allowed = _coerce_allow_set(adapter_allow)
|
||||
if user_id in allowed or "*" in allowed:
|
||||
return True
|
||||
# No allowlists configured -- check global allow-all flag
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ import sys
|
|||
from pathlib import Path as _Path
|
||||
sys.path.insert(0, str(_Path(__file__).resolve().parents[3]))
|
||||
|
||||
from gateway.authz_mixin import _coerce_allow_set
|
||||
from gateway.config import Platform, PlatformConfig
|
||||
from gateway.platforms.base import (
|
||||
BasePlatformAdapter,
|
||||
|
|
@ -1016,12 +1017,12 @@ class TelegramAdapter(BasePlatformAdapter):
|
|||
# Adapter-level allow_from / group_allow_from: when set, they are the
|
||||
# sole authority. Group chats use group_allow_from; DMs use allow_from.
|
||||
chat_type = source.chat_type or ""
|
||||
if chat_type in ("group", "forum"):
|
||||
if chat_type in ("group", "forum", "channel"):
|
||||
adapter_allow_from = self.config.extra.get("group_allow_from")
|
||||
else:
|
||||
adapter_allow_from = self.config.extra.get("allow_from")
|
||||
if adapter_allow_from is not None:
|
||||
allowed = {str(u).strip() for u in adapter_allow_from if str(u).strip()}
|
||||
allowed = _coerce_allow_set(adapter_allow_from)
|
||||
return user_id in allowed or "*" in allowed
|
||||
|
||||
# Test/custom injection only. The class method named
|
||||
|
|
@ -9410,7 +9411,7 @@ def _apply_yaml_config(yaml_cfg: dict, telegram_cfg: dict) -> dict | None:
|
|||
if isinstance(group_allowed_users, list):
|
||||
group_allowed_users = ",".join(str(v) for v in group_allowed_users)
|
||||
os.environ["TELEGRAM_GROUP_ALLOWED_USERS"] = str(group_allowed_users)
|
||||
group_allowed_chats = telegram_cfg.get("group_allowed_chats")
|
||||
group_allowed_chats = telegram_cfg.get("group_allowed_chats") or _telegram_extra.get("group_allowed_chats")
|
||||
if group_allowed_chats is not None and not os.getenv("TELEGRAM_GROUP_ALLOWED_CHATS"):
|
||||
if isinstance(group_allowed_chats, list):
|
||||
group_allowed_chats = ",".join(str(v) for v in group_allowed_chats)
|
||||
|
|
|
|||
|
|
@ -346,7 +346,9 @@ def test_observed_group_context_preserves_slash_command_text_for_dispatch():
|
|||
|
||||
assert attributed.text == "/new@hermes_bot"
|
||||
assert attributed.get_command() == "new"
|
||||
assert attributed.source.user_id is None
|
||||
# Commands preserve sender identity for slash-access control (#67816).
|
||||
assert attributed.source.user_id == "111"
|
||||
assert attributed.source.user_name == "Alice"
|
||||
assert "observed Telegram group context" in attributed.channel_prompt
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue