fix(gateway): gate oversized Telegram voice/audio before download (#44245)

* fix(gateway): gate oversized Telegram voice/audio before download

Adds a pre-download size check to the Telegram voice and audio inbound
paths. Files that exceed _max_doc_bytes (default 20 MB) are rejected
before get_file() is called, preventing silent OOM-style stalls on large
uploads. A human-readable note is appended to the event text so the
model can explain the limit to the user.

Also extends 403 entitlement detection in recover_with_credential_pool
to cover two additional cases: 'oauth authentication is currently not
allowed for this organization' and Anthropic anthropic_messages-mode 403s,
both of which should be treated as entitlement failures rather than
transient errors.

Tests: 7 new cases in test_telegram_voice_v0_regressions.py covering
the size gate (accept, reject, note text) and the STT-failure notice path.

Salvaged from #40487 (cryptopafi) — cherry-picked the Telegram voice
policy and 403 entitlement fixes; LiveKit/Discord/uv.lock workstreams
left for separate PRs.

* test(gateway): drop orphaned voice tests not backed by this PR

The cherry-picked test file from #40487 included 3 tests for STT-failure
notice and voice-mode (_handle_voice_command 'on' -> voice_only) behavior
that this PR intentionally does NOT salvage (those belong to the LiveKit/
voice-policy workstreams left in #40487). They fail on both this branch
and clean main because the feature code isn't present.

Keep only the 2 tests backed by code actually in this PR:
- test_telegram_audio_size_gate_rejects_oversized_media_before_download
  (covers the _telegram_media_size_allowed guard this PR adds)
- test_voice_tts_is_explicit_audio_reply_opt_in (matches current main)

Removed now-unused imports (MessageEvent, MessageType, AsyncMock).
This commit is contained in:
Austin Pickett
2026-06-11 10:01:51 -04:00
committed by GitHub
parent a09343cc96
commit d0e017bac8
3 changed files with 130 additions and 7 deletions
@@ -0,0 +1,71 @@
import sys
from pathlib import Path
from types import SimpleNamespace
import pytest
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from gateway.config import Platform
from gateway.platforms.telegram import TelegramAdapter
from gateway.run import GatewayRunner
from gateway.session import SessionSource
def _source():
return SessionSource(platform=Platform.TELEGRAM, chat_id="12345", chat_type="dm")
def _runner(adapter=None):
runner = object.__new__(GatewayRunner)
runner.config = SimpleNamespace(
stt_enabled=True,
group_sessions_per_user=True,
thread_sessions_per_user=False,
)
runner.adapters = {Platform.TELEGRAM: adapter} if adapter else {}
runner._consume_pending_native_image_paths = lambda _key: []
runner._session_key_for_source = lambda _source: "telegram:dm:12345"
runner._thread_metadata_for_source = lambda *_args, **_kwargs: {}
runner._reply_anchor_for_event = lambda _event: None
return runner
def test_telegram_audio_size_gate_rejects_oversized_media_before_download():
adapter = object.__new__(TelegramAdapter)
adapter._max_doc_bytes = 1024
allowed, note = adapter._telegram_media_size_allowed(
SimpleNamespace(file_size=2048),
"voice message",
)
assert allowed is False
assert "exceeds" in note
assert "voice message" in note
@pytest.mark.asyncio
async def test_voice_tts_is_explicit_audio_reply_opt_in():
adapter = SimpleNamespace(
_auto_tts_disabled_chats=set(),
_auto_tts_enabled_chats=set(),
)
runner = _runner(adapter)
runner._voice_mode = {}
runner._voice_provider_mode = {}
runner._save_voice_modes = lambda: None
runner._save_voice_provider_modes = lambda: None
event = SimpleNamespace(
source=_source(),
get_command_args=lambda: "tts",
)
result = await GatewayRunner._handle_voice_command(runner, event)
assert runner._voice_mode["telegram:12345"] == "all"
assert "12345" in adapter._auto_tts_enabled_chats
assert result