<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dmitry Maranik</title>
    <description>The latest articles on DEV Community by Dmitry Maranik (@dmitrymaranik).</description>
    <link>https://dev.to/dmitrymaranik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3952896%2F059ae87b-d06b-4f74-896d-bb82d33aef3f.png</url>
      <title>DEV Community: Dmitry Maranik</title>
      <link>https://dev.to/dmitrymaranik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dmitrymaranik"/>
    <language>en</language>
    <item>
      <title>I Lint-Ran 4 Public Supabase Apps. They All Leak Rows.</title>
      <dc:creator>Dmitry Maranik</dc:creator>
      <pubDate>Tue, 26 May 2026 17:44:07 +0000</pubDate>
      <link>https://dev.to/dmitrymaranik/i-lint-ran-4-public-supabase-apps-they-all-leak-rows-4f39</link>
      <guid>https://dev.to/dmitrymaranik/i-lint-ran-4-public-supabase-apps-they-all-leak-rows-4f39</guid>
      <description>&lt;p&gt;I ran &lt;a href="https://github.com/pgrls/pgrls" rel="noopener noreferrer"&gt;&lt;code&gt;pgrls&lt;/code&gt;&lt;/a&gt; — an open-source&lt;br&gt;
Postgres Row-Level Security linter I maintain — against four public&lt;br&gt;
Supabase-flavored repos. Three of them are first-party examples or&lt;br&gt;
official partners:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Who maintains it&lt;/th&gt;
&lt;th&gt;Findings&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/supabase/storage-api" rel="noopener noreferrer"&gt;&lt;code&gt;supabase/storage-api&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/vercel/nextjs-subscription-payments" rel="noopener noreferrer"&gt;&lt;code&gt;vercel/nextjs-subscription-payments&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Vercel × Stripe × Supabase&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/supabase/supabase/tree/master/examples/slack-clone" rel="noopener noreferrer"&gt;&lt;code&gt;supabase/supabase/examples/slack-clone&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;49&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/supabase/supabase/tree/master/examples/todo-list" rel="noopener noreferrer"&gt;&lt;code&gt;supabase/supabase/examples/todo-list&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Supabase&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;96&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Zero false positives across the 96 findings.&lt;/strong&gt; Every flagged&lt;br&gt;
policy is either a real bug or a known-acceptable trade-off worth&lt;br&gt;
surfacing for review.&lt;/p&gt;
&lt;h2&gt;
  
  
  What "correct" looks like first
&lt;/h2&gt;

&lt;p&gt;Supabase's own &lt;a href="https://supabase.com/docs/guides/database/postgres/row-level-security" rel="noopener noreferrer"&gt;RLS guide&lt;/a&gt;&lt;br&gt;
is direct about it. Under&lt;br&gt;
&lt;strong&gt;"Specify roles in your policies"&lt;/strong&gt; (in the RLS-performance&lt;br&gt;
recommendations section) the docs say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always use the Role of inside your policies, specified by the&lt;br&gt;
&lt;code&gt;TO&lt;/code&gt; operator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And demonstrate the pattern for anonymous access as a &lt;em&gt;separate,&lt;br&gt;
explicit&lt;/em&gt; policy, not a default-on side effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="nv"&gt;"Public profiles are visible to everyone."&lt;/span&gt;
    &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;
    &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;anon&lt;/span&gt;                          &lt;span class="c1"&gt;-- explicit anon allow&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The translation in practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Logged-in users read messages:&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"auth read"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;authenticated&lt;/span&gt;      &lt;span class="c1"&gt;-- explicit role binding&lt;/span&gt;
    &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Anonymous reads, only if you actually want them:&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"anon read"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;anon&lt;/span&gt;               &lt;span class="c1"&gt;-- separate, intentional&lt;/span&gt;
    &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_public&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The standard isn't load-bearing because it's elegant — it's&lt;br&gt;
