sync: 154 file da Baida98/AI@fad752ee (2026-08-15 11:09 UTC) [deploy-all]

#33
by Baida07 - opened
api/telegram_webhook.py CHANGED
@@ -61,19 +61,25 @@ async def _tg_reply(chat_id: str | int, text: str, token: str | None = None,
61
  try:
62
  import httpx
63
  timeout = httpx.Timeout(connect=5.0, read=15.0, write=10.0, pool=5.0)
64
- # Il backend non richiede proxy HTTP per raggiungere l'API Telegram.
65
- # Ignorare proxy d'ambiente evita ReadTimeout silenziosi in hosting gestiti.
 
 
 
 
 
 
 
 
 
66
  async with httpx.AsyncClient(timeout=timeout, trust_env=False) as c:
67
- response = await c.post(
68
- f"https://api.telegram.org/bot{bot_token}/sendMessage",
69
- json=payload,
70
- )
71
  try:
72
  data = response.json()
73
  except ValueError:
74
  data = {}
75
  if response.status_code >= 400 or not data.get("ok", False):
76
- detail = str(data.get("description") or response.text[:160] or "unknown")
77
  _logger.warning("tg_reply rejected: status=%s detail=%s", response.status_code, detail)
78
  except Exception as exc:
79
  detail = str(exc) or repr(exc)
 
61
  try:
62
  import httpx
63
  timeout = httpx.Timeout(connect=5.0, read=15.0, write=10.0, pool=5.0)
64
+ gateway_url = os.getenv("TELEGRAM_REPLY_PROXY_URL", "").strip()
65
+ gateway_secret = os.getenv("TELEGRAM_REPLY_PROXY_SECRET", "").strip()
66
+ if gateway_url and gateway_secret:
67
+ request_url = gateway_url
68
+ request_headers = {"Authorization": f"Bearer {gateway_secret}"}
69
+ else:
70
+ # Compatibilità per ambienti che non hanno ancora il gateway Pages.
71
+ request_url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
72
+ request_headers = {}
73
+ # Il gateway isola l'egress Telegram dal runtime HF, dove la connessione
74
+ # diretta può scadere. trust_env evita proxy ambiente non necessari.
75
  async with httpx.AsyncClient(timeout=timeout, trust_env=False) as c:
76
+ response = await c.post(request_url, headers=request_headers, json=payload)
 
 
 
77
  try:
78
  data = response.json()
79
  except ValueError:
80
  data = {}
81
  if response.status_code >= 400 or not data.get("ok", False):
82
+ detail = str(data.get("description") or data.get("error") or response.text[:160] or "unknown")
83
  _logger.warning("tg_reply rejected: status=%s detail=%s", response.status_code, detail)
84
  except Exception as exc:
85
  detail = str(exc) or repr(exc)
tests/test_telegram_reply_transport.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import unittest
2
  from unittest.mock import patch
3
 
@@ -20,6 +21,7 @@ class _Client:
20
  instances = []
21
  response = _Response()
22
  exception = None
 
23
 
24
  def __init__(self, **kwargs):
25
  self.kwargs = kwargs
@@ -31,7 +33,8 @@ class _Client:
31
  async def __aexit__(self, *_args):
32
  return False
33
 
34
- async def post(self, *_args, **_kwargs):
 
35
  if type(self).exception is not None:
36
  raise type(self).exception
37
  return type(self).response
@@ -42,6 +45,7 @@ class TelegramReplyTransportTests(unittest.IsolatedAsyncioTestCase):
42
  _Client.instances = []
43
  _Client.response = _Response()
44
  _Client.exception = None
 
45
 
46
  async def test_reply_bypasses_environment_proxy_and_accepts_success(self):
47
  with patch("httpx.AsyncClient", _Client):
@@ -51,6 +55,21 @@ class TelegramReplyTransportTests(unittest.IsolatedAsyncioTestCase):
51
  self.assertFalse(_Client.instances[0].kwargs["trust_env"])
52
  self.assertIsInstance(_Client.instances[0].kwargs["timeout"], httpx.Timeout)
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  async def test_reply_logs_rejected_telegram_response(self):
55
  _Client.response = _Response(
56
  status_code=429,
 
1
+ import os
2
  import unittest
3
  from unittest.mock import patch
4
 
 
21
  instances = []
22
  response = _Response()
23
  exception = None
24
+ last_post = None
25
 
26
  def __init__(self, **kwargs):
27
  self.kwargs = kwargs
 
33
  async def __aexit__(self, *_args):
34
  return False
35
 
36
+ async def post(self, *args, **kwargs):
37
+ type(self).last_post = (args, kwargs)
38
  if type(self).exception is not None:
39
  raise type(self).exception
40
  return type(self).response
 
45
  _Client.instances = []
46
  _Client.response = _Response()
47
  _Client.exception = None
48
+ _Client.last_post = None
49
 
50
  async def test_reply_bypasses_environment_proxy_and_accepts_success(self):
51
  with patch("httpx.AsyncClient", _Client):
 
55
  self.assertFalse(_Client.instances[0].kwargs["trust_env"])
56
  self.assertIsInstance(_Client.instances[0].kwargs["timeout"], httpx.Timeout)
57
 
58
+ async def test_reply_uses_authenticated_pages_gateway_when_configured(self):
59
+ with patch.dict(
60
+ os.environ,
61
+ {
62
+ "TELEGRAM_REPLY_PROXY_URL": "https://tma-agente.pages.dev/api/telegram/send",
63
+ "TELEGRAM_REPLY_PROXY_SECRET": "gateway-secret",
64
+ },
65
+ clear=False,
66
+ ), patch("httpx.AsyncClient", _Client):
67
+ await _tg_reply(123, "hello", token="test-token")
68
+
69
+ args, kwargs = _Client.last_post
70
+ self.assertEqual(args[0], "https://tma-agente.pages.dev/api/telegram/send")
71
+ self.assertEqual(kwargs["headers"], {"Authorization": "Bearer gateway-secret"})
72
+
73
  async def test_reply_logs_rejected_telegram_response(self):
74
  _Client.response = _Response(
75
  status_code=429,