fix(telegram): widen transport-error redaction to all remaining raw exception sites
Extends @AlexFucuson9's 3-site fix (#58594) across the full adapter: every logger call and SendResult.error that interpolates a raw PTB exception now routes through _redact_telegram_error_text(). Covers polling conflict/retry/network ladders, overflow-split edits, draft sends, prompt/approval/clarify/picker sends, media send fallbacks, media cache failures, reactions, and chat-info lookups (48 additional sites). Telegram Bot API exceptions embed the token in the request URL (/bot<TOKEN>/<method>), so any raw str(exc) is a leak surface. Adds regression tests for SendResult.error redaction (update prompt, clarify) and delete_message debug-log redaction.fix/verification-admin-route-recovery
parent
6e96b745d8
commit
a04fcbf779
|
|
@ -1222,7 +1222,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
"retrying without reply/topic anchor: %s",
|
"retrying without reply/topic anchor: %s",
|
||||||
self.name,
|
self.name,
|
||||||
media_label,
|
media_label,
|
||||||
send_err,
|
_redact_telegram_error_text(send_err),
|
||||||
)
|
)
|
||||||
if reset_media is not None:
|
if reset_media is not None:
|
||||||
reset_media()
|
reset_media()
|
||||||
|
|
@ -1883,12 +1883,12 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
self._rich_draft_disabled = True
|
self._rich_draft_disabled = True
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] sendRichMessageDraft unsupported (%s) — using legacy drafts",
|
"[%s] sendRichMessageDraft unsupported (%s) — using legacy drafts",
|
||||||
self.name, exc,
|
self.name, _redact_telegram_error_text(exc),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] sendRichMessageDraft transient failure (%s) — legacy draft this frame",
|
"[%s] sendRichMessageDraft transient failure (%s) — legacy draft this frame",
|
||||||
self.name, exc,
|
self.name, _redact_telegram_error_text(exc),
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -2155,7 +2155,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
if self._polling_error_task and not self._polling_error_task.done():
|
if self._polling_error_task and not self._polling_error_task.done():
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] Telegram polling recovery already scheduled; ignoring %s: %s",
|
"[%s] Telegram polling recovery already scheduled; ignoring %s: %s",
|
||||||
self.name, reason, error,
|
self.name, reason, _redact_telegram_error_text(error),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
self._send_path_degraded = True
|
self._send_path_degraded = True
|
||||||
|
|
@ -2188,7 +2188,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] deleteWebhook failed with a recoverable network error; "
|
"[%s] deleteWebhook failed with a recoverable network error; "
|
||||||
"continuing to polling so getUpdates/retry can recover: %s",
|
"continuing to polling so getUpdates/retry can recover: %s",
|
||||||
self.name, err,
|
self.name, _redact_telegram_error_text(err),
|
||||||
)
|
)
|
||||||
self._send_path_degraded = True
|
self._send_path_degraded = True
|
||||||
return False
|
return False
|
||||||
|
|
@ -2227,7 +2227,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Telegram polling bootstrap conflict; gateway stays alive "
|
"[%s] Telegram polling bootstrap conflict; gateway stays alive "
|
||||||
"while conflict retry runs: %s",
|
"while conflict retry runs: %s",
|
||||||
self.name, err,
|
self.name, _redact_telegram_error_text(err),
|
||||||
)
|
)
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
self._polling_error_task = loop.create_task(self._handle_polling_conflict(err))
|
self._polling_error_task = loop.create_task(self._handle_polling_conflict(err))
|
||||||
|
|
@ -2722,7 +2722,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
"held open on Telegram's servers. Waiting %ds for it to expire. "
|
"held open on Telegram's servers. Waiting %ds for it to expire. "
|
||||||
"Error: %s",
|
"Error: %s",
|
||||||
self.name, self._polling_conflict_count, MAX_CONFLICT_RETRIES,
|
self.name, self._polling_conflict_count, MAX_CONFLICT_RETRIES,
|
||||||
RETRY_DELAY, error,
|
RETRY_DELAY, _redact_telegram_error_text(error),
|
||||||
)
|
)
|
||||||
# Stop the local updater cleanly before sleeping. If it's already
|
# Stop the local updater cleanly before sleeping. If it's already
|
||||||
# stopped (e.g. PTB raised before updater.running was set) this is
|
# stopped (e.g. PTB raised before updater.running was set) this is
|
||||||
|
|
@ -2779,7 +2779,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
"[%s] Telegram polling retry %d/%d failed: %s. "
|
"[%s] Telegram polling retry %d/%d failed: %s. "
|
||||||
"Scheduling next attempt.",
|
"Scheduling next attempt.",
|
||||||
self.name, self._polling_conflict_count, MAX_CONFLICT_RETRIES,
|
self.name, self._polling_conflict_count, MAX_CONFLICT_RETRIES,
|
||||||
retry_err,
|
_redact_telegram_error_text(retry_err),
|
||||||
)
|
)
|
||||||
# Schedule the next retry rather than returning silently.
|
# Schedule the next retry rather than returning silently.
|
||||||
# Returning here without either restarting polling or setting
|
# Returning here without either restarting polling or setting
|
||||||
|
|
@ -2818,7 +2818,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
)
|
)
|
||||||
logger.error(
|
logger.error(
|
||||||
"[%s] %s Original error: %s",
|
"[%s] %s Original error: %s",
|
||||||
self.name, message, error,
|
self.name, message, _redact_telegram_error_text(error),
|
||||||
)
|
)
|
||||||
# Snapshot whether we are the call that actually transitions to fatal.
|
# Snapshot whether we are the call that actually transitions to fatal.
|
||||||
# A concurrent retry task scheduled by an earlier conflict may already
|
# A concurrent retry task scheduled by an earlier conflict may already
|
||||||
|
|
@ -2895,7 +2895,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Failed to create DM topic '%s' in chat %s: %s",
|
"[%s] Failed to create DM topic '%s' in chat %s: %s",
|
||||||
self.name, name, chat_id, e,
|
self.name, name, chat_id, _redact_telegram_error_text(e),
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -3213,7 +3213,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Could not register Telegram command menu: %s",
|
"[%s] Could not register Telegram command menu: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -3600,12 +3600,12 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
self._background_tasks.add(self._polling_error_task)
|
self._background_tasks.add(self._polling_error_task)
|
||||||
self._polling_error_task.add_done_callback(self._background_tasks.discard)
|
self._polling_error_task.add_done_callback(self._background_tasks.discard)
|
||||||
elif self._looks_like_network_error(error):
|
elif self._looks_like_network_error(error):
|
||||||
logger.warning("[%s] Telegram network error, scheduling reconnect: %s", self.name, error)
|
logger.warning("[%s] Telegram network _redact_telegram_error_text(error), scheduling reconnect: %s", self.name, error)
|
||||||
self._polling_error_task = loop.create_task(self._handle_polling_network_error(error))
|
self._polling_error_task = loop.create_task(self._handle_polling_network_error(error))
|
||||||
self._background_tasks.add(self._polling_error_task)
|
self._background_tasks.add(self._polling_error_task)
|
||||||
self._polling_error_task.add_done_callback(self._background_tasks.discard)
|
self._polling_error_task.add_done_callback(self._background_tasks.discard)
|
||||||
else:
|
else:
|
||||||
logger.error("[%s] Telegram polling error: %s", self.name, error, exc_info=True)
|
logger.error("[%s] Telegram polling _redact_telegram_error_text(error): %s", self.name, error, exc_info=True)
|
||||||
|
|
||||||
# Store reference for retry use in _handle_polling_conflict
|
# Store reference for retry use in _handle_polling_conflict
|
||||||
self._polling_error_callback_ref = _polling_error_callback
|
self._polling_error_callback_ref = _polling_error_callback
|
||||||
|
|
@ -3684,7 +3684,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] Failed to set bot status indicator to %r: %s",
|
"[%s] Failed to set bot status indicator to %r: %s",
|
||||||
self.name, text, e,
|
self.name, text, _redact_telegram_error_text(e),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _cancel_pending_delivery_tasks(self) -> None:
|
async def _cancel_pending_delivery_tasks(self) -> None:
|
||||||
|
|
@ -4498,7 +4498,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Overflow split: MarkdownV2 first-chunk edit "
|
"[%s] Overflow split: MarkdownV2 first-chunk edit "
|
||||||
"failed, falling back to plain text: %s",
|
"failed, falling back to plain text: %s",
|
||||||
self.name, fmt_err,
|
self.name, _redact_telegram_error_text(fmt_err),
|
||||||
)
|
)
|
||||||
await self._bot.edit_message_text(
|
await self._bot.edit_message_text(
|
||||||
chat_id=normalize_telegram_chat_id(chat_id),
|
chat_id=normalize_telegram_chat_id(chat_id),
|
||||||
|
|
@ -4520,9 +4520,9 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(
|
||||||
"[%s] Overflow split: first-chunk edit failed: %s",
|
"[%s] Overflow split: first-chunk edit failed: %s",
|
||||||
self.name, e, exc_info=True,
|
self.name, _redact_telegram_error_text(e), exc_info=True,
|
||||||
)
|
)
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
# Step 2 — send each remaining chunk as a continuation message,
|
# Step 2 — send each remaining chunk as a continuation message,
|
||||||
# threaded as a reply to the previous so the user sees them as a
|
# threaded as a reply to the previous so the user sees them as a
|
||||||
|
|
@ -4589,7 +4589,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
except Exception as _retry_err:
|
except Exception as _retry_err:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Overflow continuation no-reply retry failed: %s",
|
"[%s] Overflow continuation no-reply retry failed: %s",
|
||||||
self.name, _retry_err,
|
self.name, _redact_telegram_error_text(_retry_err),
|
||||||
)
|
)
|
||||||
sent_msg = None
|
sent_msg = None
|
||||||
break
|
break
|
||||||
|
|
@ -4598,7 +4598,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
continue
|
continue
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] Overflow continuation send failed: %s",
|
"[%s] Overflow continuation send failed: %s",
|
||||||
self.name, send_err,
|
self.name, _redact_telegram_error_text(send_err),
|
||||||
)
|
)
|
||||||
sent_msg = None
|
sent_msg = None
|
||||||
break
|
break
|
||||||
|
|
@ -4669,7 +4669,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] Failed to delete Telegram message %s: %s",
|
"[%s] Failed to delete Telegram message %s: %s",
|
||||||
self.name, message_id, e,
|
self.name, message_id, _redact_telegram_error_text(e),
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -4770,14 +4770,14 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] sendMessageDraft MarkdownV2 rejected, retrying "
|
"[%s] sendMessageDraft MarkdownV2 rejected, retrying "
|
||||||
"as plain text (chat=%s draft_id=%s): %s",
|
"as plain text (chat=%s draft_id=%s): %s",
|
||||||
self.name, chat_id, draft_id, e,
|
self.name, chat_id, draft_id, _redact_telegram_error_text(e),
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] sendMessageDraft failed (chat=%s draft_id=%s): %s",
|
"[%s] sendMessageDraft failed (chat=%s draft_id=%s): %s",
|
||||||
self.name, chat_id, draft_id, e,
|
self.name, chat_id, draft_id, e,
|
||||||
)
|
)
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
return SendResult(success=False, error="draft_rejected")
|
return SendResult(success=False, error="draft_rejected")
|
||||||
|
|
||||||
|
|
@ -4860,8 +4860,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
)
|
)
|
||||||
return SendResult(success=True, message_id=str(msg.message_id))
|
return SendResult(success=True, message_id=str(msg.message_id))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] send_update_prompt failed: %s", self.name, e)
|
logger.warning("[%s] send_update_prompt failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
async def send_exec_approval(
|
async def send_exec_approval(
|
||||||
self, chat_id: str, command: str, session_key: str,
|
self, chat_id: str, command: str, session_key: str,
|
||||||
|
|
@ -4939,8 +4939,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
|
|
||||||
return SendResult(success=True, message_id=str(msg.message_id))
|
return SendResult(success=True, message_id=str(msg.message_id))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] send_exec_approval failed: %s", self.name, e)
|
logger.warning("[%s] send_exec_approval failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
async def send_slash_confirm(
|
async def send_slash_confirm(
|
||||||
self, chat_id: str, title: str, message: str, session_key: str,
|
self, chat_id: str, title: str, message: str, session_key: str,
|
||||||
|
|
@ -4987,8 +4987,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
self._slash_confirm_state[confirm_id] = session_key
|
self._slash_confirm_state[confirm_id] = session_key
|
||||||
return SendResult(success=True, message_id=str(msg.message_id))
|
return SendResult(success=True, message_id=str(msg.message_id))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] send_slash_confirm failed: %s", self.name, e)
|
logger.warning("[%s] send_slash_confirm failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
async def send_clarify(
|
async def send_clarify(
|
||||||
self,
|
self,
|
||||||
|
|
@ -5069,8 +5069,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
self._clarify_state[clarify_id] = session_key
|
self._clarify_state[clarify_id] = session_key
|
||||||
return SendResult(success=True, message_id=str(msg.message_id))
|
return SendResult(success=True, message_id=str(msg.message_id))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] send_clarify failed: %s", self.name, e)
|
logger.warning("[%s] send_clarify failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
async def send_model_picker(
|
async def send_model_picker(
|
||||||
self,
|
self,
|
||||||
|
|
@ -5141,8 +5141,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
|
|
||||||
return SendResult(success=True, message_id=str(msg.message_id))
|
return SendResult(success=True, message_id=str(msg.message_id))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] send_model_picker failed: %s", self.name, e)
|
logger.warning("[%s] send_model_picker failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return SendResult(success=False, error=str(e))
|
return SendResult(success=False, error=_redact_telegram_error_text(e))
|
||||||
|
|
||||||
_PROVIDER_PAGE_SIZE = 10
|
_PROVIDER_PAGE_SIZE = 10
|
||||||
_MODEL_PAGE_SIZE = 8
|
_MODEL_PAGE_SIZE = 8
|
||||||
|
|
@ -6219,7 +6219,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.error(
|
logger.error(
|
||||||
"[%s] Failed to send Telegram voice/audio, falling back to base adapter: %s",
|
"[%s] Failed to send Telegram voice/audio, falling back to base adapter: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
return await super().send_voice(chat_id, audio_path, caption, reply_to, metadata=metadata)
|
return await super().send_voice(chat_id, audio_path, caption, reply_to, metadata=metadata)
|
||||||
|
|
@ -6345,7 +6345,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] send_media_group failed (chunk %d/%d), falling back to per-image: %s",
|
"[%s] send_media_group failed (chunk %d/%d), falling back to per-image: %s",
|
||||||
self.name, chunk_idx + 1, len(chunks), e,
|
self.name, chunk_idx + 1, len(chunks), _redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
# Fallback: send each photo in this chunk individually
|
# Fallback: send each photo in this chunk individually
|
||||||
|
|
@ -6427,7 +6427,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
"[%s] Failed to send Telegram local image as photo, "
|
"[%s] Failed to send Telegram local image as photo, "
|
||||||
"trying document fallback: %s",
|
"trying document fallback: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
# Fallback to sending as document (file) — no dimension limit,
|
# Fallback to sending as document (file) — no dimension limit,
|
||||||
|
|
@ -6607,7 +6607,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"[%s] URL-based send_photo failed, trying file upload: %s",
|
"[%s] URL-based send_photo failed, trying file upload: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
# Fallback: download and upload as file (supports up to 10MB)
|
# Fallback: download and upload as file (supports up to 10MB)
|
||||||
|
|
@ -6691,7 +6691,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.error(
|
logger.error(
|
||||||
"[%s] Failed to send Telegram animation, falling back to photo: %s",
|
"[%s] Failed to send Telegram animation, falling back to photo: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
# Fallback: try as a regular photo
|
# Fallback: try as a regular photo
|
||||||
|
|
@ -6778,7 +6778,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"[%s] Failed to send Telegram typing indicator: %s",
|
"[%s] Failed to send Telegram typing indicator: %s",
|
||||||
self.name,
|
self.name,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -6811,7 +6811,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
"[%s] Failed to get Telegram chat info for %s: %s",
|
"[%s] Failed to get Telegram chat info for %s: %s",
|
||||||
self.name,
|
self.name,
|
||||||
chat_id,
|
chat_id,
|
||||||
e,
|
_redact_telegram_error_text(e),
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
return {"name": str(chat_id), "type": "dm", "error": str(e)}
|
return {"name": str(chat_id), "type": "dm", "error": str(e)}
|
||||||
|
|
@ -7503,7 +7503,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
filename = os.path.basename(getattr(file_obj, "file_path", "") or "")
|
filename = os.path.basename(getattr(file_obj, "file_path", "") or "")
|
||||||
cached = cache_media_bytes(data, filename=filename, mime_type=mime, default_kind=kind)
|
cached = cache_media_bytes(data, filename=filename, mime_type=mime, default_kind=kind)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("[Telegram] Failed to cache observed group media: %s", exc, exc_info=True)
|
logger.warning("[Telegram] Failed to cache observed group media: %s", _redact_telegram_error_text(exc), exc_info=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if cached is None:
|
if cached is None:
|
||||||
|
|
@ -7551,7 +7551,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
filename = os.path.basename(getattr(file_obj, "file_path", "") or "")
|
filename = os.path.basename(getattr(file_obj, "file_path", "") or "")
|
||||||
cached = cache_media_bytes(data, filename=filename, mime_type=mime, default_kind=kind)
|
cached = cache_media_bytes(data, filename=filename, mime_type=mime, default_kind=kind)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("[Telegram] Failed to cache replied-to media: %s", exc, exc_info=True)
|
logger.warning("[Telegram] Failed to cache replied-to media: %s", _redact_telegram_error_text(exc), exc_info=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
if cached is None:
|
if cached is None:
|
||||||
|
|
@ -7794,7 +7794,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
self._forum_command_registered.add(chat_id)
|
self._forum_command_registered.add(chat_id)
|
||||||
logger.info("[%s] Lazy-registered %d commands for forum chat %s", self.name, len(bot_commands), chat_id)
|
logger.info("[%s] Lazy-registered %d commands for forum chat %s", self.name, len(bot_commands), chat_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[%s] Forum command lazy-registration failed: %s", self.name, e)
|
logger.warning("[%s] Forum command lazy-registration failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
|
|
||||||
def _effective_update_message(self, update: Update) -> Optional[Message]:
|
def _effective_update_message(self, update: Update) -> Optional[Message]:
|
||||||
"""Return the message-like payload for normal messages and channel posts.
|
"""Return the message-like payload for normal messages and channel posts.
|
||||||
|
|
@ -8141,7 +8141,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
return
|
return
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Failed to cache photo: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache photo: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
await self._surface_media_cache_failure(msg, event, "photo", e)
|
await self._surface_media_cache_failure(msg, event, "photo", e)
|
||||||
|
|
||||||
# Download voice/audio messages to cache for STT transcription
|
# Download voice/audio messages to cache for STT transcription
|
||||||
|
|
@ -8160,7 +8160,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
event.media_types = ["audio/ogg"]
|
event.media_types = ["audio/ogg"]
|
||||||
logger.info("[Telegram] Cached user voice at %s", cached_path)
|
logger.info("[Telegram] Cached user voice at %s", cached_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Failed to cache voice: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache voice: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
await self._surface_media_cache_failure(msg, event, "voice message", e)
|
await self._surface_media_cache_failure(msg, event, "voice message", e)
|
||||||
elif msg.audio:
|
elif msg.audio:
|
||||||
try:
|
try:
|
||||||
|
|
@ -8177,7 +8177,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
event.media_types = ["audio/mp3"]
|
event.media_types = ["audio/mp3"]
|
||||||
logger.info("[Telegram] Cached user audio at %s", cached_path)
|
logger.info("[Telegram] Cached user audio at %s", cached_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Failed to cache audio: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache audio: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
await self._surface_media_cache_failure(msg, event, "audio file", e)
|
await self._surface_media_cache_failure(msg, event, "audio file", e)
|
||||||
|
|
||||||
elif msg.video:
|
elif msg.video:
|
||||||
|
|
@ -8201,7 +8201,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
event.media_types = [SUPPORTED_VIDEO_TYPES.get(ext, "video/mp4")]
|
event.media_types = [SUPPORTED_VIDEO_TYPES.get(ext, "video/mp4")]
|
||||||
logger.info("[Telegram] Cached user video at %s", cached_path)
|
logger.info("[Telegram] Cached user video at %s", cached_path)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Failed to cache video: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache video: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
await self._surface_media_cache_failure(msg, event, "video file", e)
|
await self._surface_media_cache_failure(msg, event, "video file", e)
|
||||||
|
|
||||||
# Download document files to cache for agent processing
|
# Download document files to cache for agent processing
|
||||||
|
|
@ -8248,7 +8248,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
try:
|
try:
|
||||||
cached_path = cache_image_from_bytes(bytes(image_bytes), ext=image_ext)
|
cached_path = cache_image_from_bytes(bytes(image_bytes), ext=image_ext)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.warning("[Telegram] Failed to cache image document: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache image document: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
event.text = (
|
event.text = (
|
||||||
f"Image document '{original_filename or doc_mime or ext or 'unknown'}' "
|
f"Image document '{original_filename or doc_mime or ext or 'unknown'}' "
|
||||||
"could not be read as an image."
|
"could not be read as an image."
|
||||||
|
|
@ -8334,7 +8334,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Failed to cache document: %s", e, exc_info=True)
|
logger.warning("[Telegram] Failed to cache document: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
await self._surface_media_cache_failure(
|
await self._surface_media_cache_failure(
|
||||||
msg, event, "attachment", e,
|
msg, event, "attachment", e,
|
||||||
display_name=getattr(doc, "file_name", None) or None,
|
display_name=getattr(doc, "file_name", None) or None,
|
||||||
|
|
@ -8451,7 +8451,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
emoji, set_name,
|
emoji, set_name,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("[Telegram] Sticker analysis error: %s", e, exc_info=True)
|
logger.warning("[Telegram] Sticker analysis error: %s", _redact_telegram_error_text(e), exc_info=True)
|
||||||
event.text = build_sticker_injection(
|
event.text = build_sticker_injection(
|
||||||
f"a sticker with emoji {emoji}" if emoji else "a sticker",
|
f"a sticker with emoji {emoji}" if emoji else "a sticker",
|
||||||
emoji, set_name,
|
emoji, set_name,
|
||||||
|
|
@ -8815,7 +8815,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug("[%s] set_message_reaction failed (%s): %s", self.name, emoji, e)
|
logger.debug("[%s] set_message_reaction failed (%s): %s", self.name, emoji, _redact_telegram_error_text(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def _clear_reactions(self, chat_id: str, message_id: str) -> bool:
|
async def _clear_reactions(self, chat_id: str, message_id: str) -> bool:
|
||||||
|
|
@ -8836,7 +8836,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug("[%s] clear reactions failed: %s", self.name, e)
|
logger.debug("[%s] clear reactions failed: %s", self.name, _redact_telegram_error_text(e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def on_processing_start(self, event: MessageEvent) -> None:
|
async def on_processing_start(self, event: MessageEvent) -> None:
|
||||||
|
|
|
||||||
|
|
@ -130,3 +130,61 @@ async def test_send_video_failure_redacts_token_in_log(monkeypatch, caplog, tmp_
|
||||||
logged = "\n".join(r.getMessage() for r in caplog.records)
|
logged = "\n".join(r.getMessage() for r in caplog.records)
|
||||||
assert _SECRET_TOKEN not in logged
|
assert _SECRET_TOKEN not in logged
|
||||||
assert "Failed to send video" in logged
|
assert "Failed to send video" in logged
|
||||||
|
|
||||||
|
|
||||||
|
_SECRET_SEND_URL = f"https://api.telegram.org/bot{_SECRET_TOKEN}/sendMessage"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_update_prompt_failure_redacts_token_in_result_and_log(caplog):
|
||||||
|
"""A send_update_prompt() transport exception embedding the bot token URL
|
||||||
|
must not reach the warning log or SendResult.error unredacted."""
|
||||||
|
adapter = _make_connected_adapter()
|
||||||
|
adapter._send_message_with_thread_fallback = AsyncMock(
|
||||||
|
side_effect=RuntimeError(f"Timed out requesting {_SECRET_SEND_URL}")
|
||||||
|
)
|
||||||
|
|
||||||
|
with caplog.at_level("WARNING"):
|
||||||
|
result = await adapter.send_update_prompt("123", "restart?")
|
||||||
|
|
||||||
|
assert result.success is False
|
||||||
|
assert _SECRET_TOKEN not in (result.error or "")
|
||||||
|
assert "***" in (result.error or "")
|
||||||
|
logged = "\n".join(r.getMessage() for r in caplog.records)
|
||||||
|
assert _SECRET_TOKEN not in logged
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_clarify_failure_redacts_token_in_result_and_log(caplog):
|
||||||
|
"""A send_clarify() transport exception embedding the bot token URL must
|
||||||
|
not reach the warning log or SendResult.error unredacted."""
|
||||||
|
adapter = _make_connected_adapter()
|
||||||
|
adapter._send_message_with_thread_fallback = AsyncMock(
|
||||||
|
side_effect=RuntimeError(f"Timed out requesting {_SECRET_SEND_URL}")
|
||||||
|
)
|
||||||
|
|
||||||
|
with caplog.at_level("WARNING"):
|
||||||
|
result = await adapter.send_clarify("123", "q?", ["a", "b"], "cid", "sess")
|
||||||
|
|
||||||
|
assert result.success is False
|
||||||
|
assert _SECRET_TOKEN not in (result.error or "")
|
||||||
|
logged = "\n".join(r.getMessage() for r in caplog.records)
|
||||||
|
assert _SECRET_TOKEN not in logged
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delete_message_failure_redacts_token_in_log(caplog):
|
||||||
|
"""A delete_message() transport exception embedding the bot token URL
|
||||||
|
must not reach the debug log unredacted."""
|
||||||
|
adapter = _make_connected_adapter()
|
||||||
|
adapter._bot.delete_message = AsyncMock(
|
||||||
|
side_effect=RuntimeError(f"Bad Request: {_SECRET_SEND_URL}")
|
||||||
|
)
|
||||||
|
|
||||||
|
with caplog.at_level("DEBUG"):
|
||||||
|
ok = await adapter.delete_message("123", "55")
|
||||||
|
|
||||||
|
assert ok is False
|
||||||
|
logged = "\n".join(r.getMessage() for r in caplog.records)
|
||||||
|
assert _SECRET_TOKEN not in logged
|
||||||
|
assert "***" in logged
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue