Files
transcriber/tasks/items/journal-fields-bounded-by-service.md
T
av 91138dd39a точки входа переехали в cmd/, заведена заглушка OIDC для локального входа
- main.go и journal_route_test.go переехали в cmd/transcriber без правок
  содержимого; образ собирает ./cmd/transcriber поимённо
- cmd/oidcstub отвечает на /authorize, /token и /userinfo, проверок не делает
  и слушает петлевой адрес: войти без Authelia стало чем
- ступень сборки приложения переехала на node:24 с alpine — musl ждёт ответа
  на AAAA, которого нет, и npm ci висел вместо отказа
2026-08-15 20:15:57 +03:00

5.3 KiB
Raw Blame History

🐞 Не давать отправителю задавать, что уедет в журнал

  • Тип: fix
  • Категория: Очередь — Заведена урожаем ревью и встала в конец машинально: место в плане стройки назначает человек.
  • Зачем: Путь запроса уезжает в журнал целиком: аноним пишет туда до мегабайта своего текста одной строкой, а хвост имени файла приезжает внутри чужого текста ошибки вместо своего поля.
  • Теги: review-2026-08-15

Длину и содержимое строки журнала задаёт тот, кто прислал запрос, а не сервис.

Мест два, причина одна. Слой журнала пишет путь запроса полем http.route целиком: приведение режет только последний сегмент и только у ссылок на файлы. Отказ подготовки рабочей копии пересказывает отказ библиотеки целиком, а тот несёт полное имя временного файла — вместе с расширением, взятым из имени отправителя.

Журнал в этом проекте — место, где наблюдаются инварианты: по нему видно недоставку, остановку конвейера и молчаливый выход из шага. Вытесненный чужим текстом, он перестаёт отвечать на вопрос, ради которого заведён.

Класс проект уже назвал недопустимым в приведении отказа провайдера входа (conventions/logging.md): «без приведения аноним пишет в журнал что угодно и сколько угодно». Здесь тот же канал шире и дешевле — сессия для него не нужна.

Воспроизведение

Путь запроса. Поднять сервис и послать запрос, чей путь длиной 900 000 байт:

python3 -c 'socket … GET /<900000×"A"> HTTP/1.1'

Ответ — 404, журнал вырастает с 1048 до 901 194 байт одной строкой. Потолок замерен: 1 048 000 байт ещё проходят, 1 100 000 отвергаются кодом 431. Внедрения строк при этом нет — библиотека журнала квотирует значение.

Хвост имени. Принять запись, чьё имя несёт 280 байт после последней точки. Отказ подготовки рабочей копии приезжает в журнал уровня ERROR строкой вида error="failed to create work file: open /tmp/transcriber-<число>.<280 байт>: file name too long", и поля file_ext в ней нет вовсе.

Затрагивает

  • слой журнала запроса в cmd/transcriber и приведение пути journalRoute;
  • отказ подготовки рабочей копии в internal/service, шаг приёма записи;
  • docs/conventions/logging.md — правило о длине поля журнала;
  • умолчание MaxHeaderBytes у сервера: сегодня оно единственное неназванное рядом с названным сроком чтения.

Критерии приёмки

  • Путь запроса в журнале не длиннее объявленного предела, и усечение видно в самой строке. Оракул: тот же запрос с путём в 900 000 байт — прирост журнала не превышает предела, а маршрут по первым байтам по-прежнему различим.
  • Отказ подготовки рабочей копии не пересказывает отказ библиотеки: расширение идёт своим полем. Оракул: проверка приёма с длинным хвостом имени — строки с этим хвостом в журнале нет, поле file_ext есть.
  • Правило записано конвенцией: длину поля журнала не задаёт вызывающий. Оракул: строка в docs/conventions/logging.md и ссылка на неё из обеих правок.

Рамки

Приведение пути не должно делать маршрут неразличимым: по журналу отличают приём записи от чтения одной записи — POST /app/audiorecords от GET /app/audiorecords/{id}. Найдено прогоном ревью задачи remove-telegram-intake 2026-08-15, враждебный проход; дефект существовал до той правки, и владелец решил вынести его задачей.