teecup/test_isolation.sql

90 lines
3.4 KiB
MySQL
Raw Normal View History

2026-07-16 07:26:04 +02:00
-- =====================================================================
-- TeeCup — isolasjonstest (oppførsel, ikke bare skjema)
-- =====================================================================
-- Beviser at RLS faktisk hindrer én organisasjon i å se en annens data,
-- sett fra runtime-rollen teecup_app (som IKKE er superuser/BYPASSRLS).
--
-- Kjør som admin/superbruker mot en scratch- eller test-database der
-- 001_initial_schema.sql og 002_roles_and_grants.sql allerede er kjørt:
-- psql -d teecup_scratch -f test_isolation.sql
--
-- Alt kjøres i én transaksjon som RULLES TILBAKE til slutt — ingen testdata
-- blir liggende igjen. Skriptet stopper med feil hvis isolasjonen svikter.
-- =====================================================================
\set ON_ERROR_STOP on
BEGIN;
-- --- Seed to organisasjoner + én turnering hver (som privilegert rolle) ---
-- (Superbruker omgår RLS, så innsettingen går uhindret her — det er meningen.)
INSERT INTO organization (id, name) VALUES
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Org A'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Org B');
INSERT INTO tournament (organization_id, name) VALUES
('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'A-Cup'),
('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'B-Cup');
-- --- Bytt til runtime-rollen: nå SKAL RLS gjelde ---------------------
SET ROLE teecup_app;
SELECT set_config('app.current_org', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', false);
-- Test 1: Ser bare Org A sine turneringer (1, ikke 2).
DO $$
DECLARE n int;
BEGIN
SELECT count(*) INTO n FROM tournament;
IF n <> 1 THEN
RAISE EXCEPTION 'ISOLASJON FEILET (lesing): ser % turneringer, forventet 1', n;
END IF;
RAISE NOTICE 'OK Test 1: ser kun egen organisasjons turneringer (%).', n;
END $$;
-- Test 2: Ser bare sin egen organisasjonsrad.
DO $$
DECLARE n int;
BEGIN
SELECT count(*) INTO n FROM organization;
IF n <> 1 THEN
RAISE EXCEPTION 'ISOLASJON FEILET (organization): ser % rader, forventet 1', n;
END IF;
RAISE NOTICE 'OK Test 2: ser kun egen organisasjonsrad (%).', n;
END $$;
-- Test 3: Kan IKKE sette inn data merket med en annen organisasjon.
-- WITH CHECK skal blokkere det (SQLSTATE 42501).
DO $$
BEGIN
BEGIN
INSERT INTO tournament (organization_id, name)
VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'kryss-org-forsøk');
-- Kommer vi hit, ble det tillatt -> isolasjonen er brutt.
RAISE EXCEPTION 'ISOLASJON FEILET (skriving): fikk sette inn data for annen org';
EXCEPTION
WHEN insufficient_privilege THEN
RAISE NOTICE 'OK Test 3: WITH CHECK blokkerte kryss-org innsetting.';
END;
END $$;
-- Test 4: Kontrollprøve — bytter kontekst til Org B og ser Bs turnering isteden.
SELECT set_config('app.current_org', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', false);
DO $$
DECLARE nm text;
BEGIN
SELECT name INTO nm FROM tournament;
IF nm <> 'B-Cup' THEN
RAISE EXCEPTION 'ISOLASJON FEILET (kontekstbytte): forventet B-Cup, fikk %', nm;
END IF;
RAISE NOTICE 'OK Test 4: kontekstbytte gir riktig organisasjons data (%).', nm;
END $$;
RESET ROLE;
RESET app.current_org;
ROLLBACK; -- ingen testdata blir liggende igjen
\echo '============================================'
\echo ' Alle isolasjonstester bestått (se OK-linjer)'
\echo '============================================'