Skip to content

feat(linter): extend rollback compatibility rules - #1382

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

t-monaghan wants to merge 21 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

At Culture Amp we are proposing to use Squawk to review SQL migrations and to give us confidence that we can roll back our applications. As we adopt blue/green deployments, this check becomes more important: an earlier application revision may need to run against a database that has already been migrated.

Rolling back the application does not roll back the database migration or remove data written by the newer revision. The earlier revision must still be able to read and write using the migrated database. We want Squawk to flag migrations that could break functionality if we deploy an earlier application revision, such as changes to columns, write restrictions, or permissions. These rules add those compatibility checks so we can review the risks before deployment. They increase our confidence in application rollback, alongside testing earlier revisions against the migrated database.

Context

Default rules flag operations that directly change or remove database contracts used by earlier application revisions. Opt-in rules flag operations whose compatibility depends more on application usage or database configuration.

This PR adds 33 rules (9 default, 24 opt-in) and extends 9 existing rules.

New default rules

  • ban-drop-schema, ban-drop-sequence, ban-drop-domain detect DROP SCHEMA, DROP SEQUENCE, and DROP DOMAIN. Queries that reference the dropped object fail.
  • ban-drop-constraint detects DROP CONSTRAINT. Dropping a unique constraint can make an old INSERT ... ON CONFLICT fail.
  • ban-drop-generated-expression detects DROP EXPRESSION, which changes a generated column into an ordinary column.
  • ban-drop-extension detects DROP EXTENSION, which can remove functions, types, and operators used by the old application.
  • ban-alter-identity detects identity column additions, changes, and removals. For example, changing id to GENERATED ALWAYS rejects an earlier application's INSERT INTO t (id) VALUES (1) unless it uses OVERRIDING SYSTEM VALUE. An application that omits id may continue to work.
  • renaming-object detects renames of views, sequences, types, enum values, foreign tables, routines, aggregates, roles, databases, triggers, policies, and constraints.
  • ban-set-schema detects SET SCHEMA on tables, foreign tables, views, types, sequences, functions, procedures, routines, aggregates, and extensions.

New opt-in rules

  • ban-alter-generated-expression detects added generated columns and SET EXPRESSION. Stored-value rewrites are an availability concern separate from whether old clients understand the new values.
  • ban-drop-index detects DROP INDEX, which can remove a unique or exclusion guarantee.
  • ban-set-default detects SET DEFAULT on table, foreign table, view, and domain columns.
  • ban-disable-trigger detects disabling or enabling triggers and rules, replica-only or always firing, and FORCE / NO FORCE ROW LEVEL SECURITY. Diagnostics distinguish lost side effects from access errors.
  • ban-replica-identity detects replica identity changes, dropped publications, and changes to published tables or options.
  • ban-drop-policy detects DROP POLICY and DROP RULE.
  • ban-revoke detects REVOKE, ALTER GROUP ... DROP USER, DROP ROLE, OWNER TO, REASSIGN OWNED, and DROP OWNED.
  • ban-replace-view-function detects CREATE OR REPLACE on views, functions, procedures, triggers, rules, and aggregates.
  • ban-create-policy, ban-alter-policy-roles, ban-alter-policy-condition, and ban-alter-row-level-security detect policy and RLS changes that can change access for the old application's role.
  • ban-alter-function-options, ban-alter-view-options, ban-alter-role-options, ban-alter-database-options, and ban-alter-system-options detect option and configuration changes that can affect permissions, connection behavior, name resolution, or results. ban-alter-function-options covers procedures and routines; ban-alter-role-options covers ALTER USER.
  • ban-alter-extension detects extension updates and member removal. Extension schema moves use ban-set-schema.
  • ban-new-write-restriction detects new table, domain, and foreign-table restrictions, including NOT VALID constraints, NOT NULL constraints, constrained added columns, unique indexes built CONCURRENTLY, and tighter constraint timing or enforcement.
  • ban-add-column detects columns added to existing tables and foreign tables. Added columns can change SELECT * results and break positional inserts.
  • ban-add-enum-value and ban-add-composite-attribute detect new values or attributes that can break old decoders and positional composite input.
  • ban-detach-inheritance detects DETACH PARTITION and NO INHERIT, which can remove rows from parent-table queries.
  • ban-alter-sequence-values detects sequence and identity-sequence changes that can reissue identifiers or change their range. It excludes options that do not change generated values.

Extended existing rules

  • adding-not-nullable-field, ban-drop-default, ban-drop-not-null: also check domains and foreign tables; ban-drop-default also checks view columns.
  • ban-drop-column, changing-column-type, renaming-column: also check foreign tables and composite type attributes; renaming-column also checks views and materialized views.
  • ban-drop-function: also checks DROP AGGREGATE and DROP ROUTINE.
  • ban-drop-table: also checks DROP FOREIGN TABLE.
  • ban-drop-type: also checks DROP OPERATOR, DROP OPERATOR CLASS, DROP OPERATOR FAMILY, and DROP CAST.

For objects created unconditionally earlier in the migration, some rules suppress warnings. This is a statement-level approximation: the linter does not query the schema.

The PR adds tests, diagnostics, rule documentation, and changelog entries.

Verification

  • cargo test -p squawk-linter --lib: 444 passed, 0 failed (Rust 1.98.1 with native macOS linker).
  • git diff --check passed.
  • The prebuilt CLI parsed the new ALTER SYSTEM, ALTER EXTENSION, and ALTER AGGREGATE test statements without syntax errors.
  • Run cargo test --workspace with a compatible Rust toolchain.
  • 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 f363bb6

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