Přejít na obsah

Supabase 30. října: co se rozbije a jak to ověřit

Zobrazit jako MarkdownOtevřít v ClaudeOtevřít v ChatGPTOtevřít v Perplexity

Otázka se zkopíruje také. Pokud se chat otevře prázdný, vložte ji.

TL;DR

Od 30. října 2026 Supabase na všech stávajících projektech přestane novým tabulkám v public automaticky přidělovat grants pro anon, authenticated a service_role. Tabulky, které už máte, fungují dál. Každá tabulka vytvořená později odpoví supabase-js i vašemu secret key chybou 42501 permission denied, dokud ji migrace nepovolí. Přepnutí jsem si zreprodukoval lokálně: nové tabulky, nové views i staré tabulky, které migrace zahodí a vytvoří znovu, selhávají; existující tabulky, RPC funkce a vkládání do serial fungují dál. Zkontrolujete to dvěma SQL dotazy a jedním grepem níže a opravíte grantem, RLS a politikou ve stejné migraci, nikdy ne pomocí grant all on all tables.

Provozuji bezplatný Supabase security checker, který čte grants na každé vystavené tabulce, takže jsem chtěl přesně vidět, co tato změna udělá, než na ni lidé narazí. Vzal jsem lokální Supabase stack, nastavil mu stará výchozí nastavení, provedl přepnutí tak, jak ho popisuje Supabase, a poslal požadavek na každý druh objektu, který mě napadl. Tento článek ukazuje, co se vrátilo, a jak si před 30. ověřit vlastní projekt.

Co se mění 30. října 2026?

Dosud dostala každá tabulka vytvořená ve schématu public přes výchozí oprávnění Postgresu práva select, insert, update a delete pro anon, authenticated a service_role. Proto byla nová tabulka dostupná z prohlížeče ve chvíli, kdy vznikla, ať už ji chránilo RLS, nebo ne. Oznámení Supabase o breaking change tato výchozí nastavení odstraňuje ve třech krocích:

Datum Co se stane
28. dubna 2026 Nové projekty se mohou při vytvoření odhlásit z „Automatically expose new tables“
30. května 2026 Nové chování se stává výchozím pro nové projekty, nasazuje se postupně během několika týdnů
30. října 2026 Nové chování se použije na všechny stávající projekty

Na vašem projektu jsou to dva příkazy, tytéž, které Supabase uvádí pro dřívější přechod na vlastní žádost:

alter default privileges for role postgres in schema public
  revoke select, insert, update, delete on tables from anon, authenticated, service_role;

alter default privileges for role postgres in schema public
  revoke usage, select on sequences from anon, authenticated, service_role;

Výchozí oprávnění se týkají jen objektů vytvořených později. Již existující grants se nemění, proto vaše současné tabulky fungují dál. Čeho se podle oznámení změna netýká: jiných schémat (auth, storage, realtime, vlastních), aplikací, které mluví s Postgresem přímým připojením (psql, ORM, server s connection stringem), a samotného RLS. Změna se týká Data API: REST, GraphQL a všech klientských knihoven nad nimi.

Co se rozbije a co funguje dál?

Moje sestava: Supabase CLI 2.109.1, Postgres 17.6, PostgREST 14.14, dne 26. října 2026. V config.toml jsem nastavil auto_expose_new_tables = true, abych dostal stará výchozí nastavení, vytvořil jednu tabulku se dvěma řádky, zapnutým RLS a politikou pro čtení a pak spustil dva příkazy výše. Poté jsem vytvořil nové objekty a každý zavolal lokálním veřejným klíčem (anon) a secret klíčem (service_role), jedním požadavkem na každý.

Co přestane odpovídat po přepnutí 30. října. Lokální Supabase, objekty vytvořené po revoke z changelogu, veřejný klíč, pokud není uvedeno jinak. Nová tabulka s RLS a politikou: create table → politika, bez grantu → 42501, HTTP 401; Stejná tabulka se secret key: create table → politika, bez grantu → 42501, HTTP 403; Nový view nad fungující tabulkou: create view → 42501, HTTP 401, bez hintu; Stará tabulka zahozená a znovu vytvořená migrací: drop + create table → grants pryč → 42501, HTTP 401.
Moje reprodukce na lokálním Supabase stacku (CLI 2.109.1, Postgres 17.6, PostgREST 14.14), 26. října 2026.
Co funguje i po přepnutí 30. října. Stejný lokální stack, stejný revoke, veřejný klíč. Tabulka vytvořená před přepnutím: existující tabulka → grants zůstaly → 2 řádky, HTTP 200; Nová funkce volaná přes RPC: create function → execute přes PUBLIC → HTTP 200; Nová serial tabulka, jen select a insert: id serial → zůstal UPDATE na sekvenci → insert, HTTP 201.
Moje reprodukce na lokálním Supabase stacku (CLI 2.109.1, Postgres 17.6, PostgREST 14.14), 26. října 2026.
Objekt, vytvořený po přepnutí, pokud není uvedeno jinak Klíč Výsledek
Tabulka vytvořená před přepnutím veřejný HTTP 200, 2 řádky
Nová tabulka s RLS a politikou to anon, authenticated veřejný HTTP 401, 42501, hint GRANT SELECT ON public.new_orders TO anon;
Stejná nová tabulka secret HTTP 403, 42501, hint … TO service_role;
Nový view (security_invoker) nad starou tabulkou veřejný HTTP 401, 42501, permission denied for view, hint null
Kopie vytvořená přes create table … (like old_orders including all) veřejný HTTP 401, 42501
Stará tabulka po drop table a novém create table veřejný HTTP 401, 42501
Nová funkce public.ping() přes /rest/v1/rpc veřejný HTTP 200
Nová tabulka s id serial, pro anon jen select, insert veřejný insert HTTP 201

