internal/policy: deklarativer, DB-gehaltener Regelsatz (policy_rules) statt hartcodierter Go-Entscheidungslogik — Store.IsAllowed schaut ausschliesslich in die Datenbank, kein Go-Fallback. Ein Regelwechsel (Grant/Revoke) wirkt sich sofort aus, ohne Codeaenderung/Deploy (Akzeptanzkriterium 3). Jede Aenderung wird atomar mit einem versionierten Historieneintrag in policy_rule_changes festgehalten (grant/revoke, Akteur, Version). Enforcer.Authorize ist Default-Deny: existiert keine Regel fuer role+ permission, ist der Zugriff verboten (Akzeptanzkriterium 2), fuer sich genommen ohne Anwendungslogik testbar. Guard/GuardTenantScoped sind die zentrale Enforcement-Funktion (Akzeptanzkriterium 1): die uebergebene Query-Funktion wird NUR bei erfolgreicher Autorisierung aufgerufen — es gibt keinen Weg, Daten ohne vorherige Authorize-Entscheidung zu erhalten. GuardTenantScoped erzwingt zusaetzlich per Funktionssignatur, dass tenantSlug TEIL der Query-Funktion ist (Akzeptanzkriterium 3) — ein nachgelagerter Post-Filter (der archivmail-Fehler aus "Bekannte Fehler vermeiden": Tenant-Filter nach statt in der Query) ist mit dieser Signatur strukturell nicht moeglich, da die Repository-Implementierung tenantSlug selbst fuer ihre eigene WHERE-Klausel entgegennimmt. Pruefungen (ausgefuehrt auf root@192.168.1.131, go build/vet/test PASS): 1. Kein Datenzugriffs-Pfad umgeht die zentrale Enforcement-Schicht — TestGuard_NeverCallsQueryWithoutAuthorization: query-Funktion wird nachweislich NICHT aufgerufen ohne vorherige Regel, erst nach Grant. PASS. 2. Anfrage ohne passende Policy wird zuverlaessig abgewiesen (Default-Deny) — TestAuthorize_DefaultDeny: keine Regel konfiguriert -> ErrDenied, nicht automatisch erlaubt. PASS. 3. Policy-Regelsatz versioniert, Regelwechsel ohne Codeaenderung nachvollziehbar — TestGrantRevoke_ChangesBehaviorWithoutCodeChange: Verhalten aendert sich durch reinen Datenbank-Grant/Revoke, Historie zeigt beide Versionen korrekt. PASS. Zusaetzlich: TestGuardTenantScoped_IsolatesDataBetweenTenants belegt das Tenant-Scoping-Muster aus Akzeptanzkriterium 3 konkret anhand zweier Tenants. PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
25 lines
978 B
SQL
25 lines
978 B
SQL
-- Zentrale, deklarative Policy-Regeln (RBAC-02, siehe core-kanban/tickets/RBAC-02.md).
|
|
-- policy_rules haelt den AKTUELLEN, gewaehrten Regelsatz (Existenz = erlaubt,
|
|
-- Default-Deny fuer alles ohne Zeile). policy_rule_changes ist die
|
|
-- versionierte Aenderungshistorie (Akzeptanzkriterium 3: Regelwechsel ohne
|
|
-- Codeaenderung nachvollziehbar).
|
|
CREATE TABLE policy_rules (
|
|
role TEXT NOT NULL,
|
|
permission TEXT NOT NULL,
|
|
granted_by TEXT NOT NULL,
|
|
granted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
PRIMARY KEY (role, permission)
|
|
);
|
|
|
|
CREATE TABLE policy_rule_changes (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
role TEXT NOT NULL,
|
|
permission TEXT NOT NULL,
|
|
action TEXT NOT NULL CHECK (action IN ('grant', 'revoke')),
|
|
actor TEXT NOT NULL,
|
|
version INT NOT NULL,
|
|
changed_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX policy_rule_changes_idx ON policy_rule_changes (role, permission, version);
|