test(db): pin runbook 8.2 queries and QUE-04 log assumptions in pgTAP (KAT-01, 3a)
Adds the unchanged runbook queries (rolconfig, pg_available_extensions, pg_settings) and asserts the settings that keep search terms out of logs. katalog-pflege 8.2 now states that the three log settings depend on each other. Refs #3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0cbe813e5b
commit
c8bbd10d37
2 changed files with 24 additions and 2 deletions
|
|
@ -568,5 +568,5 @@ Bei einer Abweichung die betroffenen Spalten **per neuer Migration** entfernen u
|
|||
|
||||
- **Ohne Anmeldung aufrufbar:** `search_catalog_games` ist für `anon` ausführbar. Die Eingabegrenzen der Funktion (100 Zeichen, 10 Wörter, höchstens 20 IDs je Filter, Seitengröße 50) begrenzen die Last je Aufruf; zusätzlich gelten die `statement_timeout`-Werte der Rollen `anon` und `authenticated` (lokal 3 s und 8 s; im Self-Hosting prüfen, `select rolname, rolconfig from pg_roles where rolname in ('anon', 'authenticated')`). Ein `set statement_timeout` an der Funktion wirkt nicht.
|
||||
- **Mengenbegrenzung je IP (Entscheidung vor dem Go-live, Aufgabe D1):** Das eigentliche Risiko sind viele parallele Aufrufe ohne Anmeldung. Für R1.1 ist eine Begrenzung kein Muss; vor dem Go-live entscheidet devops, ob das Kong-Plugin `rate-limiting` auf `/rest/v1/rpc/search_catalog_games` oder `limit_req` im vorgelagerten Proxy gesetzt wird, und trägt das in das Hosting-Runbook ein.
|
||||
- **Suchbegriffe nicht protokollieren (QUE-04):** Die App sendet den Suchbegriff per `POST` im Anfragekörper (nicht in der URL). In den Datenbank-Einstellungen dürfen `log_min_duration_statement`, `log_statement` und `log_parameter_max_length*` Parameterwerte nicht in die Protokolle schreiben; `auto_explain.log_min_duration` und `pgaudit.log_parameter` ebenfalls nicht. Lokal geprüfte Werte und die Abweichungen stehen in der Beschreibung von PR 3a; auf Staging/Produktion mit `select name, setting from pg_settings where name in ('log_min_duration_statement', 'log_statement', 'log_parameter_max_length', 'log_parameter_max_length_on_error', 'auto_explain.log_min_duration', 'pgaudit.log', 'pgaudit.log_parameter')` prüfen.
|
||||
- **Suchbegriffe nicht protokollieren (QUE-04):** Die App sendet den Suchbegriff per `POST` im Anfragekörper (nicht in der URL); PostgREST reicht ihn als JSON-Parameter `$1` an die Datenbank. Drei Einstellungen müssen **zusammen** geprüft werden, weil sie voneinander abhängen: (1) `log_parameter_max_length_on_error = 0`, sonst stünde der Begriff im Fehlerprotokoll (Fehler wie `search_query_too_long` erscheinen lokal nur mit dem Platzhalter `$1`); (2) `log_min_duration_statement = -1`, `log_statement` höchstens `ddl`, `pgaudit.log = none`; (3) `auto_explain.log_min_duration` (lokal 10 s, mit `auto_explain.log_parameter_max_length = -1`, also **mit** Parameterwerten) muss **größer** sein als das längste `statement_timeout` der Rollen `anon` und `authenticated` (lokal 3 s und 8 s): Eine Suche, die das Zeitlimit erreicht, wird abgebrochen und erzeugt keine auto_explain-Ausgabe. Wird das Zeitlimit von `authenticated` über 10 s angehoben (oder `auto_explain.log_min_duration` gesenkt), landen Suchbegriffe im Protokoll. Prüfung auf Staging/Produktion: `select name, setting from pg_settings where name in ('log_min_duration_statement', 'log_statement', 'log_parameter_max_length', 'log_parameter_max_length_on_error', 'auto_explain.log_min_duration', 'pgaudit.log', 'pgaudit.log_parameter')`. Lokal bestätigt (Aufruf per `curl` gegen Kong, Datenbank- und PostgREST-Protokoll enthalten den Begriff nicht); Hetzner ist **nicht** geprüft.
|
||||
- **Erweiterungen:** `select * from pg_available_extensions where name in ('pg_trgm', 'unaccent')` muss auf Staging/Produktion beide Zeilen liefern, bevor die Migration `catalog_search` eingespielt wird.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
-- Ohne Suchbegriff wird nur auf Fixture-IDs geprüft (Hilfsfunktion pg_temp.hits blättert durch).
|
||||
-- Die Include-Dateien in ../support/ (\ir) erzeugt supabase/catalog/build_startbestand.ts.
|
||||
begin;
|
||||
select plan(211);
|
||||
select plan(217);
|
||||
|
||||
insert into auth.users (id, email, raw_user_meta_data) values
|
||||
('11111111-1111-1111-1111-111111111111', 'anna@example.com', '{"age_confirmed":"true","terms_accepted":"true","terms_version":"test","display_name":"Anna"}'),
|
||||
|
|
@ -796,6 +796,28 @@ union all select 'publishers', count(*) from public.publishers
|
|||
$$values ('games'::text, 0::bigint), ('game_alt_titles', 0), ('publishers', 0)$$,
|
||||
'Runbook 8: die Prüfabfrage meldet bei unverändertem Stand überall 0 Abweichungen');
|
||||
|
||||
-- ---------------------------------------------------------------------------------------------
|
||||
-- Abschnitt 8.2 des Runbooks: Betrieb (Prüfabfragen unverändert, dazu die Annahmen für QUE-04)
|
||||
-- ---------------------------------------------------------------------------------------------
|
||||
select set_eq($$select rolname, rolconfig from pg_roles where rolname in ('anon', 'authenticated')$$,
|
||||
$$select rolname, rolconfig from pg_roles where rolname in ('anon', 'authenticated') and exists (select 1 from unnest(rolconfig) c where c like 'statement_timeout=%')$$,
|
||||
'Runbook 8.2: anon und authenticated haben ein statement_timeout in rolconfig');
|
||||
select is((select count(*) from pg_available_extensions where name in ('pg_trgm', 'unaccent')), 2::bigint,
|
||||
'Runbook 8.2: pg_trgm und unaccent sind verfügbar (select * from pg_available_extensions …)');
|
||||
select is((select count(*) from pg_settings where name in ('log_min_duration_statement', 'log_statement', 'log_parameter_max_length', 'log_parameter_max_length_on_error', 'auto_explain.log_min_duration', 'pgaudit.log', 'pgaudit.log_parameter')), 7::bigint,
|
||||
'Runbook 8.2: die sieben Protokoll-Einstellungen der Prüfabfrage sind abfragbar');
|
||||
select is((select setting from pg_settings where name = 'log_parameter_max_length_on_error'), '0',
|
||||
'QUE-04: bei Fehlern werden keine Parameterwerte protokolliert (Suchbegriffe im JSON-Parameter von PostgREST)');
|
||||
select ok((select setting from pg_settings where name = 'log_statement') in ('none', 'ddl')
|
||||
and (select setting from pg_settings where name = 'log_min_duration_statement') = '-1'
|
||||
and (select setting from pg_settings where name = 'pgaudit.log') = 'none'
|
||||
and (select setting from pg_settings where name = 'pgaudit.log_parameter') = 'off',
|
||||
'QUE-04: weder Anweisungen mit Parametern (log_statement, log_min_duration_statement, pgaudit) noch langsame Anweisungen werden protokolliert');
|
||||
select ok((select max((regexp_match(c, '^statement_timeout=(\d+)s$'))[1]::int) * 1000
|
||||
from pg_roles r, unnest(r.rolconfig) c where r.rolname in ('anon', 'authenticated') and c like 'statement_timeout=%')
|
||||
< (select setting::int from pg_settings where name = 'auto_explain.log_min_duration'),
|
||||
'QUE-04: auto_explain (mit Parametern) greift erst nach dem längsten Zeitlimit der API-Rollen, eine abgebrochene Suche erscheint also nie im Protokoll');
|
||||
|
||||
-- Drift simulieren: Die Funktion wird geändert, die gespeicherten Spalten bleiben (wie nach einem Image-Upgrade)
|
||||
create or replace function public.search_normalize(p text) returns text language sql immutable strict parallel safe set search_path = ''
|
||||
as $$ select upper(p) $$;
|
||||
|
|
|
|||
Loading…
Reference in a new issue