pgsafe 0.11.0

Static safety linter for PostgreSQL DDL migrations — catches unsafe schema changes before they lock or break production.
Documentation
# Changelog

All notable changes to pgsafe are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.11.0] - 2026-07-12

### Added

- New rule `drop-database` (Warning): flags `DROP DATABASE` as irreversible data loss (#95).
- New rule `drop-not-null` (Warning): flags `ALTER COLUMN … DROP NOT NULL` removing a relied-on not-null invariant (#95).
- New rule `add-domain-constraint-without-not-valid` (Error): flags `ALTER DOMAIN … ADD CONSTRAINT` that validates dependent tables under lock; autofixes to `NOT VALID` (#95).
- New opt-in rule `require-schema-qualified` (Warning): flags DDL target relations named without a schema qualifier — CREATE/ALTER/RENAME/DROP/TRUNCATE/CREATE INDEX targets — which resolve through `search_path` (#95).
- New rule `prefer-identity` (Warning): prefers `GENERATED … AS IDENTITY` over `serial`; autofixes `serial` in a `CREATE TABLE` to a width-preserving identity column (#95).
- New rule `add-domain-not-null` (Error): flags `ALTER DOMAIN … SET NOT NULL` (and the PG17+ `ADD NOT NULL`), which scans and write-locks every dependent table and (unlike a CHECK) cannot be added `NOT VALID` (#95).

### Changed

- `--fix` / `--diff` now apply fixes iteratively to a fixpoint (bounded at 10
  passes), so a fix that unblocks another is fully resolved in one run. No change
  for current rules (all converge in a single pass); the loop never writes SQL
  that fails to parse or introduces a new error.
- Human output indent-aligns the continuation lines of multi-line statements so wrapped SQL stays readable (#92).

### Fixed

- `--fix` no longer adds `CONCURRENTLY` to index operations inside an explicit transaction block, where it would be invalid (#91).
- `--fix` now inserts a statement-body fix (e.g. `NOT VALID`) before a trailing comment instead of inside it, when the statement has a trailing comment and no terminating `;`. Previously the fix landed within the comment (leaving the hazard unfixed) and the fixpoint loop failed to converge (#102).

## [0.10.0] - 2026-07-06

### Added

- Colorized human output — severity-colored findings, bold rule IDs, dimmed fix suggestions, and an end-of-run summary line (#89).
- `--color <auto|always|never>` controls colorized output; `auto` respects whether stdout is a TTY and honors `NO_COLOR`. With color off, output is byte-for-byte unchanged (#90).

### Changed

- `vacuum-full-cluster` guidance now recommends the built-in `REPACK (CONCURRENTLY)` where available (#87).
- Parser access is isolated behind a `pgsafe::ast` seam, decoupling the linter from the underlying parser (#88).
- Reusable color palette and painters (`Styling`, `ColorWhen`) are exposed for library consumers (#90).

## [0.9.1] - 2026-07-05

### Added

- `pgsafe::VERSION` constant exposing the crate version to library consumers (#86).

### Documentation

- New Usage page; site reorganized to separate reference from how-to guides (#85).

## [0.9.0] - 2026-07-05

### Added

- Published to crates.io — install with `cargo install pgsafe` (#68, #70).
- `--fix` / `--diff` — apply autofixes in place or preview them as a patch (#72, #73, #80).
- `--format sarif` — SARIF 2.1.0 output for GitHub code scanning, with stable `partialFingerprints` for finding de-duplication (#81, #82).

### Changed

- `--diff` output is now `git apply`-able, and in-place fixes are written atomically (#83).

### Fixed

- `require-timeout` places the synthesized `SET` prologue correctly above leading directive comments, own-line directives on non-first statements, and multi-line block-comment directives (#75, #77, #78).

### Documentation

- Playground gained Fix/Ignore buttons and example seeding; Ignore and rule links are gated to real lint rules (#74, #76).

## [0.8.6] - 2026-06-30

### Added

- `pgsafe --list-rules` prints the authoritative rule catalog in human or JSON form.

### Changed

- `attach-partition` escalates ATTACH of a pre-existing child table to an error (#65, #66).

### Documentation

- Launched the pgsafe website (Astro): getting-started, CI, config, and output guides, plus a deep-linkable per-rule reference.
- Added an interactive **playground** that lints SQL in the browser via WebAssembly, with an examples gallery and shareable permalinks.

## [0.8.5] - 2026-06-29

### Changed

- Pin third-party and GitHub-owned Actions to commit SHAs; pin build provenance to the release workflow.

## [0.8.4] - 2026-06-29

### Added

- The GitHub Action verifies build provenance when it downloads pgsafe binaries.

## [0.8.3] - 2026-06-29

### Added

- Release binaries carry signed build-provenance attestations; releases publish via draft → upload → publish.

## [0.8.2] - 2026-06-29

### Changed

- The GitHub Action accepts multiple file globs.

### Documentation

- The Action's inputs are documented as a table.

## [0.8.1] - 2026-06-29

### Added

- Official pgsafe **GitHub Action** (composite) that runs the linter and posts inline PR annotations.

## [0.8.0] - 2026-06-29

### Added

- `--format github` — GitHub Actions workflow-annotation output.

## [0.7.0] - 2026-06-29

### Added

- `pgsafe --example-config` prints an annotated starter `pgsafe.toml`.

## [0.6.0] - 2026-06-28

### Changed

- Human output groups findings by statement so multiple findings on one statement no longer run together.

## [0.5.0] - 2026-06-29

### Added

- Opt-in policy lints, configurable via `pgsafe.toml`: `require-primary-key`, `require-not-null`, `require-comment`, `require-columns`, `require-if-exists`, `naming-convention`, `forbid-nullable-fk`, and `forbidden-column-type`.
- New hazard rules: `add-trigger`, `drop-constraint`, `identifier-too-long`, `fk-without-covering-index`, `attach-partition`, `detach-partition-non-concurrent`, `set-access-method`, and `enum-value-used-in-transaction`.
- `unchecked-do-block` (opt-in), plus static linting of the SQL inside `DO` blocks.
- `--version` flag.
- Prebuilt release binaries for Linux and macOS.

### Changed

- `alter-column-type` warns about cached-plan invalidation even for non-rewriting type changes.
- `rename` covers `ALTER TYPE … RENAME`; `require-if-exists` covers `CREATE MATERIALIZED VIEW` and `CREATE TABLE AS`.
- Config discovery also finds a non-dotfile `pgsafe.toml`.

## [0.4.0] - 2026-06-27

### Added

- `--git-diff` and `--since` changed-files selection — lint only the migrations that changed.
- `resolve()` front-end API seam that combines config and input selection.

## [0.3.0] - 2026-06-27

### Added

- `pgsafe.toml` configuration file — disable rules, override severities, set per-file options, and ignore paths with gitignore-style globs.
- New rules: `require-timeout` (engine-synthesized), `prefer-bigint-primary-key`, and `prefer-jsonb`.

## [0.2.0] - 2026-06-26

### Added

- `--in-transaction` flag and `LintOptions.assume_in_transaction`; `lint_sql` / `lint_input` now take `&LintOptions`.
- Rule-proving harness — DB-backed proofs that each rule's lock/rewrite claim holds against a real PostgreSQL server.

## [0.1.0] - 2026-06-26

Initial release.

### Added

- Postgres migration-safety linter with a rule engine, human and JSON output, stdin/file input, and CI-friendly exit codes.
- Library-first API (`lint`, `render`, `gate`) built with `forbid(unsafe_code)`.
- Initial rule set for lock- and rewrite-hazardous DDL: non-concurrent index build, foreign-key/check constraint without `NOT VALID`, `SET NOT NULL`, `ALTER COLUMN … TYPE`, renames, table/column/index drops, `TRUNCATE`, `VACUUM FULL` / `CLUSTER`, non-concurrent `REINDEX`, and `ADD COLUMN` with a volatile default, serial, identity, or stored-generated value, among others.
- Inline `pgsafe:ignore` suppression engine.
- `--fail-on` severity threshold to gate CI on findings.

[Unreleased]: https://github.com/fixed-width/pgsafe/compare/v0.11.0...HEAD
[0.11.0]: https://github.com/fixed-width/pgsafe/compare/v0.10.0...v0.11.0
[0.10.0]: https://github.com/fixed-width/pgsafe/compare/v0.9.1...v0.10.0
[0.9.1]: https://github.com/fixed-width/pgsafe/compare/v0.9.0...v0.9.1
[0.9.0]: https://github.com/fixed-width/pgsafe/compare/v0.8.6...v0.9.0
[0.8.6]: https://github.com/fixed-width/pgsafe/compare/v0.8.5...v0.8.6
[0.8.5]: https://github.com/fixed-width/pgsafe/compare/v0.8.4...v0.8.5
[0.8.4]: https://github.com/fixed-width/pgsafe/compare/v0.8.3...v0.8.4
[0.8.3]: https://github.com/fixed-width/pgsafe/compare/v0.8.2...v0.8.3
[0.8.2]: https://github.com/fixed-width/pgsafe/compare/v0.8.1...v0.8.2
[0.8.1]: https://github.com/fixed-width/pgsafe/compare/v0.8.0...v0.8.1
[0.8.0]: https://github.com/fixed-width/pgsafe/compare/v0.7.0...v0.8.0
[0.7.0]: https://github.com/fixed-width/pgsafe/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/fixed-width/pgsafe/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/fixed-width/pgsafe/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/fixed-width/pgsafe/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/fixed-width/pgsafe/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/fixed-width/pgsafe/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/fixed-width/pgsafe/releases/tag/v0.1.0