V té tabulce je pět věcí, které stojí za to znát před přepnutím.

„Existující tabulky si grants ponechají“ platí jen do chvíle, kdy tabulka existuje. Migrace, která tabulku zahodí a vytvoří znovu, kopie přes create table … (like …) nebo obnova z dumpu vytvoří novou tabulku, a nová tabulka nedostane nic. Politika se mi vrátila s mým create policy, grants ne. Cokoli ve vašem pipeline, co tabulky přestavuje místo aby je upravovalo (alter), selže při prvním spuštění po přepnutí.

Secret key se rozbije také. service_role obchází RLS, ale grant stále potřebuje. Takže Edge Function, cron úloha nebo webhook handler, který zapisuje do nové tabulky, skončí s 403, nejen prohlížeč. Hint jmenuje service_role, podle toho to poznáte.

Views žádný hint nedávají. U tabulek PostgREST vrací přesný GRANT, který potřebujete. U mého nového view byl hint null a zpráva říkala permission denied for view v_old_orders. AI nástroj, který opravuje 42501 podle hintu, tu nemá co zkopírovat; grant je grant select on public.v_old_orders to authenticated; a view si má ponechat security_invoker = true, aby se na něj dál uplatňovalo RLS tabulky.

Funkcí se tato změna netýká. Ty dva příkazy se dotýkají tabulek a sekvencí. Moje nová funkce zůstala volatelná pro anon, authenticated i service_role, protože Postgres uděluje execute na každou novou funkci pro PUBLIC a revoke na úrovni schématu to odebrat nedokáže, jak vysvětluje průvodce zabezpečením API od Supabase. RPC volání po 30. říjnu fungují dál; zároveň to znamená, že nová funkce security definer je volatelná vaším veřejným klíčem hned, jak vznikne.

Vkládání do serial fungovalo i bez grantu na sekvenci. Mnoho rad tvrdí, že serial id po přepnutí potřebuje grant usage on sequence … to authenticated. V mém běhu insert prošel i bez něj: revoke odebírá usage a select na nových sekvencích, ale update zůstává a update na nextval stačí. Pokud odeberete všechna výchozí oprávnění na sekvencích, jako to dělá plný revoke v průvodci zabezpečením API, grant na usage potřebujete. Identity sloupec (generated by default as identity) nepotřebuje nic tak či tak.

Ještě jedna věc, kterou revoke nechává za sebou: nová tabulka stále přišla s TRUNCATE, REFERENCES a TRIGGER pro všechny tři role a na Postgresu 17 výchozí nastavení nese i MAINTAIN. Na TRUNCATE se žádná politika RLS neuplatní. Psal jsem o tom v poznámce k 42501.

Kde na to narazíte před 30. říjnem

Přepnutí na vašem hostovaném projektu proběhne 30., ale tři místa se už chovají jako po něm.

supabase db reset na aktuálním CLI. CLI v2.102.0 přidalo do config.toml klíč [api] auto_expose_new_tables. Na 2.109.1 měl můj čerstvý stack bez tohoto klíče už nová výchozí nastavení: tabulky dostaly jen MAINTAIN, REFERENCES, TRIGGER a TRUNCATE, sekvence jen UPDATE. Nastavení na true vrátí stará oprávnění a vypíše api.auto_expose_new_tables is deprecated and will be removed on 2026-10-30. Takže pokud vaše lokální tabulky po resetu stále fungují, nejdřív zkontrolujte tento klíč. Je to také nejlevnější místo k testování: odeberte ho, proveďte reset, spusťte aplikaci.

Preview branches a projekty vytvořené od 30. května. Přehrávají vaše migrace na nových výchozích nastaveních. Každá tabulka, jejíž migrace neobsahuje grant, je tam už nyní nedostupná. V diskuzi na GitHubu lidé s jedním projektem na zákazníka hlásí přesně tohle: běžící projekty jsou v pořádku, každé nové nasazení ze stejných migrací je rozbité.

