From 639036c87ea53c7972e1fb19d23a66966d761d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=D1=81=20=D0=A1=D1=83=D0=BB=D1=82?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 8 Sep 2026 10:55:58 +0300 Subject: [PATCH] =?UTF-8?q?security(rls):=20ENABLE=5FRLS=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=8F=D0=B7=D0=B0=D1=82=D0=B5=D0=BB=D0=B5=D0=BD=20=D0=B2=20pro?= =?UTF-8?q?duction=20(fatal=20=D0=B1=D0=B5=D0=B7=20=D1=84=D0=BB=D0=B0?= =?UTF-8?q?=D0=B3=D0=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Шаг 0.1 (завершение) плана production-готовности: - прод: ENABLE_RLS=true включён, 31 таблица ENABLE+FORCE проверена - код: fatal при NODE_ENV=production без ENABLE_RLS - .env.example + DOCKER.md: пометки об обязательности --- .env.example | 5 +++++ DOCKER.md | 5 +++++ IMPLEMENTATION_LOG.md | 13 +++++++++++++ server/index.ts | 9 ++++++++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 2a76628..2d8d031 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,11 @@ VAPID_PRIVATE_KEY=your-vapid-private-key # SendGrid API key for transactional email (optional — app works without it) # SENDGRID_API_KEY=SG.xxxxxxxxxxxx +# Row Level Security (изоляция tenant'ов на уровне БД). +# ОБЯЗАТЕЛЬНО для production: без него процесс не стартует (fatal при NODE_ENV=production). +# В dev можно не задавать (safe default — политики существуют, но не активны). +# ENABLE_RLS=true + # ============================================= # Database — choose ONE of the two modes below # ============================================= diff --git a/DOCKER.md b/DOCKER.md index d306015..dbe9324 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -212,6 +212,11 @@ xxx... 3. Создаёт MinIO bucket если настроен S3 (автоматически) 4. Запускает сервер приложения (`npm run start`) +**Row Level Security (RLS):** при `ENABLE_RLS=true` на старте включается ENABLE+FORCE RLS +на 31 таблице с проверкой политик (schema drift, count политик) — при расхождении процесс падает. +**В production (`NODE_ENV=production`) `ENABLE_RLS=true` обязателен** — без него процесс не стартует. +В development флаг можно не задавать (политики существуют, но не активны). + --- ## Изменение схемы базы данных diff --git a/IMPLEMENTATION_LOG.md b/IMPLEMENTATION_LOG.md index acbce58..e71b6d5 100644 --- a/IMPLEMENTATION_LOG.md +++ b/IMPLEMENTATION_LOG.md @@ -429,3 +429,16 @@ - Что осталось (прод, с подтверждения): 1) добавить ENABLE_RLS=true в .env сервера и перезапустить app, проверить; 2) затем задеплоить fatal-проверку (NODE_ENV=production без ENABLE_RLS → процесс не стартует) + пометки в .env.example/DOCKER.md. - Влияние на поиск/UX: нет. - Подводные камни: порядок важен — fatal-проверку деплоить ТОЛЬКО после включения флага на проде, иначе app не поднимется. + +--- + +## [0.1] RLS обязательным в production — завершение + +- Статус: ✅ done +- Что сделано после локальной проверки (см. запись выше): + 1. Прод: бэкап БД (crm-20260908-075039.dump.gz), `ENABLE_RLS=true` в /opt/crm/.env, recreate app — старт-лог «Startup RLS: active — ENABLE+FORCE verified on 31 tables, 31 policies», health 200, поиск/списки через API работают. + 2. Код: `server/index.ts` — при NODE_ENV=production без ENABLE_RLS=true — fatal (процесс не поднимается); dev — предупреждение. + 3. Документация: `.env.example` (обязательность для production), `DOCKER.md` (sequence при старте + блок про RLS). +- Как проверялось: на проде подтверждено включение (pg_class relrowsecurity+relforcerowsecurity=31), smoke через API; локально — полный цикл на копии прод-БД. +- Влияние на поиск/UX: нет. +- Подводные камни: при переносе на новый сервер — сначала ENABLE_RLS=true в .env, иначе app не поднимется (это и есть цель шага). diff --git a/server/index.ts b/server/index.ts index 472aef1..a567301 100644 --- a/server/index.ts +++ b/server/index.ts @@ -985,8 +985,15 @@ async function runStartupDataPatches() { } log(`Startup RLS: active — ENABLE+FORCE verified on ${rlsVerified} tables, ${policyVerified} policies`); + } else if (process.env.NODE_ENV === "production") { + // Шаг 0.1: в production RLS обязателен — без изоляции tenant'ов на уровне БД + // процесс не поднимается. + throw new Error( + "Startup RLS: ENABLE_RLS=true is REQUIRED in production. " + + "Set ENABLE_RLS=true in the environment and restart." + ); } else { - log("Startup RLS: ENABLE_RLS not set — policies exist but inactive (safe default)"); + log("Startup RLS: ENABLE_RLS not set — policies exist but inactive (safe default, dev only)"); } const seedDir = path.resolve(