fix(rls): startup-проверка schema drift — array_agg name[] приходит строкой
Шаг 0.1 (подготовка) плана production-готовности:
pg-драйвер возвращает name[] как "{a,b,c}" (нет парсера OID 1003) —
проверка находила 0 таблиц и запуск с ENABLE_RLS=true всегда падал.
Поддержаны оба формата. Проверено на копии прод-БД: app стартует,
31 таблица ENABLE+FORCE, login/search/sync работают
This commit is contained in:
@@ -416,3 +416,16 @@
|
|||||||
- Как проверялось: docker compose config валиден для всех 4 файлов и для бэкапа на сервере.
|
- Как проверялось: docker compose config валиден для всех 4 файлов и для бэкапа на сервере.
|
||||||
- Влияние на поиск/UX: нет.
|
- Влияние на поиск/UX: нет.
|
||||||
- Подводные камни: сумма лимитов ~6.3 ГБ > 5.9 ГБ RAM — лимиты это потолки, не резерв; ollama в простое 36 МБ. На проде лимиты применяются к app/document-worker при ближайшем деплое; остальные сервисы — при их пересоздании.
|
- Подводные камни: сумма лимитов ~6.3 ГБ > 5.9 ГБ RAM — лимиты это потолки, не резерв; ollama в простое 36 МБ. На проде лимиты применяются к app/document-worker при ближайшем деплое; остальные сервисы — при их пересоздании.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [0.1] RLS обязательным в production — подготовка и локальная проверка
|
||||||
|
|
||||||
|
- Статус: ⏸ частично (локальная проверка пройдена; прод-включение и fatal-проверка — после подтверждения пользователя)
|
||||||
|
- Зачем: изоляция tenant'ов на уровне БД (аудит, Фаза 0).
|
||||||
|
- Что сделано:
|
||||||
|
- Локальная проверка на КОПИИ прод-БД (scratch pgvector контейнер, свежий дамп): app стартует с ENABLE_RLS=true, 31 таблица ENABLE+FORCE, login/поиск (подстрока «варий»→«Аварийка»)/список задач (50, без description)/формы/sync работают, passwordHash не утекает.
|
||||||
|
- **Найден и исправлен блокирующий баг** в `server/index.ts` (startup RLS-проверка): pg-драйвер возвращает `array_agg(tablename)` (тип name[]) СТРОКОЙ "{tasks,users,...}", а не массивом — проверка schema drift находила 0 таблиц и падала при ЛЮБОМ запуске с ENABLE_RLS=true. Т.е. RLS нельзя было включить без этого фикса. Поддержаны оба формата.
|
||||||
|
- Что осталось (прод, с подтверждения): 1) добавить ENABLE_RLS=true в .env сервера и перезапустить app, проверить; 2) затем задеплоить fatal-проверку (NODE_ENV=production без ENABLE_RLS → процесс не стартует) + пометки в .env.example/DOCKER.md.
|
||||||
|
- Влияние на поиск/UX: нет.
|
||||||
|
- Подводные камни: порядок важен — fatal-проверку деплоить ТОЛЬКО после включения флага на проде, иначе app не поднимется.
|
||||||
|
|||||||
@@ -931,8 +931,15 @@ async function runStartupDataPatches() {
|
|||||||
FROM pg_tables
|
FROM pg_tables
|
||||||
WHERE schemaname = 'public' AND tablename IN (${tableList})
|
WHERE schemaname = 'public' AND tablename IN (${tableList})
|
||||||
`));
|
`));
|
||||||
|
// pg-драйвер возвращает name[] строкой "{tasks,users,...}" (нет парсера для OID 1003) —
|
||||||
|
// поддерживаем оба формата, иначе ни одна таблица не будет «найдена».
|
||||||
|
const rawFound = (existsCheck.rows[0] as Record<string, unknown>)?.found;
|
||||||
const foundTables = new Set<string>(
|
const foundTables = new Set<string>(
|
||||||
((existsCheck.rows[0] as Record<string, unknown>)?.found as string[] | null) ?? []
|
Array.isArray(rawFound)
|
||||||
|
? (rawFound as string[])
|
||||||
|
: typeof rawFound === "string"
|
||||||
|
? rawFound.replace(/^\{|\}$/g, "").split(",").filter(Boolean)
|
||||||
|
: []
|
||||||
);
|
);
|
||||||
const missingTables = ALL_RLS_TABLES.filter(t => !foundTables.has(t));
|
const missingTables = ALL_RLS_TABLES.filter(t => !foundTables.has(t));
|
||||||
if (missingTables.length > 0) {
|
if (missingTables.length > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user