Skip to content

Releases: Goldziher/scythe

v0.10.0

14 Jun 14:46
v0.10.0
8325a95

Choose a tag to compare

Highlights — Phase 0 of `scythe inspect`

This release introduces a new product surface for scythe: live-database operational health checks. Static linting catches problems visible in the SQL text; `scythe inspect` catches the ones that only emerge in a running database — foreign keys without covering indexes, tables with policies but Row Level Security disabled, duplicate indexes. Same `Finding` shape, same human / SARIF 2.1.0 / JSON reporters, same severity model and exit-code semantics as `scythe audit`.

This is Phase 0 of a five-phase delivery. See `docs/guide/inspect.md` for the full roadmap through v0.14.0.

Phase 0 check catalog

ID Name Severity Detection
SC-INS01 missing-fk-index warn Foreign-key columns without a covering index — sequential scan on every join.
SC-INS02 policy-exists-rls-disabled error Table has `CREATE POLICY` definitions but `ROW LEVEL SECURITY` is disabled — policies never apply.
SC-INS03 duplicate-index warn Two or more indexes on the same table have identical definitions modulo name.

Detection patterns are clean-room reimplementations of the equivalent supabase/splinter lints (0001, 0006, 0009). No source copied; `ATTRIBUTIONS.md` updated.

What ships

  • `scythe inspect ` subcommand with `--format`, `--severity`, `--exit-zero`, `--output`, `--dialect`, `--list-checks` flags. URL resolves from positional arg → `$DATABASE_URL` → `$SCYTHE_DATABASE_URL`.
  • New `scythe-inspect` crate carrying a `DbDriver` async trait, a tokio-postgres-backed `PostgresDriver`, and a `MysqlDriver` stub (keeps the trait shape engine-agnostic ahead of Phase 3 MySQL work).
  • Public `scythe-inspect` pre-commit hook published via `.pre-commit-hooks.yaml`. CI-mode hook: `always_run: true`, `pass_filenames: false`, requires `$DATABASE_URL` (or `$SCYTHE_DATABASE_URL`) in the hook environment. Phase 1 will add `scythe.toml` `[inspect]` URL sourcing so local pre-commit use becomes natural.
  • New CI workflow `.github/workflows/inspect-live.yml` runs the live integration tests against a `postgres:16-alpine` service.
  • New docs page `docs/guide/inspect.md` — quick-start, check catalog, severity/exit-code semantics, GitHub Actions recipe, phased roadmap.

Phased roadmap

Phase Release Theme Engines Checks added
0 v0.10.0 (this) MVP scaffold + 3 checks PG (MySQL stub) SC-INS01..03
1 v0.11.0 Full PG check pack + TOML rule registry + `--explain` + `[inspect]` config PG SC-INS04..10
2 v0.12.0 Schema drift — declared catalog vs live PG SC-DFT01..05
3 v0.13.0 MySQL driver + initial MySQL check pack PG + MySQL SC-INS-MY01..06
4 v0.14.0 Stats-based — unused indexes, slow queries via `pg_stat_*` PG SC-INS-STAT01..04

Upgrade notes

  • Pin pre-commit hooks to `rev: v0.10.0` to pick up `scythe-inspect`.
  • The `scythe-inspect` hook is CI-mode only at Phase 0 (needs `$DATABASE_URL` in env). Local pre-commit runs without the variable will fail loudly. This is intentional; Phase 1 makes local use natural.
  • All workspace crate versions bumped 0.9.0 → 0.10.0; the new `scythe-inspect` crate ships at 0.10.0.

See `CHANGELOG.md` for the per-rule, per-flag, per-file breakdown.

v0.9.0

14 Jun 11:11
v0.9.0
e1ca1f6

Choose a tag to compare

