security(errors): 5xx без утечки err.message клиенту

Шаг 0.7 плана production-готовности:
- глобальный error handler: нейтральный текст + код инцидента, детали в лог
- route-уровень: зачистка err.message/String(err) в 5xx по 12 файлам,
  оригинальные ошибки логируются с контекстом
This commit is contained in:
2026-09-07 20:42:39 +03:00
parent b3d7923b23
commit 26419f395f
14 changed files with 73 additions and 44 deletions

View File

@@ -47,3 +47,16 @@
- Как проверялось: `npx vitest run` — 45/45 зелёные; `npm run check` — чисто.
- Влияние на поиск/UX: нет.
- Подводные камни: баг в `userActivity.ts` проявлялся только на первом аутентифицированном запросе в минуту (throttle) — в проде мог давать sporadic 403.
---
## [0.7] Обработчик ошибок без утечки деталей
- Статус: ✅ done
- Зачем: клиент не должен видеть SQL и внутренности БД в 5xx-ответах (аудит, Фаза 0).
- Что изменено:
- `server/index.ts` — глобальный error handler: при status ≥ 500 отдаёт «Внутренняя ошибка сервера (код XXXXXXXX)», оригинальная ошибка — в серверный лог с тем же кодом инцидента. 4xx не тронуты.
- Route-уровень (12 файлов): зачищены все 5xx-ответы с `err.message`/`String(err)`/телом апстрима — `auth.users.routes.ts`, `form-offline.routes.ts`, `sync.routes.ts`, `polls.routes.ts`, `reactions.routes.ts`, `mcp-rag.routes.ts`, `llm-providers.routes.ts`, `external.routes.ts`, `task-crud-write.routes.ts`, `task-fields.routes.ts`, `finance-di2/routes.ts`, `documents/worker/server.ts`. Где не было — добавлен `console.error` с контекстом.
- Как проверялось: повторный grep `status(5xx)` + `err.message` по `server/` — 0 совпадений; `npm run check` чисто; `npx vitest run` 45/45.
- Влияние на поиск/UX: нет (только тексты 5xx-ответов).
- Подводные камни: остались ответы `200 + success:false` с `err?.message` (llm-providers, rag, finance-di2) и 4xx с `err.message` (documents, data-tables) — сознательно вне скоупа шага, кандидаты для фазы 2.