Baseline migrace, která vrací staré výchozí nastavení. Komentující ve stejné diskuzi upozorňuje, že první migrace vytvořená přes supabase db pull může obsahovat alter default privileges … grant all on tables to anon, authenticated, service_role. Ten příkaz jsem spustil po přepnutí: další tabulka, kterou jsem vytvořil, byla opět dostupná, HTTP 200. Lokálně to problém zakryje. Na vašem hostovaném projektu to změnu tiše vrátí zpět a každá budoucí tabulka je opět otevřená veřejnému klíči, ať má RLS, nebo ne. Projděte své migrace hledáním alter default privileges a přečtěte si každý nález.

Jak zkontrolovat projekt před 30. říjnem

Čtyři kontroly od nejrychlejší po nejdůkladnější. První dvě běží v SQL Editoru hostovaného projektu.

1. Přepnul se už váš projekt?

Toto je dotaz z průvodce zabezpečením API od Supabase. Vypíše, co dostanou nové objekty vytvořené uživatelem postgres v public:

select
  case d.defaclobjtype
    when 'r' then 'tables'
    when 'S' then 'sequences'
    when 'f' then 'functions'
  end as object_type,
  a.grantee::regrole as role,
  string_agg(a.privilege_type, ', ' order by a.privilege_type) as privileges
from pg_default_acl d
cross join lateral aclexplode(d.defaclacl) a
where d.defaclrole = 'postgres'::regrole
  and d.defaclnamespace = 'public'::regnamespace
  and a.grantee in ('anon'::regrole, 'authenticated'::regrole, 'service_role'::regrole)
group by 1, 2
order by 1, 2;

Pokud řádky tables obsahují SELECT, INSERT, UPDATE, DELETE, je projekt stále na starém výchozím nastavení a přepne se 30. Pokud ukazují jen MAINTAIN, REFERENCES, TRIGGER, TRUNCATE (nebo žádné řádky), jsou nové tabulky už uzavřené. Vidíte to také v Dashboardu v nastavení Data API, „Automatically expose new tables“.

2. Které tabulky mají politiku, ale ne grant?

Politika pro roli, která nemá grant na daný příkaz, se nikdy nespustí: požadavek selže před RLS. Tento dotaz vypíše takové dvojice. V mé laboratoři našel novou tabulku a znovu vytvořenou starou, nic dalšího:

select p.schemaname || '.' || p.tablename as "table", r.role, p.cmd
from pg_policies p
cross join lateral unnest(case when 'public' = any(p.roles) then array['anon', 'authenticated']::name[] else p.roles end) as r(role)
join pg_class c on c.relname = p.tablename
join pg_namespace n on n.oid = c.relnamespace and n.nspname = p.schemaname
where p.schemaname = 'public'
  and r.role in ('anon', 'authenticated')
  and not has_table_privilege(r.role::text, c.oid,
        case p.cmd when 'ALL' then 'SELECT' else p.cmd end)
order by 1, 2, 3;

Spouštějte ho po každé migraci, v CI nad čerstvým db reset nebo na stagingu. Na zdravém projektu nevrátí nic; po 30. je každý řádek tabulka, na kterou vaše aplikace nedosáhne. Kontroluje grants na úrovni tabulky, takže tabulka otevřená jen sloupcovými grants (grant select (id, name) on …) se tu objeví, i když jsou ty sloupce čitelné.

3. Které migrace vytvářejí tabulku bez grantu?

Databáze ukazuje jen tabulky, které existují. Migrace, kterou jste ještě nespustili, je vidět jen ve vašem repozitáři. Tento hrubý grep vypíše každý create table v supabase/migrations bez grant … on pro stejný název:

