telegram: сервис поднимается без бота и работает одним входом
- Клиент бота собирается один раз и достаётся отправителю и транспорту; разрез прошёл по «ответил ли Telegram»: ответ «такого бота нет» роняет старт, недоступность даёт подъём без Telegram (ADR-2026-08-13). Ожидание при сборке ограничено сроком — иначе молчащий Telegram вешал подъём. - Недоставленный ответ не роняет шаг: пишется с job_id и считается метрикой, уровень по причине — WARN для неподнятого входа, ERROR для неназванного адресата. Заведены transcriber_intake_up и transcriber_undelivered_reply_count. - Закрыта утечка токена в журнал: отказ разбора адреса рождается раньше обращения к клиенту, то есть мимо чистки на его границе.
This commit is contained in:
@@ -63,6 +63,27 @@ func TestBotAPIFailureDoesNotCarryToken(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// Токен, ломающий разбор адреса, — второй путь отказа конструктора, и до
|
||||
// недавнего он был открыт: `http.NewRequest` падает раньше обращения к клиенту,
|
||||
// то есть мимо чистки на его границе. Так выглядит перенос строки, приехавший
|
||||
// с секретом из шаблона выкладки, и невычищенная `%`-последовательность.
|
||||
func TestBotConstructionFailureOnUnparsableTokenDoesNotCarryToken(t *testing.T) {
|
||||
broken := map[string]string{
|
||||
"перенос строки": probeToken + "\n",
|
||||
"негодная escape-пара": "7654321:AAH%zzSECRETtokenVALUE",
|
||||
}
|
||||
|
||||
for name, token := range broken {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
_, err := newBot(token, tgbotapi.APIEndpoint, slog.New(slog.DiscardHandler))
|
||||
|
||||
require.Error(t, err)
|
||||
assert.NotContains(t, err.Error(), token, "токен уехал в отказ: %v", err)
|
||||
assert.NotContains(t, err.Error(), "api.telegram.org", "адрес остался в отказе: %v", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Отказ конструктора несёт тот же путь: `NewBotAPIWithClient` ходит за `getMe`,
|
||||
// и контейнер, стартующий раньше сети, печатал бы токен в первую же секунду.
|
||||
func TestBotConstructionFailureDoesNotCarryToken(t *testing.T) {
|
||||
@@ -92,10 +113,21 @@ func TestLibraryLoggerRedactsToken(t *testing.T) {
|
||||
}
|
||||
|
||||
// Пустой токен — законный исход подъёма без Telegram, и узнаётся он по смыслу.
|
||||
// Обратное тоже нормируется: отказ негодного токена не должен читаться как
|
||||
// отказ от входа, иначе сборка при старте подставит заглушку там, где нужен
|
||||
// отказ, и молча потеряет бота.
|
||||
func TestEmptyTokenIsRecognizedByValue(t *testing.T) {
|
||||
_, err := NewBot("", slog.New(slog.DiscardHandler))
|
||||
|
||||
require.ErrorIs(t, err, ErrEmptyToken)
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
|
||||
server.Close()
|
||||
|
||||
_, err = newBot(probeToken, server.URL+"/bot%s/%s", slog.New(slog.DiscardHandler))
|
||||
|
||||
require.Error(t, err)
|
||||
require.NotErrorIs(t, err, ErrEmptyToken)
|
||||
}
|
||||
|
||||
// WithoutURL снимает адрес, но не причину: `errors.Is` по цепочке продолжает
|
||||
|
||||
Reference in New Issue
Block a user