cratefield-import-supabase
The engine of the Supabase importer (ADR 0026),
step one (issue #658): inspect a Supabase project read-only and produce
the migration report — every schema object, RLS policy, auth provider,
storage bucket, Edge Function and Realtime publication, each classified as
automatic, needs work or a blocker, with the data size and a rough transfer
time. fz import supabase inspect is its command-line front end; the
dashboard's "Migrate from Supabase" button will drive the same engine.
Native only: it reads Postgres through sqlx, and fails to compile on wasm with a message saying so.
Usage
use ;
# async
InspectOptions also takes a ManagementApi (Edge Functions and the auth
configuration, over the HttpClient port) and an optional Classifier
(for RLS policies no rule places) with its threshold.
Auth users (issue #659)
read_users and record_mapping are step two: moving the people. Inside
the same read-only snapshot inspect takes, read_users reads
auth.users and auth.identities and plans each account for the harness
admin import (POST /v1/auth-core/admin/users/import) — its address,
whether the source confirmed it, its bcrypt hash verbatim (upgraded to
argon2id on the first sign-in), and the OIDC links the harness can hold.
A phone-only or anonymous account is skipped, an OAuth provider the
harness has no slug for is reported unmapped, and each user's metadata
goes to the import_supabase_users mapping table record_mapping writes
in the target database, which the data step rewrites references through.
A role that cannot bypass row-level security on auth.users or
auth.identities is refused before a row is read, rather than silently
reading nothing.
Guarantees
- Read-only, checked. One connection, its session default read-only,
every read in one
REPEATABLE READ READ ONLYtransaction that is rolled back; before the rollback, Postgres must not have assigned a transaction id, or the inspection fails. The report records this evidence, and whether the role used could have written. - No secret in the output. The database URL and the token are held
cleared-on-drop and print as
[redacted]; errors strip them; the report names the database by host, port and database only; SQL fragments pass through the harness's scrubber; only the auth configuration's…_enabledbooleans are read. No password hash, email or row is read into the report. - RLS is advice, not translation. Each policy gets a pattern (rules
first, then optionally the classifier, above a threshold), a suggested
check, a failing test stub and
disposition: undecided. - A stable JSON.
report_version2, sorted lists, no timestamp — documented indocs/import/supabase-report.md.
Tests
tests/inspect.rs loads tests/fixtures/supabase-project.sql — a
Supabase-shaped project on plain Postgres 16 — into a throwaway database
on FZ_TEST_POSTGRES_URL (CI's service container) and snapshots the
report. The tests skip, saying why, when the variable is unset.