Highlights

  • scythe lint now runs the canonical audit rule packs by default, dialect-gated by the configured [[sql]].engine. Rules whose dialects list excludes the engine are silently skipped, so a mysql project does not see postgres-only SC-MIG* findings. No CLI flag — the rules ship in default_registry() and respect the existing [lint] severity overrides.
  • New scythe-audit pre-commit hook published via .pre-commit-hooks.yaml. Runs the SC-SEC*/SC-RLS*/SC-MIG*/SC-CHK* packs over staged .sql files without requiring a scythe.toml. Defaults to postgres; override per-hook with args: [--dialect, mysql].
  • Three new audit rule packs land in this release:
    • Row Level Security — SC-RLS01 policy-references-user-metadata, SC-RLS02 policy-always-permissive, SC-RLS03 policy-uses-uncached-auth-function. Walks CreatePolicy.using / .with_check typed Expr ASTs; SC-RLS03 stops at Expr::Subquery boundaries (the safe form).
    • CHECK quality — SC-CHK01 check-constraint-always-true. Catches column-level, table-level, and ALTER TABLE ADD CONSTRAINT CHECKs whose expression is a tautology (true, 1 = 1, NULL, or parenthesised variants). Lives in a new Antipattern category.
    • Splinter-inspired security/migration ports — SC-SEC12 function-search-path-mutable, SC-MIG19 unsupported-reg-types. Detection logic is clean-room reimplementations against sqlparser ASTs (splinter has no LICENSE file; ATTRIBUTIONS.md documents the courtesy attribution).
  • Migration safety rule pack extended from SC-MIG01..05 to SC-MIG01..19, covering NULL-contract integrity, column-type preferences, constraint-lock hazards, and reg* OID type bans alongside the original DDL hazards.
  • Oracle bindings upgraded to sibyl 0.7. The codegen emitter was rewritten for sibyl 0.7's API breaks: sibyl::prelude removed, Varchar::as_str() no longer returns Result, Date::timestamp() replaced with date_and_time() tuple + chrono. The integration test selects ["tokio", "nonblocking"] because sibyl 0.7's impl Debug for LOB requires one of those cfgs to compile at all. Trade-off: decimal → f64 in the Oracle manifest because sibyl 0.7 has no ToSql/FromSql for rust_decimal::Decimal.
  • sqlx 0.8 → 0.9 in the Rust integration test crates. sqlx 0.9 tightened raw_sql/query to require SqlSafeStr; templates wrap runtime strings with sqlx::AssertSqlSafe.
  • Five test_engines codegen test failures resolved. MSSQL DATETIMEOFFSETdatetime_tz, Redshift SUPERjson, Oracle NUMBER(p, s)decimal (was falling through to the unknown-type fallback). Two stale fixture expectations corrected.
  • Pre-commit hook chain aligned with the polyrepo's shared source. Nine individual hook repos consolidated to kreuzberg-dev/pre-commit-hooks v2.1.10 for general/markdown/rust/shell/actions/typos/ai-rulez. rustdoc-lint, markdownlint-rumdl-strict, and rust-max-lines are listed but commented out with TODOs covering the gaps (~449 missing-doc errors, 35 long-line MD files, 4 source files over 1,000 LOC) — each is its own focused remediation.

See CHANGELOG.md for the full per-rule, per-matcher breakdown.

Upgrade notes

  • Pin pre-commit hooks to rev: v0.9.0 to pick up scythe-audit.
  • Oracle users on Rust: sibyl 0.7 + nonblocking feature is required. The integration test still expects Oracle Instant Client at link time.
  • mysql/sqlite/mssql projects: scythe lint will start running the dialect-agnostic audit rules (SC-SEC01/02/03/06/07/08/09 and SC-CHK01). All postgres-specific rules are silently skipped.

v0.8.0

26 May 13:14
v0.8.0
19bc564

Choose a tag to compare

Added

  • Kotlin extension functions (extension_functions, opt-in) for kotlin-jdbc and kotlin-r2dbc. Generates idiomatic extension functions on the connection receiver — fun Connection.getUser(id: Int), called as connection.getUser(id) — with expression bodies for value-returning queries. kotlin-r2dbc is reworked into a suspend extension on io.r2dbc.spi.Connection. Default off; existing output unchanged. (#43)
  • Configurable PHP namespace (namespace) for php-pdo and php-amphp, enabling PSR-4 framework integration. Default remains App\Generated; an empty string omits the declaration. (#46)

Fixed

  • Postgres 18 compatibility: the schema parser no longer crashes on psql meta-commands (\restrict / \unrestrict) emitted by pg_dump 18+ and dbmate. Such lines are stripped before parsing, so plain-format dumps are consumed as-is. (#49)
  • Python imports: python-psycopg3, python-asyncpg, and python-aiomysql now emit import uuid / from typing import Any when their type mappings need them, fixing a NameError on import of generated modules. (#48)

Full Changelog: v0.7.0...v0.8.0

v0.7.0

20 May 12:01
36693ed

Choose a tag to compare

Added custom annotation capture on parser/analyzer outputs, optional serde derives for public IR types, and Catalog::tables_iter(). Fixed sqlparser 0.62 AST compatibility so cargo clippy --workspace -- -D warnings is clean.

v0.6.13

10 May 16:39
v0.6.13

Choose a tag to compare

Fixed

  • Generated Rust code is now rustfmt-clean — scythe pipes generated .rs files through rustfmt --edition=2024 so downstream projects no longer see whitespace-only diffs after running cargo fmt. Falls back gracefully to unformatted output if rustfmt isn't on PATH.

Tests

  • Regression tests assert embedded SQL preserves original casing of LEAST/COALESCE/SUM and the as alias keyword.

v0.6.12

07 May 14:44
c78c1de

Choose a tag to compare

Fixed

  • The 0.6.11 ON CONFLICT preprocessor scanned the raw SQL byte string, so text inside -- line comments and '…' literals could trigger the predicate-stripping path and chew into the surrounding INSERT body. The scanner now runs against an ASCII-uppercase mask where comments + string literals are replaced with same-length spaces, so positions still line up but only structural SQL is matched.

Supersedes v0.6.11; please skip directly to v0.6.12 if you haven't installed v0.6.11 yet.

v0.6.11

07 May 14:33
6226c27

Choose a tag to compare

Fixed

  • PostgreSQL: accept INSERT … ON CONFLICT (cols) WHERE … DO … (the index-inference form for partial unique indexes). sqlparser-rs through 0.61 doesn't recognise the predicate, so scythe now strips it for the parser pass while keeping the original SQL for codegen and runtime, where Postgres validates and uses the predicate to pick the matching partial index. Mirrors the existing dialect-preprocess pattern used for Oracle and MSSQL.

v0.6.10

06 May 08:43
ce6e249

Choose a tag to compare

Fixed

  • Clippy warnings in scythe-lint style rules (collapsible_match) and typescript-postgres backend (unnecessary_sort_by)

Changed

  • Fixture data for pending engines (MSSQL, Oracle, Redshift, Snowflake) moved from engines_pending/ to testing_data/engines_pending/ — all fixtures now under one directory
  • Updated pre-commit hooks: ai-rulez v4.1.6, rumdl v0.1.88, cargo-sort v2.1.4
  • Bumped integration test dependencies: rand 0.8.5 → 0.8.6, pgx/v5 5.7.4 → 5.9.2, gosnowflake 1.10.1 → 1.13.3, snowflake-sdk 1.15.0 → 2.0.4, snowflake-jdbc 3.16.1 → 4.0.2

Full changelog: https://github.com/Goldziher/scythe/blob/main/CHANGELOG.md

v0.6.9

15 Apr 18:27
v0.6.9
54412ac

Choose a tag to compare

What's New

Pre-commit dialect auto-detection

scythe fmt and scythe lint now automatically read the SQL dialect from scythe.toml when files are passed directly by pre-commit hooks. Previously, the dialect defaulted to "ansi" unless explicitly specified via --dialect.

Integration test fixes

  • 31/35 tests passing across 8 database engines
  • Fixed PHP amphp PostgreSQL (autoload + API compatibility)
  • Fixed Ruby/PHP SQLite :exec query handling
  • Fixed Kotlin SQLite Float type literals
  • Fixed Oracle Go EZ Connect format
  • Fixed MariaDB C# UUID type casting
  • Fixed Elixir Ecto/jamdb Oracle backends
  • Snowflake CI simplified to Python fakesnow (no Docker emulator needed)
  • Oracle CI: added Instant Client SDK for ruby-oci8

Known limitations

  • MSSQL Elixir TDS: parameter encoding (#28)
  • Snowflake: only Python tested via fakesnow; other drivers need emulator support (#27)
  • Oracle ruby-oci8: native extension build may fail without SDK headers

v0.6.8

15 Apr 06:02
v0.6.8
7c43817

Choose a tag to compare

What's New

MSSQL Support (9/10 backends passing)

  • Full integration tests: Rust (tiberius), Python (pyodbc), Go (go-mssqldb), TypeScript (mssql), Java (JDBC), Kotlin (JDBC), C# (SqlClient), Ruby (TinyTds), PHP (PDO)
  • OUTPUT INSERTED preprocessing for parser compatibility
  • CI with SQL Server 2022 Docker

Redshift Support (13/13 backends passing)

  • All PostgreSQL-compatible drivers with Redshift-specific manifests
  • PG-compatible schema for CI testing
  • IDENTITY(N,N) schema preprocessing

Snowflake Support (Python passing via fakesnow)

  • Python integration tests using fakesnow (DuckDB-backed)
  • TIMESTAMP_NTZ, TIMESTAMP_TZ, TIMESTAMP_LTZ, VARIANT type mappings
  • CI with snowflake-emulator Docker

Other Fixes

  • CI: libaio1libaio1t64 for Ubuntu 24.04
  • CI: SQLite create_if_missing(true)
  • Go codegen: @pN placeholder rewriting for MSSQL
  • Rust tiberius codegen: proper &dyn ToSql param binding
  • Ruby TinyTds codegen: type-aware inline value interpolation
  • TypeScript mssql codegen: explicit sql.* type bindings

Total: 89 integration test backends across 8 database engines