load-bearing because the alternative ships rows to anonymous&lt;br&gt;
clients by accident. A policy without an explicit &lt;code&gt;TO&lt;/code&gt; clause&lt;br&gt;
defaults to &lt;code&gt;TO public&lt;/code&gt;, which means &lt;em&gt;every&lt;/em&gt; role on the database,&lt;br&gt;
including &lt;code&gt;anon&lt;/code&gt;. The 96 findings are what falls out when four&lt;br&gt;
sample apps are measured against this single principle and the&lt;br&gt;
small handful of related ones (FORCE the owner role, scope by&lt;br&gt;
&lt;code&gt;auth.uid()&lt;/code&gt; not &lt;code&gt;current_user&lt;/code&gt;, wrap auth calls for the planner).&lt;/p&gt;
&lt;h2&gt;
  
  
  The four rules that fire on every repo
&lt;/h2&gt;

&lt;p&gt;Across all four codebases, the same four rules appear:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;th&gt;Why it's everywhere&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SEC002&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;RLS enabled but &lt;code&gt;FORCE ROW LEVEL SECURITY&lt;/code&gt; missing&lt;/td&gt;
&lt;td&gt;The owner role (typically the migration role) bypasses RLS until you opt into &lt;code&gt;FORCE&lt;/code&gt;. Default-off in Postgres.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SEC003&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Permissive policy with no &lt;code&gt;TO &amp;lt;role&amp;gt;&lt;/code&gt; clause&lt;/td&gt;
&lt;td&gt;Defaults to &lt;code&gt;TO public&lt;/code&gt;, which reaches anonymous (&lt;code&gt;anon&lt;/code&gt;) connections by accident.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SEC007&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All policies on a table are permissive&lt;/td&gt;
&lt;td&gt;A single typo in &lt;code&gt;RESTRICTIVE&lt;/code&gt; (or forgetting it entirely) collapses the OR-chain to "anyone matching ANY policy passes."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SEC016&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;service_role&lt;/code&gt; has &lt;code&gt;BYPASSRLS&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;True by design on Supabase, but surfaced so an operator can audit the blast radius before granting it to anything else.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These four are the default-Supabase posture findings. Nothing&lt;br&gt;
exotic. Every Supabase project has them on day one.&lt;/p&gt;
&lt;h2&gt;
  
  
  What the deviation looks like in practice
&lt;/h2&gt;

&lt;p&gt;The densest single finding is &lt;strong&gt;SEC003 in slack-clone — 13&lt;br&gt;
instances&lt;/strong&gt; of the same shape. From&lt;br&gt;
&lt;a href="https://github.com/supabase/supabase/blob/master/examples/slack-clone/nextjs-slack-clone/full-schema.sql#L87" rel="noopener noreferrer"&gt;&lt;code&gt;examples/slack-clone/nextjs-slack-clone/full-schema.sql#L87&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="n"&gt;policy&lt;/span&gt; &lt;span class="nv"&gt;"Allow logged-in read access"&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;role&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'authenticated'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;TO &amp;lt;role&amp;gt;&lt;/code&gt; clause, so the policy defaults to &lt;code&gt;TO public&lt;/code&gt;. The&lt;br&gt;
predicate (&lt;code&gt;auth.role() = 'authenticated'&lt;/code&gt;) catches it at runtime&lt;br&gt;
&lt;em&gt;today&lt;/em&gt;, but the policy still runs for &lt;code&gt;anon&lt;/code&gt; connections — any&lt;br&gt;
later predicate change (a misplaced &lt;code&gt;OR&lt;/code&gt;, a NULL-tolerant&lt;br&gt;
&lt;code&gt;IS DISTINCT FROM&lt;/code&gt;, the SEC004 &lt;code&gt;auth_func() IS NULL OR …&lt;/code&gt; shape)&lt;br&gt;
immediately leaks every message to unauthenticated callers.&lt;/p&gt;

&lt;p&gt;The fix is moving the role gate from the predicate into the &lt;code&gt;TO&lt;/code&gt;&lt;br&gt;
clause, where it belongs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;POLICY&lt;/span&gt; &lt;span class="nv"&gt;"Allow logged-in read access"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;
    &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;authenticated&lt;/span&gt;         &lt;span class="c1"&gt;-- ← gate here, not in USING&lt;/span&gt;
    &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;13 policies in slack-clone follow the broken shape. 5 do in&lt;br&gt;
