Skip to content

fix(drizzle): declare RLS policies and the blob-chunks FK in createSchema() so drizzle-kit stops flagging them as drift - #5

Open
riccardomerlo wants to merge 2 commits into
marcoripa96:mainfrom
riccardomerlo:fix/drizzle-schema-rls-fk
Open

fix(drizzle): declare RLS policies and the blob-chunks FK in createSchema() so drizzle-kit stops flagging them as drift#5
riccardomerlo wants to merge 2 commits into
marcoripa96:mainfrom
riccardomerlo:fix/drizzle-schema-rls-fk

Conversation

@riccardomerlo

@riccardomerlo riccardomerlo commented Aug 31, 2026

Copy link
Copy Markdown

Fixes #4.

What

createSchema() now declares everything drizzle-orm can express, so drizzle-kit sees the full picture instead of flagging the missing pieces as drift:

  • workspace_isolation RLS policies — attached to every table via pgPolicy() (drizzle auto-enables RLS on tables that carry a policy). Opt-out with the new enableRLS: false schema option, mirroring setup() / generateMigrationSQL().
  • fs_blob_chunks → fs_blobs composite FK — declared with foreignKey() under its core-DDL name (fs_blob_chunks_blob_fkey, ON DELETE CASCADE).
  • ltree gist indexes — built with column.op("gist_ltree_ops(siglen=124)") instead of a raw sql`...` expression. Generated SQL is byte-identical, but drizzle-kit can introspect and match the .op() form, so push stops dropping/recreating them on every run.

generateMigrationSQL() shrinks conceptually to what the schema cannot express (extensions, FORCE ROW LEVEL SECURITY) but keeps emitting its idempotent policy/FK blocks as a safety net for pre-existing setups and enableRLS: false schemas. Docs (README + schema page) updated, including the upgrade note below.

Why

On a fully migrated Path A database, drizzle-kit push diffs the TS schema against the live DB and proposed:

ALTER TABLE "fs_entries" DISABLE ROW LEVEL SECURITY;
DROP POLICY "workspace_isolation" ON "fs_entries" CASCADE;
-- ... all six tables
ALTER TABLE "fs_blob_chunks" DROP CONSTRAINT "fs_blob_chunks_blob_fkey";

One accidental confirm away from losing tenant isolation (full story in #4).

Verification

  • vitest run: 1347/1347 (3 new tests in tests/drizzle-schema.test.ts cover the policies, the enableRLS: false opt-out, and the FK shape).
  • End-to-end on a fresh project (npm pack install, drizzle-kit generate + --custom bootstrap + migrate, then push) with drizzle-kit 0.31.10 / drizzle-orm 0.44.7:
    • PostgreSQL 17: push"No changes detected".
    • PostgreSQL 18: only residual churn is fs_blob_chunks' composite PK — an upstream drizzle-kit 0.31.x introspection bug on PG18 (composite PK/UNIQUE on tables with an FK), unrelated to this schema; reproducible on a plain two-column table with no bash-gres involved.

Compatibility notes

  • Peer bump: pgPolicy requires drizzle-orm ≥ 0.36 (Nov 2024), so the peer range moves >=0.30.0>=0.36.0.

  • Existing Path A projects (verified against a snapshot generated with 3.0.0): the first drizzle-kit generate after upgrading emits a migration the bootstrapped database largely already satisfies. Edit it before applying (keep the file — it updates the snapshot):

    • delete the CREATE POLICY and ADD CONSTRAINT fs_blob_chunks_blob_fkey statements — they fail as duplicates on a bootstrapped database;
    • optionally delete the gist-index DROP/CREATE pairs — identical definition (only the schema-side declaration changed from sql`...` to .op()), applying them just rebuilds the indexes and blocks writes meanwhile;
    • the ENABLE ROW LEVEL SECURITY statements are idempotent and safe to keep.

    createSchema({ enableRLS: false }) omits only the policies — the FK and the index-form change still show up in the diff, so the edit above applies either way. All of this is in the schema docs page.

  • Versioning: peer-range narrowing + the one-time migration edit above suggest this ships as a deliberate minor (3.1.0) with a release note rather than a patch — your call.

Happy to split the docs-site edits into a separate commit/PR if you prefer.

… drizzle-kit stops flagging them as drift

createSchema() now attaches the workspace_isolation pgPolicy to every
table (opt-out with enableRLS: false), declares the fs_blob_chunks ->
fs_blobs composite FK under its core-DDL name, and builds the ltree gist
indexes with column.op() instead of a raw SQL expression so drizzle-kit
can introspect and match them.

Before this, drizzle-kit push on a fully migrated database proposed
DISABLE ROW LEVEL SECURITY + DROP POLICY workspace_isolation on all six
tables and DROP CONSTRAINT fs_blob_chunks_blob_fkey — one accidental
confirm away from losing tenant isolation (closes marcoripa96#4).

drizzle-kit generate now emits the policies and FK into migrations;
generateMigrationSQL() shrinks to what the schema cannot express
(extensions, FORCE ROW LEVEL SECURITY) but keeps emitting the idempotent
policy/FK blocks as a safety net for pre-existing setups and
enableRLS: false schemas.

Verified end-to-end (generate + custom bootstrap + migrate + push):
'No changes detected' on PostgreSQL 17; on 18 the only residual churn is
fs_blob_chunks' composite PK, an upstream drizzle-kit introspection bug
unrelated to this schema. Full suite: 1347/1347.

Requires drizzle-orm >= 0.36 (pgPolicy): peer range bumped.
@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the mripa's projects Team on Vercel.

A member of the Team first needs to authorize it.

The first generate after upgrading emits ENABLE RLS (idempotent, keep),
CREATE POLICY + the blob FK (already applied by the bootstrap — delete,
they fail as duplicates) and a gist index recreate (identical definition,
optional to keep). enableRLS: false omits only the policies, so the edit
applies either way. Verified against a snapshot generated with 3.0.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

drizzle adapter: drizzle-kit push proposes dropping the workspace_isolation RLS policies (createSchema() cannot express RLS / the chunks FK)

1 participant