Skip to content

feat(linter): add default rollback compatibility rules - #1383

Merged
kodiakhq[bot] merged 1 commit into
sbdchd:masterfrom
t-monaghan:compat-default-split
Oct 5, 2026
Merged

kodiakhq[bot] merged 1 commit into
sbdchd:masterfrom
t-monaghan:compat-default-split

Conversation

@t-monaghan

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

Copy link
Copy Markdown
Contributor

Purpose

At Culture Amp the SRE team are proposing using Squawk to review SQL migrations and to increase 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.

These default rules flag migration operations that directly change or remove database contracts used by earlier application revisions. They help identify risks before deployment, alongside testing earlier revisions against the migrated database.

Context

This PR adds nine rules enabled by default:

  • ban-drop-schema, ban-drop-sequence, ban-drop-domain detect DROP SCHEMA, DROP SEQUENCE, and DROP DOMAIN. Queries that reference a dropped object fail.
  • ban-drop-constraint detects DROP CONSTRAINT. Dropping a unique constraint can make an earlier application's 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 earlier application.
  • ban-alter-identity detects identity column additions, changes, and removals. 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.

This PR also extends nine existing rules:

  • adding-not-nullable-field, ban-drop-default, and ban-drop-not-null also check domains and foreign tables. ban-drop-default also checks view columns.
  • ban-drop-column, changing-column-type, and 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.

The PR includes tests, diagnostics, rule documentation, and a changelog entry.

@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 5cb8256

@t-monaghan
t-monaghan marked this pull request as draft October 5, 2026 05:00
@t-monaghan
t-monaghan force-pushed the compat-default-split branch 5 times, most recently from c2188e3 to 9cc9682 Compare October 5, 2026 05:57
if let ast::Stmt::DropDomain(node) = stmt {
ctx.report(Violation::for_node(
Rule::BanDropDomain,
"Dropping a domain may break existing clients.".into(),

@sbdchd sbdchd Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just out of curiosity, are you using domains? I've heard they're kinda prickly to use in practice

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not, but given the breadth of our services I wouldn't make the assumption that we never will. I'm happy to be guided on this being opt-in if it seems like overkill

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha yeah I think it's fine to lean on by default

"Dropping a table may break existing clients.".into(),
drop_table.syntax(),
));
} else if let ast::Stmt::DropForeignTable(drop_table) = stmt {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@sbdchd sbdchd left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@sbdchd sbdchd added the automerge automerge with kodiak label Oct 5, 2026
@kodiakhq
kodiakhq Bot merged commit 3fa6b86 into sbdchd:master Oct 5, 2026
34 checks passed
@t-monaghan

Copy link
Copy Markdown
Contributor Author

Thanks for the review @sbdchd, I'll polish up #1384 now and mark it as ready

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge automerge with kodiak

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants