feat(db): crm_supplier_worker BYPASSRLS-роль для queue worker (Plan 2.6 #iv)
Закрывает CV.11 audit WARN minor #2 + #3 (LeadRouter + ResetDeliveredTodayCommand под crm_app_user → RLS-policy tenant_isolation отвергает cross-tenant SELECT/UPDATE). Архитектурное решение (Plan 2.6 brainstorm 10.05.2026 поздняя ночь, вариант C из 3 опций): новая PG-роль crm_supplier_worker с BYPASSRLS — privilege-boundary by design. Queue worker = backend system process для cross-tenant операций (sharing-webhook routing, global crons); web worker остаётся под crm_app_user (RLS-enforce). WHERE(tenant_id=) фильтры в коде сохраняются как defense-in-depth. Deploy: - Роль создаётся через db/00_create_roles.sql при первом deploy (psql -v crm_supplier_worker_password='<from-secrets>' ...). - GRANT'ы в db/02_grants.sql секция 5. - Queue worker .env: DB_USERNAME=crm_supplier_worker (отдельно от web .env). Inline-warnings обновлены в LeadRouter.php + ResetDeliveredTodayCommand.php (ссылка на crm_supplier_worker BYPASSRLS на prod, db/00_create_roles.sql). 00_create_roles.sql header bump v1.0 → v1.1 (4 → 5 ролей). Без TDD-теста на роль (integration-тест требует CREATE ROLE в test DB + смены connection — overhead не оправдан); smoke-grep verify пройден. Pest 558/556 (+9 от Plan 2.5 baseline 549/547), Larastan + Pint + squawk green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,10 @@ use Illuminate\Support\Facades\DB;
|
||||
* Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §6.1.
|
||||
* Расписание: каждый день в 00:00 МСК (timezone Europe/Moscow).
|
||||
*
|
||||
* NB: tenant-scoped запрос без RLS — UPDATE сразу на все tenant'ы.
|
||||
* dev=postgres BYPASSRLS / prod=elevated role при выполнении из Scheduler'а.
|
||||
* NB: tenant-scoped запрос без RLS — UPDATE сразу на все tenant'ы. На production
|
||||
* queue worker (через Scheduler) запускается под ролью crm_supplier_worker
|
||||
* (BYPASSRLS) — Plan 2.6 fix #iv. На dev подключение под postgres (BYPASSRLS
|
||||
* implicit). См. db/00_create_roles.sql.
|
||||
*/
|
||||
class ResetDeliveredTodayCommand extends Command
|
||||
{
|
||||
|
||||
@@ -25,8 +25,9 @@ use InvalidArgumentException;
|
||||
*
|
||||
* RLS-quirk: запрос работает поверх N tenant'ов одновременно (sharing-model).
|
||||
* Не использует SET LOCAL app.current_tenant_id (в sharing-flow tenant ещё не определён —
|
||||
* запрос подбирает кандидатов из всех tenant'ов параллельно). Полагается на
|
||||
* dev=postgres BYPASSRLS / prod=elevated role при выполнении из job'а.
|
||||
* запрос подбирает кандидатов из всех tenant'ов параллельно). На production queue worker
|
||||
* запускается под ролью crm_supplier_worker (BYPASSRLS) — Plan 2.6 fix #iv. На dev
|
||||
* подключение под postgres (BYPASSRLS implicit). См. db/00_create_roles.sql.
|
||||
*
|
||||
* Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §6
|
||||
*/
|
||||
|
||||
+22
-2
@@ -1,7 +1,10 @@
|
||||
-- =============================================================================
|
||||
-- 00_create_roles.sql — создание 4 ролей PostgreSQL для Лидерры
|
||||
-- 00_create_roles.sql — создание 5 ролей PostgreSQL для Лидерры
|
||||
-- =============================================================================
|
||||
-- Версия: 1.0 (08.05.2026, фаза 1 backend multi-tenant фундамент)
|
||||
-- Версия: 1.1 (10.05.2026, Plan 2.6 fix #iv — добавлена роль crm_supplier_worker
|
||||
-- BYPASSRLS для backend queue worker, sharing-flow webhook routing
|
||||
-- + global crons; brainstorm decision вариант C)
|
||||
-- Версия 1.0 (08.05.2026, фаза 1 backend multi-tenant фундамент) — 4 роли.
|
||||
-- Источник: schema.sql v8.5 §13 «Роли БД (CTO-5)» (закомментированные DDL)
|
||||
-- =============================================================================
|
||||
--
|
||||
@@ -17,6 +20,7 @@
|
||||
-- -v crm_admin_password='<from-secrets>' \
|
||||
-- -v crm_migrator_password='<from-secrets>' \
|
||||
-- -v crm_audit_writer_password='<from-secrets>' \
|
||||
-- -v crm_supplier_worker_password='<from-secrets>' \
|
||||
-- -f db/00_create_roles.sql
|
||||
--
|
||||
-- ПОСЛЕ: запустить миграции под `crm_migrator` (BYPASSRLS, CREATEDB):
|
||||
@@ -51,3 +55,19 @@ CREATE ROLE crm_migrator
|
||||
CREATE ROLE crm_audit_writer
|
||||
LOGIN
|
||||
PASSWORD :'crm_audit_writer_password';
|
||||
|
||||
-- Роль backend queue worker для cross-tenant операций (Plan 2.6 fix #iv).
|
||||
-- BYPASSRLS by design: queue worker = system process, обрабатывает sharing-flow
|
||||
-- webhook routing (RouteSupplierLeadJob — N tenant'ов параллельно) и global
|
||||
-- crons (projects:reset-delivered-today, supplier:check-webhook-secret).
|
||||
-- Web worker остаётся под crm_app_user (RLS-enforce).
|
||||
-- WHERE(tenant_id=) фильтры в коде сохраняются как defense-in-depth даже под
|
||||
-- BYPASSRLS-ролью. См. RouteSupplierLeadJob::createDealCopyForProject lines 161-164
|
||||
-- (lockForUpdate Tenant + явный tenant_id фильтр перед каждым INSERT/UPDATE).
|
||||
-- Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §6.
|
||||
-- Brainstorm decision: вариант C из 3 опций (A=elevated DB-connection /
|
||||
-- B=RLS WITH-CHECK exception / C=BYPASSRLS-роль). См. memory project_supplier_integration.md.
|
||||
CREATE ROLE crm_supplier_worker
|
||||
LOGIN
|
||||
PASSWORD :'crm_supplier_worker_password'
|
||||
BYPASSRLS;
|
||||
|
||||
@@ -110,3 +110,25 @@ ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT ALL PRIVILEGES ON TABLES TO crm_migrator;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT ALL PRIVILEGES ON SEQUENCES TO crm_migrator;
|
||||
|
||||
-- =============================================================================
|
||||
-- 5. crm_supplier_worker — backend queue worker (BYPASSRLS) — Plan 2.6 fix #iv
|
||||
-- =============================================================================
|
||||
-- Для запуска `php artisan queue:work` под отдельным .env (отдельным от web).
|
||||
-- Cross-tenant операции: sharing-flow webhook routing (RouteSupplierLeadJob),
|
||||
-- global crons (projects:reset-delivered-today, supplier:check-webhook-secret).
|
||||
-- Web worker остаётся под crm_app_user (RLS-enforce). WHERE(tenant_id=) фильтры
|
||||
-- в коде сохраняются как defense-in-depth даже под BYPASSRLS-ролью.
|
||||
--
|
||||
-- Brainstorm decision (10.05.2026 поздняя ночь): вариант C из 3 опций
|
||||
-- (A=elevated DB-connection / B=RLS WITH-CHECK exception / C=BYPASSRLS-роль).
|
||||
|
||||
GRANT USAGE ON SCHEMA public TO crm_supplier_worker;
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_supplier_worker;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_supplier_worker;
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_supplier_worker;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA public
|
||||
GRANT USAGE, SELECT ON SEQUENCES TO crm_supplier_worker;
|
||||
|
||||
Reference in New Issue
Block a user