Files
transcriber/docs/adr/ADR-2026-08-23-test-headers-substituted-by-service.md
T
av 52fe31319a локальный вход задаётся конфигом: заголовки подставляет сам сервис
- в конфиг добавлены секция [auth.test_headers] и предохранитель [server] debug:
  заголовки входа подставляет слой транспорта, второго процесса локальный запуск
  больше не требует
- подкоманда devtools proxy удалена целиком: всё, ради чего её поднимали, делает
  сам сервис
- адресного предохранителя нет по решению владельца — цена названа в ADR и в
  модели угроз
2026-08-23 13:12:47 +03:00

7.4 KiB
Raw Blame History

Заголовки входа отладочного запуска подставляет сам сервис, а не второй процесс

Решение

Заголовки входа на машине разработчика ставит сам сервис — отдельным слоем цепочки корня приложения, а не вспомогательным процессом рядом:

отдельный слой цепочки корня приложения, стоящий перед TrustedHeaderIdentity и после ограничителя частоты. Он правит заголовки запроса и ничего больше не делает: учётной записи не заводит, отказов не выдаёт, в контекст не пишет.

Включают слой два новых ключа настроек — предохранитель [server] debug и секция значений [auth.test_headers]. Прежний вспомогательный процесс уходит:

Решено владельцем на чекпоинте: подкоманда удаляется. Назначения у неё не остаётся — всё, ради чего её поднимали, делает сам сервис, — и второго способа входить локально не остаётся тоже.

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

Почему

Владелец назвал желаемое: один бинарник, различия между запусками — в конфиге. Дизайн записал это целью:

Локальный запуск идёт одним процессом и одной командой; вход — то, кем назвался пришедший, — отличает тестовый прогон от боевого содержимым файла настроек, и ничем больше.

Довод в пользу слоя перед узнаванием, а не внутри него:

Отлаживается та же ветка кода, что работает в бою: подставленный заголовок неотличим от пришедшего от Caddy к моменту, когда его читает узнавание.

Отвергнуты три очевидных подхода, и у каждого названа цена. Подстановка внутри TrustedHeaderIdentity — «узнавание получило бы второй источник значений и ветку, которой в бою нет. Отлаживалась бы не боевая ветка, а её отладочный двойник». Произвольная карта имён заголовков в конфиге — «опечатка Remote-Usr даёт „сервис меня не узнаёт“ без единого следа». Вырезать подстановку из боевой сборки тегом сборки:

сборка образа в гейте не проверяется вовсе (CLAUDE.md, «Гейт»), и тег, забытый в одной ступени, дал бы ровно ту тишину, которой избегает пункт 3.

Почему это ADR

Триггер сработал дважды. Дорогой откат: решение заводит два имени ключа настроек, а имя ключа конфига CLAUDE.md называет необратимым; вернуться к вспомогательному процессу значит поднять удалённую подкоманду, убрать оба ключа из настроек и переписать рецепт локального запуска, разошедшийся по образцу конфига, README.md, CLAUDE.md и конвенции настроек. Намеренный отказ: вырезать отладочный код из боевой сборки тегом сборки — то, что делают по умолчанию, и отказ от этого объясняется один раз здесь, а не на каждом вопросе «почему подстановка вообще есть в боевом бинарнике».

Последствия

  • + Локальный запуск идёт одним процессом и одной командой; приложение открывают по адресу сервиса, второго порта нет.
  • + Отлаживается боевая ветка узнавания: подставленный заголовок неотличим от пришедшего от прокси к моменту, когда его читают.
  • + Второго способа входить локально не остаётся, и документация перестаёт каждый раз говорить, какой из способов чей.
  • + Имена заголовков остаются с одним домом — константами транспорта; ключ, не совпавший ни с одним из них, роняет старт и называет принимаемые имена.
  • Местный инструмент больше не воспроизводит поломки контура. Цена названа в источнике прямо: два значения Remote-User, заголовок с недоверенного адреса, цепочка X-Forwarded-For — всё это теперь воспроизводит только автотест, ставящий заголовок сам.
  • В боевом бинарнике появляется код, называющий пришедшего без провайдера. Что его держит и чего у него нет — ADR-2026-08-23-no-address-guard-for-debug-login.
  • У ключа [server] debug закрытый перечень следствий, и держать его придётся руками: новое поведение привязывается к ключу только отдельным решением владельца и получает своё требование спеки access. Ключ с открытым перечнем следствий обрастает ими молча.
  • Каждый новый логин имитации заводит учётную запись, а удалять их сервис не умеет. Локальная база ронится и пересоздаётся свободно, в бою подстановка выключена — но лишние записи копятся.