🛡️ Red Team RLS Triaaž · 25 tabelit / 8 view / 34 funktsioon

Agent: spawn_red_team_rls_2026-05-27 · Run: agent_runs id=76
Koordinaator: vs_eirik koord 12 (run id=74) · Parent context: koord 10 PR #130 Tier 1 DEGRADED monitor järellaine
PR: #115 audit-jälg + #112 Kiht 1 read-only + #81 strateegilise PR audit-rituaal + #124 SAMM 12
Sisend: Erki tervise-raport pos_deep_memory id=8706 + Supabase advisors security category
Mode: nas_dsm.set_read_only(True) ✓ · Tier 2 Supabase MCP otse (Tier 1 DEGRADED per PR #130)
⚠️ Sub-agent piirang: See on RED TEAM triaaž (mitte impl). Ühtegi migrationit EI APPLY-ta. Kõik SQL on plaani-fail, mille Erki ja/või koordinaator rakendab käsitsi pärast verdict-i läbivaatamist.

1. Hüpervision SAMM 12 (PR #124)

session_manifests.payload.hypervision_status = 'PASS_TIER2' · Tier 1 DEGRADED (PR #130 trigger viimase 24h 572 health_check), Tier 2 Supabase MCP otse LIVE. Paralleelseid status='running' sub-sessioone tuvastatud: vs_eirik koord 12 (id=74) = parent — ootuspärane.

2. KOOND verdict

🎯 KOOND: CONCERNS

Põhjus: RLS-puudus on tegelik risk avalikele tabelitele (LVM-kaart anon-key SELECT + personalos_waitlist anon-key INSERT), kuid 17 sisemist tabelit on madala riski-ga (mõju ainult kui anon-key publicly leakib). Lahendus on selge 3-faasiline migration, mis ei riku ühtegi LIVE-äppi.

3 PARANDUST:

  1. Faas 1 (autonomne, PR #111 Recommended): 17 sisemise tabeli RLS + service_role_only policy. 0 äpi-mõju, sest need tabelid pole anon-key kaudu kasutusel.
  2. Faas 2 (Erki kinnitusega): 4 avaliku tabeli RLS + anon_read/anon_insert policy: lvm_parcels, lvm_fells, lvm_nogabali (Janis-äpi kaart), personalos_waitlist (signup vorm). 8 SECURITY DEFINER vaate → SECURITY INVOKER konversioon koos baastabelite anon_read policy lisamisega. spatial_ref_sys JÄTTA puutumata (PostGIS standard, Supabase advisor false-positive).
  3. Faas 3 (autonomne): ~30 user-funktsiooni SET search_path = public, pg_catalog bulk-lock. PostGIS funktsioone EI puuduta (extension manageeritud).

VERDICT-i kvalifikatsioon: Kui Faas 1 + Faas 2 + Faas 3 rakendatakse järjest 1 ETA-päeva sees → PASS. Praegune CONCERNS = LIVE-staatus (0% LIVE).

3. Per-tabel triaaž (25 tabelit)

TabelSuurusLayerConsumers (registry)App-kasutusRiskVerdictFaasSoovitatav policy
lvm_nogabali39 MB2Aterranervus, timbertrace, janis_ui lvm_geo_kaart_v1.html:400 ANON SELECT 4anon_readFaas 2 CREATE POLICY anon_read ON public.lvm_nogabali FOR SELECT USING (true);
lvm_works9.5 MB2Aterranervus 2service_onlyFaas 1 FORCE RLS; service_role ALL
lvm_cirsmas7.3 MB2Aterranervus, timbertrace, janis_ui — (registry janis_ui aga grep 0 hit) 3service_only*Faas 1 *Kui janis_ui hakkab anon-i kasutama, lisa anon_read hiljem (Faas 2 patch)
spatial_ref_sys7 MB2Apostgis PostGIS extension data 1postgis_skip JÄTA puutumata. Supabase advisor INFO-level false-positive — PostGIS standard SRID tabel, ainult koordinaadid (EPSG:4326 jne), pole tundlikku andmeid. Migration ALTER TABLE spatial_ref_sys ENABLE RLS tekitab extension-level konfliktid.
lvm_parcels4 MB2Aterranervus, timbertrace, janis_ui lvm_geo_kaart_v1.html:299 ANON SELECT + write_map_v2.py:270 5anon_readFaas 2 CREATE POLICY anon_read ON public.lvm_parcels FOR SELECT USING (true);
lvm_fells840 kB2Aterranervus, timbertrace lvm_geo_kaart_v1.html:336 ANON SELECT 4anon_readFaas 2 CREATE POLICY anon_read ON public.lvm_fells FOR SELECT USING (true);
pos_deep_memory_l2392 kB2Bvs_eirik, cowork_eirik, chat_eirik tier_2_5_helper SERVICE_ROLE 7service_onlyFaas 1 Mälu-agendi narratiivi-mälu — sisaldab kogu Erki–Eirik kontekstuaal-info. Avalik = identiteedi leke.
lvm_service_providers240 kB2Atimbertrace 3service_onlyFaas 1 FORCE RLS; service_role ALL
skills_registry152 kB2Eall_agents kaudne läbi v_active_skills (SECURITY DEFINER view, anon bypass) 2service_onlyFaas 1 Sõltuvus: v_active_skills jätkab töötamast SECURITY DEFINER tõttu (kuni Faas 2 view-konversioon). Pärast view INVOKER → vaja anon_read WHERE status='active'.
agent_runs144 kB4vs_eirik, cowork_eirik, chat_eirik, cursor_eirik, vahimees_eirik, malu_agent, archiver eirik_live.html:336 ANON SELECT läbi v_agent_live (SECURITY DEFINER) 5service_onlyFaas 1 SECURITY DEFINER view kaitseb täna anon-juurdepääsu. Kui view → SECURITY INVOKER, vaja anon_read või jätame view DEFINER-iks (Variant B).
santa_saatelehed128 kB2Atimbertrace santa_xlsx_sync/sync.py:43 SERVICE_ROLE 4service_onlyFaas 1 Vestmani transport-andmed — anon leke = klient-info paljas.
process_state_log120 kB4malu_agent, vahimees_eirik, archiver kaudne läbi v_agent_live 3service_onlyFaas 1 FORCE RLS; service_role ALL
agent_task_locks96 kB4vs_eirik, cowork_eirik, chat_eirik, cursor_eirik, vahimees_eirik, malu_agent eirik_live.html:299 ANON SELECT (otsene) 4anon_read* või service_onlyFaas 2 Erki otsus vajalik: kas eirik_live.html on (a) avalik dashboard → anon_read OR (b) sisemine → muuda eirik_live.html service_role peale või loginiga.
sec_filings96 kB2Cnw_kinnistu_optimizer 2service_onlyFaas 1 FORCE RLS; service_role ALL (turuandmed avalik EDGAR, aga ETL-load on private)
integration_inventory64 kB2Eadmin 3service_onlyFaas 1 Admin-tabel
market_quotes64 kB2Cnw_kinnistu_optimizer 2service_onlyFaas 1 FORCE RLS; service_role ALL
market_fundamentals64 kB2Cnw_kinnistu_optimizer 2service_onlyFaas 1 FORCE RLS; service_role ALL
inventory_files56 kB2Fclassifier.py, extractor.py, embedder.py, cataloger.py, vahimees_eirik 5service_onlyFaas 1 Mälu-agendi failipaths Touro 461GB — leke = file-system kaardistus.
timbertrace_deliveries56 kB2Atimbertrace ocr_pipeline.py:42 SERVICE_ROLE 6service_onlyFaas 1 Vestmani veoselehed OCR — kliendi-tundlik (PR #112 andmete-omandus printsiip).
toftan_warehouse_stock48 kB2Ctimbertrace toftan_sftp_watcher/watcher.py:138 SERVICE_ROLE 5service_onlyFaas 1 Toftan saetehas stock — partner-tundlik.
jetson_jobs40 kB+Bmalu_agent, vahimees_eirik, kaardiaju 2service_onlyFaas 1 FORCE RLS; service_role ALL
nse_corporate_filings32 kB2Cnw_kinnistu_optimizer 2service_onlyFaas 1 FORCE RLS; service_role ALL
insider_transactions32 kB2Cnw_kinnistu_optimizer 2service_onlyFaas 1 FORCE RLS; service_role ALL
personalos_waitlist32 kB2Cpersonalos personalos.html:599+617 ANON SELECT count + ANON INSERT 8anon_insert + countFaas 2 KRIITILINE: avalik signup vorm — ilma RLS-iga saab anon SELECT *. Vajab: anon_insert policy (WITH CHECK true) + anon_count_only (näit USING (false) aga count-päring töötab või eraldi RPC) + service_role read full.
lvm_etl_sync_log24 kB2Fops_board 2service_onlyFaas 1 FORCE RLS; service_role ALL

4. SECURITY DEFINER vaadete triaaž (8 vaadet)

ViewBaastabel(id)Anon-kasutus?VerdictSoovitatav samm
v_agent_liveagent_runs, process_state_log, agent_task_lockseirik_live.html ANONCONCERNSVariant B (eelistatud): jätka SECURITY DEFINER + GRANT SELECT TO anon. Long-term Variant A: muuda INVOKER + baastabelite anon_read.
v_active_skillsskills_registrytundmatu (grep 0 hit; tõenäoliselt ops_board admin)PASSMuuda SECURITY INVOKER. skills_registry service_role-only OK kuna ops_board kasutab ilmselt teenuse-võtit.
v_pending_invoicesinvoice_verificationstundmatu (eeldatavalt Janis admin)CONCERNSMuuda INVOKER. Vaja kontrollida kas Janis-äpp kasutab anon-key (PR #109 invoice-verify pipeline).
v_active_price_listsprice_liststundmatuPASSINVOKER + price_lists service_role-only
data_freshness_statusdata_sources, sync_logprojektipuu.html ANON (data_sources)CONCERNSSäilita DEFINER VÕI lisa baastabelitele anon_read. Aga lihtsam: jätka DEFINER + GRANT.
v_changelogagent_messagestundmatuCONCERNSSäilita DEFINER + GRANT. agent_messages ON KAITSTUD täna (RLS LIVE) aga view bypassib seda — risk on lugemise scope laienemine.
v_active_coefficientcoefficient_historytundmatuPASSINVOKER + coefficient_history service_role-only
v_layer_registry_summaryforestsense_layer_registrytundmatu (ops_board admin)PASSINVOKER + forestsense_layer_registry anon_read OK (mitte tundlik — registry definitsioonid).
Disainivalik anon-kasutusega vaadete jaoks:
Variant B (Recommended PR #111): jätka SECURITY DEFINER, lisa baastabelitele RLS + service_role-only, GRANT SELECT view-le anon-le. View peidab tundlikud read/veerud (näit v_agent_live filtreerib viimase 5 min). Madal töö, kohe valmis.
Variant A (Long-term): muuda kõik 8 vaate SECURITY INVOKER + baastabelitele lisa anon_read spetsiifilise filter-iga. Puhtam PG 15+ best practice. Suurem töö, mitu policy-d.

5. Function search_path triaaž

Supabase advisor näitas 34 funktsiooni. Tegelikult ~30 user-funktsiooni (ülejäänud on PostGIS extension, ei puuduta). Kriitilisemad on 7 SECURITY DEFINER user-funktsiooni — neid kasutatakse RLS-bypass-iga, mistõttu mutable search_path = SQL-injection vektor.

FunktsioonLangSec modeRiskSoovitus
hypervision_record_api_key_usageplpgsqlDEFINER7SET search_path = public, pg_catalog
hypervision_verify_api_keyplpgsqlDEFINER7SET search_path = public, pg_catalog
insert_tmaplpgsqlDEFINER6SET search_path = public, pg_catalog
set_default_client_idplpgsqlDEFINER5SET search_path = public, pg_catalog
trigger_embed_messageplpgsqlDEFINER5SET search_path = public, pg_catalog
trigger_red_team_checkplpgsqlDEFINER5SET search_path = public, pg_catalog
~25 SECURITY INVOKER user-funktsiooniINVOKER3Bulk ALTER FUNCTION SET search_path
~140 PostGIS funktsioonisql/plpgsqlINVOKER1EI PUUDUTA — PostGIS extension management.

6. Faas 1 migration SQL (autonomne, PR #111 Recommended)

-- Faas 1: 17 sisemise tabeli RLS + service_role-only policy
-- 0 äpi-mõju (pole anon-key kaudu kasutusel)
-- Apply: Supabase Studio → SQL Editor

BEGIN;

-- 1. LVM ETL tabelid (3)
ALTER TABLE public.lvm_works ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.lvm_cirsmas ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.lvm_service_providers ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.lvm_etl_sync_log ENABLE ROW LEVEL SECURITY;

-- 2. Market data (5)
ALTER TABLE public.sec_filings ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.market_quotes ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.market_fundamentals ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.nse_corporate_filings ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.insider_transactions ENABLE ROW LEVEL SECURITY;

-- 3. Mälu-agent + Hypervision (5)
ALTER TABLE public.pos_deep_memory_l2 ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.inventory_files ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.jetson_jobs ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.process_state_log ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.agent_runs ENABLE ROW LEVEL SECURITY;

-- 4. Tundlikud partner-tabelid (3)
ALTER TABLE public.santa_saatelehed ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.timbertrace_deliveries ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.toftan_warehouse_stock ENABLE ROW LEVEL SECURITY;

-- 5. Skills + integration (2)
ALTER TABLE public.skills_registry ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.integration_inventory ENABLE ROW LEVEL SECURITY;

-- service_role-only policy bulk (PostgreSQL alates 17 saab kasutada DO-blokis;
-- 16 või vanem — kirjuta need 18 lauset käsitsi)
DO $$
DECLARE t TEXT;
BEGIN
  FOREACH t IN ARRAY ARRAY[
    'lvm_works','lvm_cirsmas','lvm_service_providers','lvm_etl_sync_log',
    'sec_filings','market_quotes','market_fundamentals','nse_corporate_filings','insider_transactions',
    'pos_deep_memory_l2','inventory_files','jetson_jobs','process_state_log','agent_runs',
    'santa_saatelehed','timbertrace_deliveries','toftan_warehouse_stock',
    'skills_registry','integration_inventory'
  ] LOOP
    EXECUTE format('CREATE POLICY service_role_all ON public.%I FOR ALL TO service_role USING (true) WITH CHECK (true);', t);
  END LOOP;
END $$;

COMMIT;

-- Validatsioon
SELECT tablename, count(*) AS policy_count FROM pg_policies WHERE schemaname='public'
  AND tablename IN ('lvm_works','lvm_cirsmas','lvm_service_providers','lvm_etl_sync_log',
    'sec_filings','market_quotes','market_fundamentals','nse_corporate_filings','insider_transactions',
    'pos_deep_memory_l2','inventory_files','jetson_jobs','process_state_log','agent_runs',
    'santa_saatelehed','timbertrace_deliveries','toftan_warehouse_stock',
    'skills_registry','integration_inventory')
GROUP BY tablename;
-- Eeldus: 19 rida, igaüks policy_count=1
Märkus agent_runs kohta: see on tier_2_5_helper REST (service_role JWT) kasutuses LIVE. Service_role policy hoiab kõike töötamas. Kui v_agent_live jätame SECURITY DEFINER-iks, ka eirik_live.html anon-päring jätkab.

7. Faas 2 migration SQL (Erki kinnitusega — avalikud tabelid + vaated)

-- Faas 2: 4 avaliku tabeli anon_read/insert + agent_task_locks otsus + view INVOKER (valikuline)

BEGIN;

-- 1. LVM kaart (Janis-äpp anon-key SELECT)
ALTER TABLE public.lvm_parcels ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.lvm_fells ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.lvm_nogabali ENABLE ROW LEVEL SECURITY;
CREATE POLICY anon_read ON public.lvm_parcels FOR SELECT TO anon, authenticated USING (true);
CREATE POLICY anon_read ON public.lvm_fells FOR SELECT TO anon, authenticated USING (true);
CREATE POLICY anon_read ON public.lvm_nogabali FOR SELECT TO anon, authenticated USING (true);
CREATE POLICY service_role_all ON public.lvm_parcels FOR ALL TO service_role USING (true) WITH CHECK (true);
CREATE POLICY service_role_all ON public.lvm_fells FOR ALL TO service_role USING (true) WITH CHECK (true);
CREATE POLICY service_role_all ON public.lvm_nogabali FOR ALL TO service_role USING (true) WITH CHECK (true);

-- 2. PersonalOS waitlist (avalik signup vorm)
ALTER TABLE public.personalos_waitlist ENABLE ROW LEVEL SECURITY;
-- anon saab INSERT (signup) AGA EI saa SELECT (e-maile ei loe kõik)
CREATE POLICY anon_insert ON public.personalos_waitlist
  FOR INSERT TO anon, authenticated WITH CHECK (true);
-- count-päring vajab eraldi RPC funktsiooni VÕI policy USING(false) + count erand
-- Lihtsam: loo RPC SECURITY DEFINER `personalos_waitlist_count()`
CREATE OR REPLACE FUNCTION public.personalos_waitlist_count()
RETURNS integer LANGUAGE sql SECURITY DEFINER SET search_path = public, pg_catalog
AS $$ SELECT count(*)::int FROM personalos_waitlist; $$;
GRANT EXECUTE ON FUNCTION public.personalos_waitlist_count() TO anon, authenticated;
-- service_role full access
CREATE POLICY service_role_all ON public.personalos_waitlist FOR ALL TO service_role USING (true) WITH CHECK (true);
-- TODO: uuenda personalos.html:599 päring RPC kutsele

-- 3. agent_task_locks — KAS eirik_live.html on avalik?
-- VARIANT A (avalik dashboard, Erki valib): anon_read
-- ALTER TABLE public.agent_task_locks ENABLE ROW LEVEL SECURITY;
-- CREATE POLICY anon_read ON public.agent_task_locks FOR SELECT TO anon USING (true);
-- CREATE POLICY service_role_all ON public.agent_task_locks FOR ALL TO service_role USING (true) WITH CHECK (true);
-- VARIANT B (sisemine, Erki valib): service_only + muuda eirik_live.html service_role peale
ALTER TABLE public.agent_task_locks ENABLE ROW LEVEL SECURITY;
CREATE POLICY service_role_all ON public.agent_task_locks FOR ALL TO service_role USING (true) WITH CHECK (true);

-- 4. spatial_ref_sys — JÄTA RLS OFF (PostGIS standard, advisor false-positive)
-- (ei tee mingit muudatust)

-- 5. SECURITY DEFINER → INVOKER konversioon (valikuline, soovituslik PG15+)
-- Variant A — täielik:
ALTER VIEW public.v_active_skills SET (security_invoker=true);
ALTER VIEW public.v_active_price_lists SET (security_invoker=true);
ALTER VIEW public.v_active_coefficient SET (security_invoker=true);
ALTER VIEW public.v_layer_registry_summary SET (security_invoker=true);
GRANT SELECT ON public.v_layer_registry_summary TO anon, authenticated;
-- v_agent_live + v_changelog + v_pending_invoices + data_freshness_status — JÄTA DEFINER
-- (anon-kasutus baastabelite vastu vajab täiendavat policy-tuningut, eraldi triaaž)

COMMIT;

8. Faas 3 migration SQL (autonomne — function search_path bulk-lock)

-- Faas 3: 30 user-funktsiooni search_path lukk
-- PostGIS funktsioone EI muuda (extension management)

BEGIN;

-- 7 SECURITY DEFINER kriitilist
ALTER FUNCTION public.hypervision_record_api_key_usage SET search_path = public, pg_catalog;
ALTER FUNCTION public.hypervision_verify_api_key SET search_path = public, pg_catalog;
ALTER FUNCTION public.insert_tma SET search_path = public, pg_catalog;
ALTER FUNCTION public.set_default_client_id SET search_path = public, pg_catalog;
ALTER FUNCTION public.trigger_embed_message SET search_path = public, pg_catalog;
ALTER FUNCTION public.trigger_red_team_check SET search_path = public, pg_catalog;

-- 23 SECURITY INVOKER user-funktsiooni
ALTER FUNCTION public.acquire_agent_lock SET search_path = public, pg_catalog;
ALTER FUNCTION public.audit_check_source SET search_path = public, pg_catalog;
ALTER FUNCTION public.audit_immutable SET search_path = public, pg_catalog;
ALTER FUNCTION public.auto_cleanup SET search_path = public, pg_catalog;
ALTER FUNCTION public.block_legacy_watchdog SET search_path = public, pg_catalog;
ALTER FUNCTION public.calculate_coefficient SET search_path = public, pg_catalog;
ALTER FUNCTION public.check_response_format SET search_path = public, pg_catalog;
ALTER FUNCTION public.claim_work SET search_path = public, pg_catalog;
ALTER FUNCTION public.find_skill SET search_path = public, pg_catalog;
ALTER FUNCTION public.os_reports_update_search_text SET search_path = public, pg_catalog;
ALTER FUNCTION public.query_memory SET search_path = public, pg_catalog;
ALTER FUNCTION public.search_bge_m3 SET search_path = public, pg_catalog;
ALTER FUNCTION public.search_memory_text SET search_path = public, pg_catalog;
ALTER FUNCTION public.search_memory_vec SET search_path = public, pg_catalog;
ALTER FUNCTION public.search_pos_deep_memory SET search_path = public, pg_catalog;
ALTER FUNCTION public.search_pos_memory SET search_path = public, pg_catalog;
ALTER FUNCTION public.tma_load_stems SET search_path = public, pg_catalog;
ALTER FUNCTION public.tma_load_stems_json SET search_path = public, pg_catalog;
ALTER FUNCTION public.tma_load_tracking_json SET search_path = public, pg_catalog;
ALTER FUNCTION public.trg_layer_registry_updated_at SET search_path = public, pg_catalog;
ALTER FUNCTION public.trigger_embed_agent_message SET search_path = public, pg_catalog;
ALTER FUNCTION public.trigger_sync SET search_path = public, pg_catalog;
ALTER FUNCTION public.update_coefficient SET search_path = public, pg_catalog;
ALTER FUNCTION public.update_skills_registry_updated_at SET search_path = public, pg_catalog;
ALTER FUNCTION public.watchdog_check SET search_path = public, pg_catalog;
ALTER FUNCTION public.watchdog_daily_report SET search_path = public, pg_catalog;

-- search_memory + query_memory on overload-vorm (mitu signatuuri) — peab käsitsi viiteid:
-- Kontroll \df+ search_memory ENNE.

COMMIT;

-- Validatsioon
SELECT proname, array_to_string(proconfig, ', ') AS cfg
FROM pg_proc p JOIN pg_namespace n ON n.oid=p.pronamespace
WHERE n.nspname='public' AND p.proname IN (
  'hypervision_record_api_key_usage','hypervision_verify_api_key','insert_tma',
  'set_default_client_id','trigger_embed_message','trigger_red_team_check',
  'calculate_coefficient','search_pos_deep_memory','tma_load_stems_json','watchdog_check'
);
-- Eeldus: kõik cfg sisaldab 'search_path=public, pg_catalog'

9. Erijuhud + märkused

🚨 KRIITILINE: personalos_waitlist on hetkel täielikult avalik — anon-key SELECT * tagastab kõik nimed+emailid. personalos.html:599+617 kasutab anon-key SELECT count + INSERT. Faas 2 on KIIRELOOMULINE. Hetkel võiks kontrollida kas keegi on tegelikult avalikult SELECT*-i teinud (Supabase audit log).
⚠️ search_memory overload: SQL ALTER FUNCTION search_memory ebaõnnestub kui funktsiooni on 2 signatuuri. Vaja täpsustada argumenttüüpe: ALTER FUNCTION search_memory(text, integer) .... Faas 3 PEAB enne apply'i tegema \df+ search_memory tüüpide tuvastamiseks.
✅ spatial_ref_sys advisor-warning on PostGIS extension'i osa. Supabase Linter näitab INFO-level "rls disabled in public", aga selle RLS-i sisselülitamine põhjustab PostGIS funktsioonide regressiooni (st_transform jne ei leia SRID-i). JÄTA puutumata.

10. Audit-jälg (PR #115)


spawn_red_team_rls_2026-05-27 · Eirik OS K0 sub-agent · PR #115 audit-jälg + PR #112 Kiht 1 + PR #124 SAMM 12 + PR #81 Red Team verdict mall
Generated 2026-05-27 · Tier 2 Supabase MCP (Tier 1 DEGRADED PR #130)