c703d87a1c
- ownerUserId (NULL = gemeinsam, sonst persoenlich) mit Zeilenschutz nach Muster SearchProvider - GET nur gemeinsame + eigene, fremde persoenliche Eintraege 404 - POST fuer jeden Benutzer, shared nur fuer Administratoren (403) - PATCH/DELETE: persoenlich nur Besitzer, gemeinsam nur Administrator - Zugriffsklassifikation nachgemessen: 61/223/6 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
78 lines
3.2 KiB
SQL
78 lines
3.2 KiB
SQL
-- 260929-dzu — Eigene Module fuer jeden Benutzer: persoenliche Eintraege.
|
|
--
|
|
-- Zweck: jeder Benutzer darf eigene Seitenleisten-Eintraege anlegen, die nur
|
|
-- er selbst sieht. Die Spalte "ownerUserId" unterscheidet: NULL = gemeinsamer
|
|
-- Eintrag (vom Administrator, fuer alle sichtbar, bisheriges Verhalten),
|
|
-- gesetzt = persoenlicher Eintrag dieses Benutzers. Faellt der Benutzer weg,
|
|
-- fallen seine Eintraege mit (ON DELETE CASCADE). Bestehende Zeilen bleiben
|
|
-- gemeinsam (NULL).
|
|
--
|
|
-- Zeilenschutz: Muster "SearchProvider" (20260911120000_rls_user_dimension_
|
|
-- personal_tables) — Spalte mit NULL = gemeinsame Zeile. Die eine Regel
|
|
-- "tenant_isolation_policy" (aus 20260929120000, ohne Benutzerdimension) wird
|
|
-- durch vier nach Befehl getrennte Regeln ersetzt (Praezedenz 260910-jab (3)):
|
|
-- ein einzelner USING-Ausdruck, der die gemeinsame Zeile zum Lesen einschliesst,
|
|
-- wuerde sie sonst auch zum Aendern/Entfernen freigeben.
|
|
-- SELECT: Mandant UND (kein Benutzer gesetzt ODER gemeinsame Zeile ODER
|
|
-- eigene Zeile).
|
|
-- INSERT/UPDATE/DELETE: Mandant UND (kein Benutzer gesetzt ODER eigene
|
|
-- Zeile). Ein Benutzerkontext kann gemeinsame Zeilen also NICHT
|
|
-- schreiben; der Administrator-Weg fuer gemeinsame Eintraege bindet
|
|
-- deshalb ohne Benutzer (`forTenant(prisma, tenantId)`), die
|
|
-- Rollenpruefung liegt im Controller/Dienst.
|
|
-- Die Regelnamen sind neu (vier statt eine), rls-coverage.spec.ts fordert nur
|
|
-- mindestens eine Regel je Tabelle mit eingeschaltetem RLS.
|
|
--
|
|
-- Rechte fuer tessera_app kommen ueber ALTER DEFAULT PRIVILEGES aus
|
|
-- 20260909130000_rls_app_role — hier nichts zu tun.
|
|
--
|
|
-- WICHTIG: wie alle RLS-Regeln dieses Schemas wirken diese erst, wenn die
|
|
-- Anwendung als Rolle ohne Umgehungsrecht verbindet (Schalter heute AUS, siehe
|
|
-- docs/mandantentrennung-datenbankrolle.md). Bis dahin tragen die
|
|
-- Anwendungspruefungen im Dienst den Schutz allein.
|
|
|
|
ALTER TABLE "CustomModule" ADD COLUMN "ownerUserId" TEXT;
|
|
|
|
CREATE INDEX "CustomModule_tenantId_ownerUserId_idx" ON "CustomModule"("tenantId", "ownerUserId");
|
|
|
|
ALTER TABLE "CustomModule" ADD CONSTRAINT "CustomModule_ownerUserId_fkey"
|
|
FOREIGN KEY ("ownerUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
DROP POLICY tenant_isolation_policy ON "CustomModule";
|
|
|
|
CREATE POLICY tenant_user_read_policy ON "CustomModule"
|
|
FOR SELECT
|
|
USING (
|
|
"tenantId" = current_tenant_id()
|
|
AND (
|
|
current_user_id() IS NULL
|
|
OR "ownerUserId" IS NULL
|
|
OR "ownerUserId" = current_user_id()
|
|
)
|
|
);
|
|
|
|
CREATE POLICY tenant_user_insert_policy ON "CustomModule"
|
|
FOR INSERT
|
|
WITH CHECK (
|
|
"tenantId" = current_tenant_id()
|
|
AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id())
|
|
);
|
|
|
|
CREATE POLICY tenant_user_update_policy ON "CustomModule"
|
|
FOR UPDATE
|
|
USING (
|
|
"tenantId" = current_tenant_id()
|
|
AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id())
|
|
)
|
|
WITH CHECK (
|
|
"tenantId" = current_tenant_id()
|
|
AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id())
|
|
);
|
|
|
|
CREATE POLICY tenant_user_delete_policy ON "CustomModule"
|
|
FOR DELETE
|
|
USING (
|
|
"tenantId" = current_tenant_id()
|
|
AND (current_user_id() IS NULL OR "ownerUserId" = current_user_id())
|
|
);
|