textmachine/platform/docs/DEFECT_REGISTER.md

9.6 KiB
Raw Blame History

Регистр дефектов и уязвимостей платформы

Заведён по решению владельца 04.08 («отдельно ведётся колонка багов и уязвимостей — тут опасно всё»). Правила: каждая находка любой сессии/приёмки/аудита — строкой сюда ДО закрытия; ID стабилен навсегда; закрытие — только с коммитом фикса и тестом, пинящим свойство (урок PD-1: свойство без пинящего теста считается НЕ закрытым). Класс: vuln — эксплуатируемо или ослабляет защиту · bug — неверное поведение · hardening — защита в глубину / латентное. Статус: open · fixed(<commit>) · accepted-risk(<кем, когда>).

ID Класс Серьёзность Где Суть Статус Источник
PD-1 hardening minor internal/pgstore/pg_test.go:89 Свойство «в БД только SHA-256, не токен» НЕ запинено тестом: посадка «Digest возвращает плейнтекст» выживает — тест сверяет хранимое через тот же auth.Digest (self-consistent). Нужен тест с НЕЗАВИСИМО вычисленным хешом либо ассерт «плейнтекст в БД не находится» open приёмка P0 (посадка №1)
PD-2 vuln major, ЖИВАЯ (не латентная) cmd/tmplatformd/main.go:73-82 Нет ReadTimeout ⇒ соединения пиннятся уже СЕГОДНЯ, без единой body-принимающей ручки: net/http дренирует непрочитанное тело <256 КБ ВНУТРИ chunkWriter.writeHeader до отправки заголовка ответа (net/http/server.go:1389-1435), и этот чтение-шаг наследует отсутствующий дедлайн. Репродуцировано оркестратором на собранном бинаре: 50 полу-кормленных POST на охраняемый /v0/* → сервер отработал и залогировал 50×401 ms:0, клиенты получили НОЛЬ байт, fd 7→57 и держались, пока не закрыл КЛИЕНТ (агент-скептик независимо пинил 500 соединений). Ограничителя соединений и документированного edge-прокси в зоне нет. Фикс — одна строка (ReadTimeout; для будущего SSE — per-conn дедлайны через ResponseController). Вторая половина (MaxBytesReader) сегодня не эксплуатируема (ни один хендлер не читает body) — гейт P1: закрыть ДО первого POST-хендлера open приёмка P0 (security-линза + скептик + собственная репродукция)
PD-3 bug minor internal/httpapi/middleware.go:57 Recover логирует сырой r.URL.Path на ERROR — id книг/прогонов утекают в лог, против собственной дисциплины AccessLog (route-pattern, не путь) open приёмка P0 (security-линза)
PD-4 hardening minor internal/pgstore/sessions.go:41 WHERE у Touch слабее, чем у Lookup (нет idle_expires_at > now): прямой вызов воскресил бы idle-истёкшую сессию. Через Require недостижимо (Touch только после успешного Lookup) — одна строка защиты в глубину open приёмка P0 (security-линза)
PD-5 bug minor internal/auth/middleware.go:36,45 Ошибки стора невидимы: сбойный Lookup → 401 без единой строки лога (аутентификационный DB-outage выглядит как шторм 401), Touch глотается _ =. На проводе различать нельзя (оракул) — но лог обязан различать open приёмка P0 (security+blind линзы)
PD-6 hardening info internal/auth/csrf.go:51 GET освобождён от CSRF (верно), но SSE-хендшейк — GET с амбиентной кукой: origin-чек хендшейка потока (STACK §5) не покрыт ничем. Закрыть при постройке SSE (P1) open приёмка P0 (security-линза)
PD-7 bug info internal/pgstore/sessions.go:78 DeleteExpiredSessions никем не вызывается — свип запланировать в P1 (периодическая джоба воркера) open приёмка P0
PD-8 hardening info internal/auth/session.go:18 Писателя куки ещё нет; __Host- требует Secure ⇒ локальный dev по HTTP куку не поставит. Решить формой в P1 (dev-профиль), префикс не ослаблять в проде open приёмка P0
PD-9 bug minor cmd/tmplatformd/main.go:81 BaseContext возвращает signal-контекст ⇒ SIGTERM мгновенно рубит контексты ВСЕХ in-flight запросов, и 15-секундный дренаж Shutdown мёртв для ctx-aware хендлеров. Fix: BaseContext без signal-ctx; сигнал ведёт только Shutdown open приёмка P0 (faults-линза)
PD-10 bug minor internal/ingest/decoder.go:42,61,67 Три ужесточения декодера: (а) hello с пустым engine_run_id принимается — а это половина ключа идемпотентности; (б) seq самого hello не пинится к 1 — потеря пре-хендшейковых строк недетектируема; (в) mid-stream hello (любой версии, вкл. мажор 9.9) уходит в Sink как обычное событие — version-гейт держит только строку 1 open приёмка P0 (faults-линза)
PD-11 bug minor internal/pgstore/migrations/00002_readmodel.sql:137,177 Неиндексированные FK-каскады: notes.chapter_id и bank_decisions.term_id — каскадное удаление сканирует таблицы open приёмка P0 (faults-линза)
PD-12 bug info internal/ingest/supervisor.go:82-84 Сбой Sink в начале прогона ⇒ платформа дренирует ВЕСЬ оставшийся поток в io.Discard часами: ceiling/bank_stop-события выбрасываются, никто не оповещён. Нужна политика «БД платформы упала посреди прогона» (ретраи синка / деградация с алармом) — дизайн-вопрос P1 open приёмка P0 (faults-линза)
PD-13 bug info internal/ingest/supervisor.go:64 Краш платформы осиротляет процесс движка: ни process-group, ни pidfile, ни пути реаттача (поток невосстановим, повторный спавн упрётся в EXCLUSIVE-лок). Дизайн супервизии P1 open приёмка P0 (faults-линза)
PD-14 hardening info internal/httpapi/server.go:79 readyz: ping без собственного таймаута (WriteTimeout нет намеренно — SSE), эндпоинт неаутентифицирован и без rate-limit — задушить дешёво; таймаут на ping + прикрыть на ops-слое open приёмка P0
PD-15 bug info internal/ingest/resync.go:32 Деньги в ре-синке — float64, а usage_windows хранит micro-USD именно против дрейфа: дрейф входит шагом раньше (JSON-парс + суммирование дельт). Принять осознанно или считать в целых open приёмка P0 (faults-линза)
PD-16 bug minor internal/httpapi/server.go:81 readyz глотает ошибку ping вопреки собственному комменту «the reason stays in the log» — лога нет open приёмка P0 (blind-линза)
PD-17 bug minor Makefile:41-42 Баннер «did NOT run (no database)» печатается и при ПРОГНАННЫХ БД-тестах (безусловный); батарея гоняет сьют дважды ради имён скипов (второй прогон без -race) open приёмка P0 (blind-линза)
PD-18 bug info internal/pgstore/migrations/00002_readmodel.sql:9,139 Коммент шапки «engine vocabulary never crosses this seam» противоречит notes.reason (движковая причина хранится, не проецируется); коммент переписать честно open приёмка P0 (canon-линза)
PD-19 bug info internal/ingest/resync.go:44 WorstFlagReason задокументирован «stored», а колонки в chapters нет — доккоммент или схема, одно из двух open приёмка P0 (canon-линза)