nextjs-subscription-payments. 4 in todo-list. Same fix line each&lt;br&gt;
time.&lt;/p&gt;
&lt;h2&gt;
  
  
  The performance footgun: PERF001 in 19 of the 4 repos
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;          &lt;span class="c1"&gt;-- re-evaluates per row&lt;/span&gt;
&lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="c1"&gt;-- evaluated once per query&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://supabase.com/docs/guides/database/postgres/row-level-security" rel="noopener noreferrer"&gt;Supabase's own RLS docs recommend the&lt;br&gt;
&lt;code&gt;(SELECT auth.uid())&lt;/code&gt; wrap&lt;/a&gt;&lt;br&gt;
for performance reasons — a row-by-row &lt;code&gt;auth.uid()&lt;/code&gt; call is&lt;br&gt;
quadratic-ish on a large SELECT, while the wrapped form lets the&lt;br&gt;
planner evaluate once. &lt;strong&gt;19 policies across the four repos miss&lt;br&gt;
this wrap.&lt;/strong&gt; pgrls flags it as &lt;code&gt;PERF001&lt;/code&gt; and auto-fixes it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What 0 false positives means
&lt;/h2&gt;

&lt;p&gt;I don't think most lint tools earn the "0 false positives" claim&lt;br&gt;
honestly. Two things make pgrls's count credible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It analyzes the live database catalog, not source files.&lt;/strong&gt; The
policy that fires is the policy Postgres will actually enforce —
not a guess at what the migration text resolves to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each rule is severity-rated and configurable.&lt;/strong&gt; "False
positive" in the strictest sense means "the rule flags something
that's not a bug." Across these 96 findings, every flagged
policy either &lt;em&gt;is&lt;/em&gt; a bug or has a known-acceptable trade-off
(e.g., &lt;code&gt;service_role&lt;/code&gt;'s &lt;code&gt;BYPASSRLS&lt;/code&gt; on Supabase is intentional
— but &lt;code&gt;pgrls.toml&lt;/code&gt;'s &lt;code&gt;allowlist&lt;/code&gt; lets the operator mark it as
acknowledged rather than silently ignored).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a finding doesn't apply to your project, it's an allowlist&lt;br&gt;
entry, not a bug in the linter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[lint.rules.SEC016]&lt;/span&gt;
&lt;span class="py"&gt;allowlist&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"service_role"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try it against your own schema
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pgrls
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'postgres://…'&lt;/span&gt;
pgrls lint &lt;span class="nt"&gt;--schemas&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're on Supabase, the dev workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;supabase start
&lt;span class="nv"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;supabase status &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;env&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;DB_URL | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-f2&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
pgrls lint &lt;span class="nt"&gt;--schemas&lt;/span&gt; public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or as a one-step GitHub Action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pgrls/pgrls-action@v1&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;database-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SUPABASE_DB_URL }}&lt;/span&gt;
    &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you share a (sanitized) policy that pgrls misses or&lt;br&gt;
misclassifies, the catalog grows from real schemas, not synthetic&lt;br&gt;
test fixtures. Drop a thread at&lt;br&gt;
&lt;a href="https://github.com/pgrls/pgrls/discussions" rel="noopener noreferrer"&gt;github.com/pgrls/pgrls/discussions&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;47 rules total, 12 with mechanical auto-fixes. MIT,&lt;br&gt;
framework-agnostic, runs against any Postgres 15+. Source:&lt;br&gt;
&lt;a href="https://github.com/pgrls/pgrls" rel="noopener noreferrer"&gt;github.com/pgrls/pgrls&lt;/a&gt;. Docs:&lt;br&gt;
&lt;a href="https://pgrls.github.io/pgrls-docs/" rel="noopener noreferrer"&gt;pgrls.github.io/pgrls-docs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>postgres</category>
      <category>security</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
