feat(quick-260909-dgj): Pruefwerkzeug fuer den Nachweis plus Betriebsanleitung (Task 3/4)
- apps/api/scripts/rls-preflight.mjs misst fuenf benannte Eigenschaften (rollenrechte, kontext-setzbar, ohne-kontext-leer, mit-kontext-sichtbar, schreibrechte) jeweils in einer eigenen Transaktion gegen eine per TESSERA_PREFLIGHT_DATABASE_URL angegebene Verbindung; --print-plan verbindet nicht, das Werkzeug schreibt in keiner Betriebsart - 5 Tests in rls-preflight.spec.ts (rot vor dem Werkzeug, jetzt gruen) - docs/mandantentrennung-datenbankrolle.md: Befund, Sperrgrund (182 unskalierte Zugriffe, Anmeldeweg), Handgriffe des Betreibers samt Kennwortsetzung, Freigabebedingung und Rueckweg; docs/README.md verweist darauf Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
/**
|
||||
* Prueft apps/api/scripts/rls-preflight.mjs ausschliesslich in der
|
||||
* Pruefplan-Betriebsart (--print-plan) — es wird keine Datenbankverbindung
|
||||
* aufgebaut (Task 3, WINDOWS #18).
|
||||
*/
|
||||
|
||||
const SCRIPT_PATH = join(__dirname, '../../scripts/rls-preflight.mjs');
|
||||
|
||||
describe('rls-preflight.mjs --print-plan', () => {
|
||||
it('Test 1: endet mit Ende-Code 0, obwohl keine Verbindungsangabe in der Umgebung steht', () => {
|
||||
const stdout = execFileSync(process.execPath, [SCRIPT_PATH, '--print-plan'], {
|
||||
env: { PATH: process.env.PATH ?? '' },
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
expect(stdout).toBeTruthy();
|
||||
});
|
||||
|
||||
it('Test 2: nennt alle fuenf Pruefkennungen', () => {
|
||||
const stdout = execFileSync(process.execPath, [SCRIPT_PATH, '--print-plan'], {
|
||||
env: { PATH: process.env.PATH ?? '' },
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
for (const kennung of [
|
||||
'rollenrechte',
|
||||
'kontext-setzbar',
|
||||
'ohne-kontext-leer',
|
||||
'mit-kontext-sichtbar',
|
||||
'schreibrechte',
|
||||
]) {
|
||||
expect(stdout).toContain(kennung);
|
||||
}
|
||||
});
|
||||
|
||||
it('Test 3: nennt TESSERA_PREFLIGHT_DATABASE_URL als Quelle der zu pruefenden Verbindung', () => {
|
||||
const stdout = execFileSync(process.execPath, [SCRIPT_PATH, '--print-plan'], {
|
||||
env: { PATH: process.env.PATH ?? '' },
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
expect(stdout).toContain('TESSERA_PREFLIGHT_DATABASE_URL');
|
||||
});
|
||||
|
||||
it('Test 4: jede Pruefung laeuft innerhalb einer Transaktion ($transaction) — ausserhalb kann der Verbindungspool die Folgeabfrage auf eine andere Verbindung legen als die, auf der set_config gesetzt wurde, und die Messung waere wertlos', () => {
|
||||
const source = readFileSync(SCRIPT_PATH, 'utf-8');
|
||||
expect(source).toContain('$transaction');
|
||||
});
|
||||
|
||||
it('Test 5: das Werkzeug schreibt nicht — keines der Schluesselwoerter INSERT, UPDATE, DELETE, DROP, ALTER in einer SQL-Zeichenkette', () => {
|
||||
const source = readFileSync(SCRIPT_PATH, 'utf-8');
|
||||
const sqlStrings = source.match(/`[^`]*`/g) ?? [];
|
||||
for (const str of sqlStrings) {
|
||||
for (const verb of ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'ALTER']) {
|
||||
expect(str.toUpperCase()).not.toContain(verb);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user