Skip to content

feat(linter): add rollback compatibility rules - #1381

Closed
t-monaghan wants to merge 15 commits into
sbdchd:masterfrom
t-monaghan:compat-rules-extended
Closed

t-monaghan wants to merge 15 commits into
sbdchd:masterfrom
t-monaghan:compat-rules-extended

Conversation

@t-monaghan

@t-monaghan t-monaghan commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Detect PostgreSQL migrations that can break an application-only rollback. The migration and data written by the new application remain in place when the old application returns.

Context

Migration availability and application compatibility are different checks. NOT VALID avoids checking existing rows but still restricts new writes; CONCURRENTLY limits index-creation locking but a unique index still rejects duplicates. The new opt-in rules identify operations that need application context. A lint result does not prove rollback compatibility.

New default rules

  • ban-drop-extension: DROP EXTENSION can remove functions, types, and operators still used by the old application.
  • ban-drop-generated-expression: DROP EXPRESSION changes a generated column into an ordinary column.

ban-drop-constraint and ban-alter-identity are now enabled by default. Dropping a unique constraint can make an old INSERT ... ON CONFLICT fail immediately. The generated-expression rule is split: replacement with SET EXPRESSION and addition of a generated column remain opt-in under ban-alter-generated-expression.

New opt-in rules

  • ban-new-write-restriction: new table, domain, and foreign-table restrictions, including NOT VALID constraints, NOT NULL, unique indexes created CONCURRENTLY, and tighter constraint enforcement or timing, can reject old-application writes. Suppressions for objects unconditionally created earlier in the migration are statement-level approximations, not schema knowledge.
  • ban-add-enum-value: the new application can write a label that an old decoder or workflow does not handle. Includes BEFORE, AFTER, and IF NOT EXISTS.
  • ban-add-composite-attribute: an added attribute can change positional composite input and result decoding.
  • ban-detach-inheritance: DETACH PARTITION and NO INHERIT can remove rows from queries through a parent table.
  • ban-alter-sequence-values: sequence and identity-sequence option changes or restarts can reissue identifiers or change their supported range.
  • ban-create-policy, ban-alter-policy-roles, ban-alter-policy-condition, and ban-alter-row-level-security: policy and RLS changes can hide rows, reject writes, or change access for the old application's role.
  • ban-alter-function-options, ban-alter-view-options, ban-alter-role-options, and ban-alter-database-options: option changes can change permissions, query behavior, or the ability of the old application to connect.

Extended existing rules

  • Rename, column, constraint, default, nullability, drop, privilege, replacement, and schema-move rules cover additional PostgreSQL variants: domains, composite attributes, foreign tables, views, routines, aggregates, operators, casts, roles, ownership, and constraints marked NOT ENFORCED.
  • ban-disable-trigger detects replica-only trigger and rule firing, which stops them from firing on normal application writes, as well as the relevant RLS enforcement variants. Diagnostics distinguish lost side effects from access errors.
  • ban-alter-generated-expression detects SET EXPRESSION. Stored-value rewrites are an availability concern separate from whether old clients understand the resulting values.

The PR adds tests, diagnostics, rule documentation, changelog entries, and an application rollback verification guide. The guide covers data migrations, procedural SQL, privileges, plain TRUNCATE, and old-application tests that a statement-level linter cannot replace.

Verification

  • cargo test --workspace with Rust 1.94 and offline vendored dependencies: all tests passed (one ignored).
  • cargo check --workspace and cargo fmt --all --check passed.
  • Test default and opt-in registration, explicit exclusion, ignore comments, SQL variants, and diagnostic snapshots.
  • Apply a representative migration; let the new application write data; run each allowed rollback version against that database with its actual database role. Check reads, writes, decoding, authorization, identifier generation, and database side effects.

@netlify

netlify Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

👷 Deploy request for squawkhq pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 113084f

@t-monaghan
t-monaghan force-pushed the compat-rules-extended branch from ae9caf5 to 15d732b Compare October 5, 2026 00:42
@t-monaghan
t-monaghan marked this pull request as draft October 5, 2026 00:45
@t-monaghan t-monaghan closed this Oct 5, 2026
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.

1 participant