feat(quick-260914-eym): forSystem(), is_system_context(), Systemleseregel auf fuenf Tabellen, DKV-Planer je Mandant — ein Pfad (WINDOWS #21)
- Helfer forSystem(prisma) in prisma-tenant.extension.ts (Array-Form, setzt app.system_context='true' und die beiden anderen Variablen ausdruecklich leer); forTenant()/withTenantTransaction() setzen app.system_context='' als Literal (4 neue Spec-Tests) - Migration 20260914120000_rls_system_context_read: is_system_context() (COALESCE, STABLE) und system_read_policy FOR SELECT auf DkvModuleConfig, LdapConfig, LdapFieldMapping, TenderMatch, TenderSavedSearch — lokal angewendet (36 Migrationen, pg_proc 1, 5 system_read_policy, 34 Regeln) - migration-sql.spec.ts: describe-Block fuer die neue Migration (6 Tests) - rls-scratch-check.mjs: Funktion aus der Migration geschnitten, forSystemQuery/buildInlineSystemClient, Reset in forTenantQuery/ buildInlineExtendedClient, runSystemContextChecks (4 Funktionsfaelle + 9 Kennungen DkvModuleConfig) -> Alle 216 Pruefungen bestanden - rls-access-inventory.spec.ts: fuenfte Erkennungsform const X = forSystem(, Stand system-gebunden mit Vorrangregel, FORSYSTEM_ALLOWED_CALL_SITES (exakte Zahl je Datei, 3 Tests), Proben C/D/E - DKV: loadActiveConfigsForScheduler() ueber forSystem (findMany isActive, CONFIG_SAFE_SELECT, orderBy tenantId); DkvSchedulerService mit Auftrag je Mandant dkv-inbox-poll:<tenantId>, activeTenantId ersatzlos entfernt, setInterval/stopJob je Mandant, registeredTenantIds(); Controller stopJob(tenantId); neue dkv-scheduler.service.spec.ts (7 Tests), dkv.service.spec.ts Tests 6/7 umgestellt - Klassifikation: dkv.service.ts/dkvModuleConfig system-gebunden, Header mit fuenfter Erkennungsform und viertem Stand-Wert - Baseline: 63 Dateien / 1051 Tests, tsc 0, Werkzeug 216 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
This commit is contained in:
@@ -255,6 +255,67 @@ describe('rls_user_dimension_personal_tables migration.sql (Etappe 3b, 260911-nk
|
||||
});
|
||||
});
|
||||
|
||||
describe('rls_system_context_read migration.sql (Etappe 3c, 260914-eym)', () => {
|
||||
const sql = readMigrationSql('_rls_system_context_read');
|
||||
const SYSTEM_READ_TABLES = ['DkvModuleConfig', 'LdapConfig', 'LdapFieldMapping', 'TenderMatch', 'TenderSavedSearch'];
|
||||
const NOT_OPENED_TABLES = ['SmtpConfig', 'Tenant', 'Tender'];
|
||||
|
||||
function nonCommentLines(source: string): string {
|
||||
return source
|
||||
.split('\n')
|
||||
.filter((line) => !line.trim().startsWith('--'))
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function policyStatements(source: string): string[] {
|
||||
return (nonCommentLines(source).match(/CREATE POLICY [\w]+ ON "[A-Za-z]+"[\s\S]*?;/g) ?? []).map((stmt) =>
|
||||
stmt.replace(/\s+/g, ' '),
|
||||
);
|
||||
}
|
||||
|
||||
it('legt is_system_context() mit COALESCE an (ohne Variable FALSE, nicht NULL)', () => {
|
||||
expect(sql).toContain('CREATE OR REPLACE FUNCTION is_system_context() RETURNS BOOLEAN AS $$');
|
||||
expect(sql).toContain("COALESCE(current_setting('app.system_context', true) = 'true', false)");
|
||||
expect(sql).toContain('LANGUAGE sql STABLE');
|
||||
});
|
||||
|
||||
it('legt genau fuenf CREATE POLICY system_read_policy an, je eine fuer die fuenf Tabellen', () => {
|
||||
const stmts = policyStatements(sql);
|
||||
expect(stmts).toHaveLength(5);
|
||||
for (const table of SYSTEM_READ_TABLES) {
|
||||
const forTable = stmts.filter((stmt) => stmt.startsWith(`CREATE POLICY system_read_policy ON "${table}"`));
|
||||
expect(forTable, table).toHaveLength(1);
|
||||
}
|
||||
});
|
||||
|
||||
it('jede system_read_policy ist FOR SELECT mit USING (is_system_context())', () => {
|
||||
const stmts = policyStatements(sql);
|
||||
expect(stmts).toHaveLength(5);
|
||||
for (const stmt of stmts) {
|
||||
expect(stmt).toContain('FOR SELECT');
|
||||
expect(stmt).toContain('USING (is_system_context())');
|
||||
expect(stmt).not.toContain('WITH CHECK');
|
||||
}
|
||||
});
|
||||
|
||||
it('enthaelt kein DROP POLICY (bestehende Regeln bleiben unveraendert)', () => {
|
||||
expect(nonCommentLines(sql)).not.toContain('DROP POLICY');
|
||||
});
|
||||
|
||||
it('enthaelt KEINE Anweisung auf SmtpConfig/Tenant/Tender ausserhalb von Kommentaren', () => {
|
||||
const codeOnly = nonCommentLines(sql);
|
||||
expect(codeOnly).not.toContain('SmtpConfig');
|
||||
for (const table of NOT_OPENED_TABLES) {
|
||||
expect(codeOnly).not.toContain(`"${table}"`);
|
||||
}
|
||||
});
|
||||
|
||||
it('nennt SmtpConfig im Kopf als bewusst nicht enthalten (Startpfad entfernt, nicht umgestellt)', () => {
|
||||
expect(sql).toContain('Keine Regel auf SmtpConfig');
|
||||
expect(sql).toContain('ENTFERNT');
|
||||
});
|
||||
});
|
||||
|
||||
describe('add_group_internal_name_and_object_guid migration.sql (D-04)', () => {
|
||||
const sql = readMigrationSql('_add_group_internal_name_and_object_guid');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user