RowShield
Guides

Adding a policy check to your Supabase CLI workflow today

The Supabase CLI already gives your database changes a front door: migrations live in files, reviews happen in pull requests, deploys run through one command. A security check belongs behind the same door, at the same moment — after the migration applies, before you consider the deploy finished.

RowShield's CLI provides that step as a shipped interface, not a roadmap item. One command scans the project's catalog metadata, applies the nine rules covering disabled, absent and tautological policies, missing WITH CHECK clauses, public buckets, unindexed predicates, unwrapped auth calls and key exposure, and prints generated remediation SQL when anything fails. This page is workflow guidance rather than a detection claim: the checks themselves are automated by the scanner, and what you add is the habit of running them in sequence.

RowShield does not detect this yet. This guide gives you the catalog queries to check it yourself. The nine rules that do ship are listed on the rules index.

The command and its contract

The scan command takes a connection string, a severity threshold and an output preference, and it communicates its verdict entirely through exit codes rather than prose. The --sql flag prints remediation SQL alongside each finding — generated from your actual columns, owner-scoped, FORCE ROW LEVEL SECURITY included:

Exit codes are designed for scripts: 0 means clean, 1 means findings at or above the threshold exist, and 2 means the run itself broke — bad credentials, unreachable host. Distinguishing 1 from 2 matters, because a red build for a broken run says nothing about posture and should not be read as one.

rowshield scan --db-url "$DATABASE_URL" --fail-on high --sql
# exit 0 = clean
# exit 1 = findings at or above the threshold
# exit 2 = the run itself failed

Wiring it into the flow

The natural home for the check is immediately after migrations apply and before the deploy counts as finished. A package script keeps the invocation in version control where reviews can see it, instead of in documentation where it quietly rots:

Run manually during development, or as a step in whatever runs your deploys — the command is a plain executable and asks for nothing beyond the connection string. For the outside-in half of the picture, probe the deployed app once the deploy lands; the probe needs only the public URL:

{
  "scripts": {
    "db:secure": "rowshield scan --db-url \"$DATABASE_URL\" --fail-on high --sql"
  }
}

# after deploy: outside-in check of the public surface
rowshield probe https://your-app.example.com

Reading failures correctly

An exit of 1 lists every finding at or above threshold with its rule, rationale and generated fix. Treat the printed SQL as a proposal to review, not a patch to blind-apply: applying access-control changes belongs in a migration like any other schema work, reviewed and reversible.

An exit of 2 means the audit did not happen, which is a different problem class entirely — fix connectivity first and resist marking the step optional, because a skipped check and a passing check look identical in a log unless the exit codes are explicit.

What this does not cover

Stated plainly: a local CLI run audits one moment. It cannot watch the interval afterwards, alert anyone when a later migration regresses a fix, or record transitions over time — that is what scheduled scans add, with alerts delivered as email, Slack Block Kit, Discord embeds or generic webhooks depending on plan.

Nothing else on this page is a promise either way: the CLI and scheduled scans are shipped interfaces, while deeper CI wrappers remain planned. RowShield is an independent product, unaffiliated with and not endorsed by Supabase. Start without any setup at all — run the free audit at rowshield.dev/audit.

Frequently asked

What do the RowShield CLI exit codes mean?
Zero means the scan ran and found nothing at or above threshold; one means the scan ran and found something at or above threshold; two means the scan could not complete, such as bad credentials or an unreachable host. Scripts branch on these directly.
Does the CLI need my production database credentials?
The scan connects with a Postgres connection string and reads catalog metadata only — pg_catalog and bucket metadata, never table rows. Many teams use a dedicated read-capable role so the credential's power matches the task.
How is this different from probing my deployed app?
The scan reads configuration from inside Postgres and evaluates nine rules; the probe speaks HTTP to the deployed surface using only the public anon key and reports what unauthenticated callers actually receive. The two halves catch different failure classes.

Check your project in about ten seconds

Paste a URL. No signup, no writes, nothing stored.

Run the free audit
supabase cli security checksupabase cli rls scanrowshield cli exit codespostgres security cli step