for t in $(grep -hioE 'create table( if not exists)? +[a-z0-9_."]+' supabase/migrations/*.sql | awk '{print $NF}' | sort -u); do
  grep -qiF "on $t " supabase/migrations/*.sql || grep -qiF "on table $t " supabase/migrations/*.sql || echo "no grant: $t"
done

Je to porovnávání textu, ne parsování SQL: grant uvádějící několik tabulek v jednom příkazu, nebo tabulka jmenovaná na jednom místě bez schématu a na jiném se schématem, dá falešný nález. Přečtěte si každý vypsaný řádek. Tabulky, na které sahá jen serverový kód přímým připojením, grant nepotřebují vůbec.

4. Přehrát všechno na nových výchozích nastaveních

Odeberte auto_expose_new_tables z config.toml, spusťte supabase db reset a pusťte nad tím aplikaci nebo její testy. To je váš projekt po 30., navíc s čerstvou kopií každé tabulky, což je těžší případ. Supabase také vypisuje dotčené tabulky v Security Advisor a v Table Editoru označuje vystavení přes Data API.

Jak to opravit, aniž byste otevřeli každou tabulku

Napište grant, RLS a politiky do migrace, která tabulku vytváří, a každé roli dejte jen to, co aplikace používá:

create table public.invoices (
  id bigint generated by default as identity primary key,
  user_id uuid not null default auth.uid(),
  total numeric not null
);

revoke all on table public.invoices from anon, authenticated, service_role;
grant select, insert on table public.invoices to authenticated;
grant select, insert, update, delete on table public.invoices to service_role;

alter table public.invoices enable row level security;

create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);

create policy "Owners add their invoices"
on public.invoices for insert
to authenticated
with check ((select auth.uid()) = user_id);

Tento blok jsem spustil na stejném lokálním stacku: přihlášený testovací uživatel vložil řádek a přečetl ho zpět (HTTP 201, pak 200), veřejný klíč bez session dostal 42501 a kontrola 2 výše tabulku už nevypsala. Úvodní revoke all smaže TRUNCATE, TRIGGER a REFERENCES, které nová tabulka dostane, a na projektu, který se ještě nepřepnul, dává stejný výsledek. Roli anon dávejte grant jen na data určená odhlášeným návštěvníkům a service_role jen tehdy, pokud serverový kód používá na této tabulce secret key. Jak do sebe zapadají grants a politiky v celé aplikaci, popisuje můj checklist zabezpečení aplikace z Lovable.

Co nedělat, když přijde první 42501:

  • Nespouštějte grant all on all tables in schema public to anon, authenticated. Vrátí to staré výchozí nastavení pro všechny tabulky najednou, včetně každé tabulky, kde RLS nebylo nikdy zapnuto, a ty se stanou čitelnými pro každého, kdo drží váš veřejný klíč. Poznámka k 42501 ukazuje, proč je grant první zámek a RLS druhý.
  • Nepřidávejte znovu alter default privileges … grant. Je to rollback celé změny.
  • Nevypínejte RLS „na zkoušku“ a nedávejte secret key do frontendu. Secret key obchází RLS pro každého, kdo otevře váš bundle; rozdíl mezi klíči je v článku anon key vs service role key.

Pokud vám migrace píše AI nástroj, přidejte do jeho instrukcí jednu větu: „každá nová tabulka v public dostane explicitní grants pro každou roli, row level security a politiky zapni ve stejné migraci; nikdy negrantuj na all tables in schema public“. Hint v chybě ho naučí grant, nikdy ne RLS, které k němu patří.

Otázky, které lidé kolem změny kladou

Přestanou mé existující tabulky 30. října fungovat? Ne. Výchozí oprávnění se týkají objektů vytvořených později a v mém běhu stará tabulka po přepnutí odpověděla HTTP 200. Výjimkou je tabulka, kterou vaše migrace zahodí a vytvoří znovu.

Musím něco dělat, když nikdy nevytvářím tabulky? Ne 30. Zkontrolujte, až příště tabulku přidáte vy, kolega nebo AI nástroj, a zkontrolujte každý pipeline, který vytváří projekty nebo větve z vašich migrací.

Týká se to Edge Functions? Ano, pokud používají supabase-js se secret key na nové tabulce: service_role potřebuje grant také. Funkce, které se připojují k Postgresu přímo, se to netýká.

Týká se to RPC funkcí, Storage nebo Auth? V této změně ne. Nové funkce zůstávají volatelné přes PUBLIC a storage s auth nejsou schéma public.

Mohu přepnout dřív? Ano. Dva příkazy na začátku jsou to přepnutí; spusťte je nejdřív na stagingu, pak na produkci. Existující tabulky si grants ponechají, takže běžící aplikace si ničeho nevšimne a další nová tabulka vám hned řekne, zda jsou vaše migrace připravené.

Jak to vidí checker

Checker se připojuje jen pro čtení a čte grants na každé tabulce ve vašich vystavených schématech: do kterých tabulek může veřejný klíč zapisovat bez politiky, které tabulky mají RLS vypnuté a které výchozí oprávnění stále dávají každé nové tabulce TRUNCATE, REFERENCES nebo TRIGGER. Vypíše také každou politiku, jejíž role nemá pro daný příkaz grant, tedy tabulky, které najde kontrola 2, kromě těch s vypnutým RLS nebo se sloupcovými granty. Nevidí soubory migrací, které jste nespustili, takže kontrola 3 výše zůstává na vás. Pokud si nejste jistí právě RLS, provede vás jím jak testovat Supabase RLS a poznámka o vystavených schématech pokrývá jiná schémata než public, kterých se tato změna netýká.

© 2026 Denys Zaichenko. Původní článek: https://madsalt.tech/cs/blog/supabase-october-30-grant-change/