89 lines
3.4 KiB
PL/PgSQL
89 lines
3.4 KiB
PL/PgSQL
-- =====================================================================
|
|
-- 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 '============================================'
|