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

5.6 KiB

Разбор TOML: незнакомый ключ и незнакомая секция не отказ, а тишина

Отвечает на вопрос, возникший по ходу задачи config-test-headers-login: что делает декодер настроек с ключом и секцией, которых структура не знает, и виден ли этот случай хоть чем-нибудь. Наблюдение понадобилось потому, что ревью нашло опечатку в имени новой секции [auth.test_headers], проходящую молча, и без разреза нельзя было сказать, где кончается предмет задачи и начинается свойство самой библиотеки.

Соседняя записка о той же библиотеке — toml-decode-errors.md — разбирает семейства отказов; здесь предмет обратный: случай, отказа не дающий.

Как снималось

Прогонами на зависимости, зафиксированной в go.mod: github.com/BurntSushi/toml версии v1.5.0. Оба уровня снял триаж ревью 2026-08-23, отчёт — triage-2026-08-23.md, находка 2 и факт, подтверждённый разбором прохода operations. Временные файлы прогонов удалены, бинарник поднимался в каталог вне репозитория, не в data/.

  • Модульный. Вход [server]\ndebug = true\n[auth]\n[auth.test_headrs]\n"Remote-User" = "dev" — опечатка в имени секции.
  • Сквозной. Настоящий бинарник на конфиге с той же опечаткой, порт 18099, каталог данных вне репозитория; проба curl /app/me.

Что выяснилось

  • Незнакомая секция и незнакомый ключ отказа не дают: decode err=<nil>. Разбор проходит целиком, поля структуры остаются нулевыми, и отличить «в файле этого нет» от «в файле это написано с опечаткой» по результату разбора нельзя. В прогоне: Server.Debug=true len(TestHeaders)=0.
  • Потерянное называет только MetaData.Undecoded(). Он возвращает перечень путей, которых структура не знала: [auth.test_headrs auth.test_headrs.Remote-User]. Значение это в проекте не читает никто — ни загрузка настроек, ни проверки старта.
  • Контроль показывает, что дело в уровне, а не в разборе вообще. Ту же опечатку внутри известной секции (Remote-Usr вместо Remote-User) ловит проверка старта — auth: секция [auth.test_headers] называет заголовок, которого сервис не читает: Remote-Usr, — потому что судит её код проекта, а не библиотека. Ошибка в имени самой секции до этого кода не доходит.
  • Сквозной прогон следа не оставляет вовсе. Бинарник поднимается без предупреждения, curl /app/me отвечает 401, а в журнале стоит только INFO "Incoming request" … http.status_code=401.
  • Отсюда направление отката бинарника безопасно. Прежний образ, получивший конфиг с ключами, которых его структура ещё не знает, эти ключи игнорирует и поднимается. Свойство держится ровно на тишине выше: перечень MetaData.Undecoded() никто не судит.

Что из этого следует для кода

Свойство сегодня используется, а не терпится: правило выкладки «конфиг после образа» опирается именно на него, и его дом — ../architecture.md, «Эксплуатация». Здесь записано, чем свойство обеспечено и как проверено, а не надо ли его менять.

Отсюда же цена любой будущей проверки MetaData.Undecoded(): непонятый ключ, роняющий старт, закрывает опечатки во всех секциях разом — и тем же движением снимает безопасность отката, потому что прежний образ перестанет поднимать конфиг новее себя. Разменивать одно на другое — отдельное решение владельца, а не попутная правка.

Наблюдение привязано к версии. Версия, начавшая судить незнакомые ключи сама, сменит оба следствия разом — молчаливую опечатку и безопасный откат.