- в конфиг добавлены секция [auth.test_headers] и предохранитель [server] debug: заголовки входа подставляет слой транспорта, второго процесса локальный запуск больше не требует - подкоманда devtools proxy удалена целиком: всё, ради чего её поднимали, делает сам сервис - адресного предохранителя нет по решению владельца — цена названа в ADR и в модели угроз
7.4 KiB
Заголовки входа отладочного запуска подставляет сам сервис, а не второй процесс
- Дата: 2026-08-23
- Источник: ../../openspec/changes/archive/2026-08-23-config-test-headers-login/design.md, решения 1, 6, 7 и 10
Решение
Заголовки входа на машине разработчика ставит сам сервис — отдельным слоем цепочки корня приложения, а не вспомогательным процессом рядом:
отдельный слой цепочки корня приложения, стоящий перед
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. Ключ с открытым перечнем следствий обрастает ими молча.−Каждый новый логин имитации заводит учётную запись, а удалять их сервис не умеет. Локальная база ронится и пересоздаётся свободно, в бою подстановка выключена — но лишние записи копятся.