mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
fix(telegram): group authz fallback + command sender identity
- authz_mixin: add config.extra fallback for group_allowed_chats when observe-unmentioned mode strips user_id from env-var check - authz_mixin: check adapter allow_from/group_allow_from for user authorization from config.yaml without env vars - telegram/adapter: separate group_allow_from for group chats vs allow_from for DMs - telegram/adapter: preserve sender source for command messages so admin-only slash commands work in groups - telegram/adapter: add _telegram_extra fallback for group_allow_from config reading
This commit is contained in:
parent
9eb7b1a6b1
commit
45fce38b9e
2 changed files with 48 additions and 4 deletions
|
|
@ -357,6 +357,24 @@ class GatewayAuthorizationMixin:
|
|||
if "*" in allowed_group_ids or source.chat_id in allowed_group_ids:
|
||||
return True
|
||||
|
||||
# Fallback: also check adapter-level config (config.yaml)
|
||||
# for platforms.<platform>.extra.group_allowed_chats.
|
||||
# The Telegram observe-unmentioned mode strips user_id from
|
||||
# triggered group messages (_apply_telegram_group_observe_attribution),
|
||||
# so the env-var-only check above misses config.yaml-configured
|
||||
# allowlists. Read the live adapter's config.extra as a fallback.
|
||||
try:
|
||||
adapter = self._adapter_for_source(source)
|
||||
if adapter is not None:
|
||||
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()}
|
||||
if "*" in allowed or source.chat_id in allowed:
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Bots admitted by {PLATFORM}_ALLOW_BOTS bypass the human allowlist (#4466).
|
||||
# Checked before the no-user-id guard below: some platforms deliver
|
||||
# bot/automation traffic with no user_id at all -- e.g. Slack Workflow
|
||||
|
|
@ -525,6 +543,21 @@ class GatewayAuthorizationMixin:
|
|||
)
|
||||
if effective_policy == "allowlist":
|
||||
return True
|
||||
# Some adapters (e.g. Telegram) gate access via config.extra.allow_from /
|
||||
# group_allow_from at intake but do not override enforces_own_access_policy.
|
||||
# Check their allowlist here so config.yaml-configured allow_from works
|
||||
# without requiring a separate {PLATFORM}_ALLOWED_USERS env var.
|
||||
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"}:
|
||||
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()}
|
||||
if user_id in allowed or "*" in allowed:
|
||||
return True
|
||||
# No allowlists configured -- check global allow-all flag
|
||||
return _auth_env("GATEWAY_ALLOW_ALL_USERS").lower() in {"true", "1", "yes"}
|
||||
|
||||
|
|
|
|||
|
|
@ -1013,8 +1013,13 @@ class TelegramAdapter(BasePlatformAdapter):
|
|||
if not user_id:
|
||||
return True
|
||||
|
||||
# Adapter-level allow_from: when set, it is the sole authority.
|
||||
adapter_allow_from = self.config.extra.get("allow_from")
|
||||
# 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"):
|
||||
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()}
|
||||
return user_id in allowed or "*" in allowed
|
||||
|
|
@ -7775,9 +7780,15 @@ class TelegramAdapter(BasePlatformAdapter):
|
|||
observe_prompt = self._telegram_group_observe_channel_prompt()
|
||||
channel_prompt = f"{event.channel_prompt}\n\n{observe_prompt}" if event.channel_prompt else observe_prompt
|
||||
if event.message_type == MessageType.COMMAND:
|
||||
# Commands must retain the original source (with user_id) so
|
||||
# slash-access control (_check_slash_access) can identify the
|
||||
# sender. Replacing the source with an anonymised shared source
|
||||
# (user_id=None) causes admin-only commands like /new to be
|
||||
# denied even when the sender is an admin, because
|
||||
# SlashAccessPolicy.is_admin(None) is always False.
|
||||
# Still inject channel_prompt for group context.
|
||||
return dataclasses.replace(
|
||||
event,
|
||||
source=shared_source,
|
||||
channel_prompt=channel_prompt,
|
||||
)
|
||||
return dataclasses.replace(
|
||||
|
|
@ -9394,7 +9405,7 @@ def _apply_yaml_config(yaml_cfg: dict, telegram_cfg: dict) -> dict | None:
|
|||
if isinstance(allowed_users, list):
|
||||
allowed_users = ",".join(str(v) for v in allowed_users)
|
||||
os.environ["TELEGRAM_ALLOWED_USERS"] = str(allowed_users)
|
||||
group_allowed_users = telegram_cfg.get("group_allow_from")
|
||||
group_allowed_users = telegram_cfg.get("group_allow_from") or _telegram_extra.get("group_allow_from")
|
||||
if group_allowed_users is not None and not os.getenv("TELEGRAM_GROUP_ALLOWED_USERS"):
|
||||
if isinstance(group_allowed_users, list):
|
||||
group_allowed_users = ",".join(str(v) for v in group_allowed_users)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue