mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-01 07:01:41 +00:00
fix(gateway): allow chat-scoped telegram auth without sender user_id
This commit is contained in:
parent
721d47f439
commit
b38140eb8f
2 changed files with 162 additions and 5 deletions
|
|
@ -276,6 +276,133 @@ def test_telegram_group_chat_allowlist_authorizes_group_chat_without_user_allowl
|
|||
assert runner._is_user_authorized(source) is True
|
||||
|
||||
|
||||
def test_telegram_group_chat_allowlist_authorizes_anonymous_sender(monkeypatch):
|
||||
"""TELEGRAM_GROUP_ALLOWED_CHATS must authorize chat traffic with no
|
||||
sender user_id (Telegram anonymous-admin posts, sender_chat). The
|
||||
docs state the chat allowlist authorizes "every member of that chat,
|
||||
regardless of sender" — anonymous senders had been silently dropped
|
||||
despite an explicit chat opt-in.
|
||||
"""
|
||||
_clear_auth_env(monkeypatch)
|
||||
monkeypatch.setenv("TELEGRAM_GROUP_ALLOWED_CHATS", "-1001878443972")
|
||||
|
||||
runner, _adapter = _make_runner(
|
||||
Platform.TELEGRAM,
|
||||
GatewayConfig(platforms={Platform.TELEGRAM: PlatformConfig(enabled=True, token="t")}),
|
||||
)
|
||||
|
||||
source = SessionSource(
|
||||
platform=Platform.TELEGRAM,
|
||||
user_id=None,
|
||||
chat_id="-1001878443972",
|
||||
user_name=None,
|
||||
chat_type="group",
|
||||
)
|
||||
|
||||
assert runner._is_user_authorized(source) is True
|
||||
|
||||
|
||||
def test_telegram_group_chat_allowlist_rejects_anonymous_sender_in_other_chat(monkeypatch):
|
||||
"""Anonymous senders in a chat *not* on the allowlist must still be
|
||||
rejected — the early no-user-id path must not become an open gate.
|
||||
"""
|
||||
_clear_auth_env(monkeypatch)
|
||||
monkeypatch.setenv("TELEGRAM_GROUP_ALLOWED_CHATS", "-1001878443972")
|
||||
|
||||
runner, _adapter = _make_runner(
|
||||
Platform.TELEGRAM,
|
||||
GatewayConfig(platforms={Platform.TELEGRAM: PlatformConfig(enabled=True, token="t")}),
|
||||
)
|
||||
|
||||
source = SessionSource(
|
||||
platform=Platform.TELEGRAM,
|
||||
user_id=None,
|
||||
chat_id="-1009999999999",
|
||||
user_name=None,
|
||||
chat_type="group",
|
||||
)
|
||||
|
||||
assert runner._is_user_authorized(source) is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_message_does_not_drop_anonymous_sender_in_allowlisted_chat(monkeypatch):
|
||||
"""End-to-end: a group message with from_user=None in an allowlisted
|
||||
chat must reach the dispatch path — not get silently dropped by the
|
||||
no-user-id guard, and not trigger pairing (anonymous senders can't
|
||||
be paired anyway).
|
||||
"""
|
||||
_clear_auth_env(monkeypatch)
|
||||
monkeypatch.setenv("TELEGRAM_GROUP_ALLOWED_CHATS", "-1001878443972")
|
||||
|
||||
config = GatewayConfig(
|
||||
platforms={Platform.TELEGRAM: PlatformConfig(enabled=True, token="t")},
|
||||
)
|
||||
runner, adapter = _make_runner(Platform.TELEGRAM, config)
|
||||
|
||||
# Force _handle_message to bail with a sentinel right after the
|
||||
# auth gate, so a successful "auth passed" call can be distinguished
|
||||
# from the buggy "silently dropped" case (which would return None
|
||||
# before this hook ever runs).
|
||||
reached_dispatch = MagicMock(side_effect=RuntimeError("reached dispatch"))
|
||||
runner._session_key_for_source = reached_dispatch
|
||||
|
||||
event = MessageEvent(
|
||||
text="hi",
|
||||
message_id="m1",
|
||||
source=SessionSource(
|
||||
platform=Platform.TELEGRAM,
|
||||
user_id=None,
|
||||
chat_id="-1001878443972",
|
||||
user_name=None,
|
||||
chat_type="group",
|
||||
),
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="reached dispatch"):
|
||||
await runner._handle_message(event)
|
||||
|
||||
reached_dispatch.assert_called_once()
|
||||
runner.pairing_store.generate_code.assert_not_called()
|
||||
adapter.send.assert_not_awaited()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_message_drops_anonymous_sender_outside_allowlist(monkeypatch):
|
||||
"""Anonymous senders in a chat *not* on the allowlist remain silently
|
||||
dropped — the fix must not become a backdoor for unauthorized chats.
|
||||
"""
|
||||
_clear_auth_env(monkeypatch)
|
||||
monkeypatch.setenv("TELEGRAM_GROUP_ALLOWED_CHATS", "-1001878443972")
|
||||
|
||||
config = GatewayConfig(
|
||||
platforms={Platform.TELEGRAM: PlatformConfig(enabled=True, token="t")},
|
||||
)
|
||||
runner, adapter = _make_runner(Platform.TELEGRAM, config)
|
||||
|
||||
must_not_run = MagicMock(side_effect=AssertionError("auth gate did not drop"))
|
||||
runner._session_key_for_source = must_not_run
|
||||
|
||||
event = MessageEvent(
|
||||
text="hi",
|
||||
message_id="m1",
|
||||
source=SessionSource(
|
||||
platform=Platform.TELEGRAM,
|
||||
user_id=None,
|
||||
chat_id="-1009999999999",
|
||||
user_name=None,
|
||||
chat_type="group",
|
||||
),
|
||||
)
|
||||
|
||||
result = await runner._handle_message(event)
|
||||
|
||||
assert result is None
|
||||
must_not_run.assert_not_called()
|
||||
runner.pairing_store.generate_code.assert_not_called()
|
||||
adapter.send.assert_not_awaited()
|
||||
|
||||
|
||||
def test_telegram_group_users_legacy_chat_ids_still_authorize(monkeypatch):
|
||||
"""Backward-compat: PR #15027 shipped TELEGRAM_GROUP_ALLOWED_USERS as a
|
||||
chat-ID allowlist. PR #17686 renamed it to sender IDs and added
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue