Files
portal/db/02_grants.sql
T
Дмитрий f502b0058d phase1(backend): multi-tenant фундамент развёрнут — schema v8.5→v8.6 + migrate:fresh
Backend multi-tenant фундамент развёрнут на dev-БД liderra: 68 таблиц
(52 обычных + 16 партиций) + 36 RLS-policies + 5 функций + 13 триггеров.
`php artisan migrate:fresh` за 870 ms через одну raw-SQL миграцию
`load_initial_schema.php` (DB::unprepared с db/schema.sql).

Первый реальный запуск schema.sql на pristine PG 16 поймал 2
несовместимости v8.5, исправлены архитектурно (CTO-17):

1. CREATE UNIQUE INDEX на партиционированной deals (schema:1263)
   PG требует partition key (received_at) в UNIQUE; включить нельзя —
   ломает идемпотентность webhook'ов. Решение: новая таблица
   webhook_dedup_keys (не партиционированная, PK (tenant_id, source_crm_id)
   → deal_id, composite FK на deals(id, received_at) ON DELETE CASCADE,
   RLS tenant_isolation USING+WITH CHECK). UNIQUE INDEX в deals
   заменён на обычный. Webhook handler — двустадийная UPSERT.

2. GENERATED ALWAYS AS на pd_subject_requests.deadline_at (schema:1999)
   `+ INTERVAL '30 days'` не immutable. Решение: обычная TIMESTAMPTZ
   NOT NULL + триггер trg_pd_subject_requests_deadline + функция
   set_pd_subject_request_deadline().

Изменения:

- db/schema.sql: v8.5 → v8.6 (заголовок, 1 новая таблица, 1 RLS-policy,
  1 функция, 1 триггер, замена UNIQUE на обычный INDEX, замена GENERATED
  на TIMESTAMPTZ NOT NULL)
- db/CHANGELOG_schema.md: новая запись §X v8.5→v8.6
- db/00_create_roles.sql (NEW): deployment-скрипт 4 ролей PG для production
  (crm_app_user, crm_admin_user BYPASSRLS, crm_migrator BYPASSRLS+CREATEDB,
  crm_audit_writer). На dev — postgres superuser (schema §13 разрешает)
- db/02_grants.sql (NEW): GRANT/REVOKE из закомментированных секций §13
  schema. REVOKE на 6 saas-таблицах для crm_app_user (defense-in-depth
  поверх RLS, OPEN-И-14). REVOKE DELETE на 4 финансовых таблицах для
  crm_admin_user (только soft markers)
- app/database/migrations: удалены 3 default Laravel (users/cache/jobs
  дублировались с нашей schema), создан 0001_01_01_000000_load_initial_schema.php
- .squawk.toml: + excluded_paths для db/00_create_roles.sql (psql client-side
  variables :'name' не парсятся libpg_query)
- docs/Открытые_вопросы_v8_3.md: v1.18 → v1.19, CTO-17 закрыт фиксом,
  70  / 5 🟦 / 4 ⏸. Техдолг: ТЗ §15-16 webhook handler нужно обновить
  под двустадийную dedup-логику
- CLAUDE.md: v1.9 → v1.10 (§0 ссылки на schema v8.6 + реестр v1.19;
  §2 метрики БД 54→55/91→92/35→36/12→13/4→5; §6 фундамент развёрнут)
- cspell-words.txt: +9 новых терминов

Smoke-test через Boost MCP database-query:
- 68 таблиц (включая webhook_dedup_keys + 16 партиций)
- 36 RLS-policies
- 35 RLS-enabled (relkind='r'; +2 partitioned 'p' = 37 total)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 13:48:24 +03:00

113 lines
6.5 KiB
SQL

-- =============================================================================
-- 02_grants.sql — GRANT/REVOKE для 4 ролей Лидерры
-- =============================================================================
-- Версия: 1.0 (08.05.2026, фаза 1 backend multi-tenant фундамент)
-- Источник: schema.sql v8.5 §13 «Роли БД (CTO-5)» + §14 «АУДИТ APPEND-ONLY»
-- =============================================================================
--
-- НАЗНАЧЕНИЕ: deployment-скрипт для production. Запускается ПОСЛЕ:
-- 1. db/00_create_roles.sql — роли созданы
-- 2. db/schema.sql — таблицы/индексы/RLS-политики созданы (через `php artisan migrate`)
--
-- ЗАПУСК:
-- psql -U postgres -h <host> -d liderra -f db/02_grants.sql
-- (требуется superuser, т.к. GRANT/REVOKE на чужие объекты)
--
-- ВНИМАНИЕ: на **dev-машине** этот файл НЕ запускается — schema.sql §13 разрешает
-- использовать суперпользователя `postgres` для разработки. RLS-политики работают
-- через `current_setting('app.current_tenant_id')::bigint` — независимо от роли.
-- =============================================================================
-- =============================================================================
-- 1. crm_app_user — tenant-уровень приложения (RLS активна)
-- =============================================================================
GRANT USAGE ON SCHEMA public TO crm_app_user;
-- SELECT/INSERT/UPDATE/DELETE на ВСЕ таблицы (RLS-политики ограничат доступ
-- к чужим tenant-данным; saas-таблицы дополнительно закрыты REVOKE ниже)
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_app_user;
-- USAGE на sequences (для BIGSERIAL nextval)
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_app_user;
-- Default privileges для будущих таблиц/sequences (после миграций)
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_app_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO crm_app_user;
-- v8.5 (OPEN-И-14) defense-in-depth: REVOKE ALL на 6 saas-таблицах.
-- К этим таблицам tenant-приложение НЕ должно иметь доступа даже теоретически
-- (RLS + REVOKE = 2 барьера).
REVOKE ALL ON saas_admin_users FROM crm_app_user;
REVOKE ALL ON saas_admin_sessions FROM crm_app_user;
REVOKE ALL ON saas_admin_audit_log FROM crm_app_user;
REVOKE ALL ON incidents_log FROM crm_app_user;
REVOKE ALL ON pd_subject_requests FROM crm_app_user;
REVOKE ALL ON impersonation_tokens FROM crm_app_user;
-- =============================================================================
-- 2. crm_admin_user — администрирование SaaS (BYPASSRLS)
-- =============================================================================
GRANT USAGE ON SCHEMA public TO crm_admin_user;
-- ВСЕ права crm_app_user + доступ к saas_admin_*, supplier_*, system_settings,
-- tariff_plans, legal_entities, payment_gateways
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO crm_admin_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO crm_admin_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO crm_admin_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO crm_admin_user;
-- Запрет DELETE на финансовых таблицах (только soft markers через UPDATE):
REVOKE DELETE ON balance_transactions FROM crm_admin_user;
REVOKE DELETE ON supplier_invoices FROM crm_admin_user;
REVOKE DELETE ON supplier_lead_costs FROM crm_admin_user;
REVOKE DELETE ON tenant_subscriptions FROM crm_admin_user;
-- =============================================================================
-- 3. crm_audit_writer — append-only audit (INSERT-only)
-- =============================================================================
-- UPDATE/DELETE дополнительно блокируются триггерами audit_block_mutation
-- (schema.sql §14). Двухслойная защита от tampering.
GRANT USAGE ON SCHEMA public TO crm_audit_writer;
GRANT INSERT ON auth_log TO crm_audit_writer;
GRANT INSERT ON activity_log TO crm_audit_writer;
GRANT INSERT ON pd_processing_log TO crm_audit_writer;
GRANT INSERT ON saas_admin_audit_log TO crm_audit_writer;
GRANT INSERT ON balance_transactions TO crm_audit_writer;
GRANT USAGE ON SEQUENCE auth_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE activity_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE pd_processing_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE saas_admin_audit_log_id_seq TO crm_audit_writer;
GRANT USAGE ON SEQUENCE balance_transactions_id_seq TO crm_audit_writer;
-- crm_audit_writer НЕ имеет SELECT/UPDATE/DELETE/TRUNCATE — это специально.
-- Явно отзываем дефолтные привилегии PUBLIC, если такие есть:
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON auth_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON activity_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON pd_processing_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON saas_admin_audit_log FROM crm_audit_writer;
REVOKE SELECT, UPDATE, DELETE, TRUNCATE ON balance_transactions FROM crm_audit_writer;
-- =============================================================================
-- 4. crm_migrator — runtime миграций (BYPASSRLS, CREATEDB)
-- =============================================================================
-- Для запуска `php artisan migrate` в production без ослабления RLS.
GRANT USAGE, CREATE ON SCHEMA public TO crm_migrator;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO crm_migrator;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO crm_migrator;
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;