orm-preflight について
orm-preflightは、TypeORMのマイグレーションを検査し、マージ前にデータ損失、テーブルロック、デプロイ上のリスクを検出するコマンドラインツールです。データベース接続は不要で、問題の説明、安全な代替案、CI向けの出力を提供します。
主な機能
- 01マイグレーションのデータ損失リスクを検査
- 02ブロックにつながる可能性のある操作を検出
- 03ローリングデプロイの問題を検出
- 04検出内容と安全な代替案を説明
- 05JSON、GitHub注釈、SARIFで出力
活用シーン
- 01マージ前にTypeORMのマイグレーションを確認
- 02プルリクエスト内の追加・変更分を検査
- 03GitHub Actionsにマイグレーション検査を追加
- 04データ書き換えやテーブルロックの可能性を調査
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
3掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| files | array | いいえ | projectDir からの相対パスで指定するマイグレーションファイルまたは glob です。例:["src/migrations/1727200000000-AddEmail.ts"]。 |
| dialect | enum | いいえ | データベースです。デフォルト:設定値、または postgres。postgres | mysql |
| projectDir | string | いいえ | package.json があるプロジェクトルートの絶対パスです。デフォルト:サーバーの起動時のディレクトリ。 |
| changedSince | string | いいえ | origin/main などの Git 参照です。ブランチがその参照から分岐した後に追加または変更されたマイグレーションのみを確認します。 |
| postgresVersion | integer | いいえ | PostgreSQL のメジャーバージョンです。デフォルト:設定値、または 16。 |
詳細
orm-preflight
TypeORM のマイグレーションを安全に事前チェックします。データ損失やロックをマージ前に検出します。
ドキュメント:https://sikandar100.github.io/orm-preflight/
TypeORM でカラムの長さを変更すると、そのカラムのデータがすべて削除されることがあります。カラムの型や長さが変更されると、TypeORM のマイグレーションジェネレーターはカラムを削除して再度追加します (typeorm/typeorm#3357)。このマイグレーションはレビューでは問題がないように見え、空のデータベースではすべてのテストに合格します。orm-preflight は、こうしたマイグレーションや、データ損失を引き起こす、稼働中のテーブルをロックする、またはローリングデプロイを妨げるほかのマイグレーションを、マージ前に検出します。
src/migrations/1727100000000-WidenUserName.ts
7:30 error no-drop-and-recreate-column
"users"."name" is dropped and re-added in the same migration. Every existing value in this column will be lost.
Why: TypeORM drops and re-adds a column when its type or length changes, instead of changing it in place. The new column starts empty.
Safe: Change the type in place: ALTER TABLE "users" ALTER COLUMN "name" TYPE varchar(255). Widening a varchar, or changing varchar to text, does not rewrite the table. ...
Docs: https://github.com/sikandar100/orm-preflight/blob/main/docs/rules/no-drop-and-recreate-column.md
8:30 error no-add-not-null-without-default
"users"."name" is added as NOT NULL without a default. The migration fails as soon as "users" has any rows.
...
2 errors, 0 warnings in 1 migration
インストールと実行
npm install --save-dev orm-preflight
npx orm-preflight "src/migrations/*.ts"
Node.js 20 以降が必要です。引数を指定しない場合、orm-preflight は設定内の migrations グロブ、またはプロジェクト内のすべての migrations フォルダーをチェックします。
既存プロジェクトで履歴を修正せずに使い始めるには、まず npx orm-preflight init を実行してください
(既存プロジェクトへの導入を参照)。
検出できる問題
| ルール | 検出内容 |
|---|---|
| データ損失 | |
no-drop-and-recreate-column | 1つのマイグレーション内で削除後に再追加されたカラム |
possible-rename-data-loss | データがコピーされずに、あるカラムが削除され、別のカラムが追加されている(警告) |
no-drop-column | 削除されたカラム |
no-drop-table | 削除されたテーブル |
no-truncate | TRUNCATE または clearTable() |
no-truncating-type-change | left() など、USING が各値の一部だけを保持する型変更(警告) |
no-delete-rows | 既存のテーブルに対する DELETE(警告) |
no-null-out-column | カラムを NULL に設定するだけの UPDATE(警告) |
rewrites-existing-rows | 既存のテーブルに対するすべての UPDATE、upsert、または INSERT ... SELECT(レビュー用、情報) |
typeorm/no-changecolumn-recreate | カラムを削除して再追加する changeColumn() |
| デプロイの安全性 | |
no-rename-column | 名前が変更されたカラム |
no-rename-table | 名前が変更されたテーブル |
| ロック(PostgreSQL) | |
require-concurrent-index | CONCURRENTLY を指定しない CREATE INDEX |
concurrent-index-transaction | トランザクション内で実行される CONCURRENTLY |
no-add-not-null-without-default | デフォルト値なしで追加された NOT NULL カラム |
no-volatile-default | 揮発性のデフォルト値を指定して追加されたカラム、またはシリアル、identity、generated として追加されたカラム |
no-unsafe-column-type-change | テーブルを書き換えるカラムの型変更 |
require-not-valid-foreign-key | NOT VALID を指定せずに追加された外部キー |
no-set-not-null | 既存のカラムに対する SET NOT NULL |
require-not-valid-check | NOT VALID を指定せずに追加された CHECK 制約 |
validate-in-same-transaction | NOT VALID で追加した同じトランザクション内での VALIDATE CONSTRAINT(効果がない場合、警告) |
require-concurrent-unique | インプレースで追加された一意制約または主キー |
require-concurrent-index-drop | CONCURRENTLY を指定しない DROP INDEX(警告) |
no-blocking-maintenance | CONCURRENTLY を指定しない VACUUM FULL、CLUSTER、または REINDEX |
enum-value-used-in-same-transaction | 追加するトランザクションがコミットされる前に使用された新しい enum 値 |
require-lock-timeout | lock_timeout を指定しない既存テーブルへの変更(オフ、オプトイン) |
typeorm/no-enum-recreate | 型を再作成する TypeORM 0.3 の enum 変更(警告) |
| 正確性 | |
typeorm/transaction-override-forbidden | トランザクションモードが "all" のときにマイグレーションに設定された transaction |
typeorm/invalid-migration-name | 13 桁のタイムスタンプを含まないマイグレーション名 |
unanalyzable-statement | orm-preflight が解析できなかったステートメント(警告) |
invalid-suppression | 理由がない、または不明なルールを指定した抑制コメント |
no-edit-applied-migration | --changed-since の使用時:ベースブランチにすでに存在するマイグレーションの編集 |
require-down | 空または未定義の down()(警告) |
各指摘では、何が起こるのか、その理由、安全に変更する方法を説明します。各ルールのページでは、主張の根拠となる PostgreSQL、MySQL、または TypeORM のソースを引用しています。npx orm-preflight explain <rule> を実行するとターミナルで内容を確認できます。一覧を見るには npx orm-preflight rules を実行してください。 |
同じマイグレーション内で作成されたテーブルへの変更は報告されません。まだ行が存在しないためです。
コマンドライン
orm-preflight [files or globs...] [options]
-c, --config <path> Config file (default: orm-preflight.config.json, then the
"ormPreflight" key in package.json)
--dialect <postgres|mysql> Database dialect (default: postgres)
--postgres-version <n> PostgreSQL major version the migrations run on (default: 16)
--orm <typeorm> ORM adapter (default: typeorm)
--changed-since <git-ref> Check only migrations added or changed since the merge base
with <git-ref>, such as origin/main
--format <format> pretty, json, github (annotations), or sarif. Default:
github in GitHub Actions, pretty elsewhere
--max-warnings <n> Fail when there are more than n warnings (default: no limit)
--execute Run each migration's up() to see SQL built at run time. This
runs your code: only use it on code you trust
--allow-untrusted-execute Allow --execute under GitHub's pull_request_target event
--no-color Print without colors
orm-preflight rules List every rule
orm-preflight explain <rule> Print a rule's documentation
orm-preflight init [files or globs...] Write a starter config
orm-preflight mcp Run as an MCP server for AI coding agents
| 終了コード | 意味 |
|---|---|
0 | エラーがなく、警告数が --max-warnings 以下 |
1 | エラーがある、または警告数が --max-warnings を超過 |
2 | 使用方法、設定、または内部エラー |
| 形式 | 出力 |
|---|---|
pretty | ファイルごとにグループ化した、人が読みやすい指摘。抑制された指摘は件数のみ表示されます。 |
json | 抑制されたものも含む、すべての指摘。形式は公開 API であり、docs/json-output.md に記載されています。 |
github | プルリクエストの該当行に対する GitHub Actions の注釈と、その後に表示されるサマリー行。 |
sarif | GitHub コードスキャンやその他の SARIF ビューアー向けの SARIF 2.1.0。抑制された指摘も理由とともに保持されます。 |
設定
設定は orm-preflight.config.json に記述するか、package.json の "ormPreflight" キーの下に記述してください。JSON のみをサポートしているため、プルリクエストから設定を通じてコードを実行することはできません。
{
"$schema": "./node_modules/orm-preflight/schema.json",
"orm": "typeorm",
"dialect": "postgres",
"postgresVersion": 16,
"migrations": ["src/migrations/*.ts"],
"startAfter": 1727000000000,
"typeorm": { "transactionMode": "each" },
"rules": { "no-rename-column": "warn" }
}
| キー | 意味 |
|---|---|
migrations | マイグレーションファイルの glob パターン。デフォルト:すべての migrations フォルダー。 |
startAfter | マイグレーションのタイムスタンプ。このタイムスタンプ以前のマイグレーションはチェックされません。 |
postgresVersion | 実行する PostgreSQL のメジャーバージョン。12 以降を指定してください。安全な代替策の一部はバージョンに依存します。デフォルト:16。 |
defaultSchema | スキーマが修飾されていないテーブル名に適用するスキーマ。PostgreSQL でのデフォルト:public。 |
typeorm.transactionMode | DataSource の migrationsTransactionMode と一致させる必要があります。all(TypeORM のデフォルト)、each、または none。 |
rules | ルールごとの重大度:error、warn、info、または off。 |
コマンドラインフラグは設定を上書きします。
各重大度の動作:
| 重大度 | 意味 |
|---|---|
error | 実際の問題です。実行は失敗します(終了コード 1)。 |
warn | 問題の可能性があります。--max-warnings を超えた場合にのみ実行が失敗します。 |
info | 既存の行を書き換えるステートメントなど、把握しておくとよい情報です。実行が失敗することはありません。 |
off | このルールは実行されません。 |
既存のプロジェクトに導入する
npx orm-preflight init
init は startAfter に最新のマイグレーションを設定した orm-preflight.config.json を書き込みます。そのため、これ以降に追加したマイグレーションだけがチェックされます。マイグレーションファイルは読み取りますが、実行することはありません。
プルリクエストでは、ブランチで追加または変更したマイグレーションだけをチェックすることもできます。
npx orm-preflight --changed-since origin/main
origin/main とのマージベースを比較し、未コミットファイルと未追跡ファイルも含めます。変更されたマイグレーションのいずれかが作成するテーブルは、それらすべてのマイグレーションに対して新規として扱われます。origin/main にすでに存在するマイグレーションの編集は、no-edit-applied-migration によって報告されます。GitHub Actions では、マージベースを利用できるように fetch-depth: 0 を指定してチェックアウトしてください。
継続的インテグレーション
orm-preflight はデータベースもシークレットも必要としないため、フォークからのプルリクエストでも安全に実行できます。
GitHub Action
検出結果は、プルリクエストの該当行に注釈として表示されます。
name: Migrations
on: pull_request
permissions:
contents: read
jobs:
orm-preflight:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # for changed-since
persist-credentials: false
- uses: sikandar100/orm-preflight@v1
with:
changed-since: origin/${{ github.base_ref }}
使用するバージョンは次のとおりです。
@v1はすべての 1.x リリースに追従するため、変更を加えずに修正を取得できます。- 固定する必要がある場合は、
@v1.0.0またはコミット SHA を指定すると、そのバージョンに固定されます。
このアクションはタグに対応するバージョンの orm-preflight を npm でインストールして実行するため、GitHub ホストランナーではほかに何も必要ありません。セルフホストランナーでは、事前に Node.js 20 以降をセットアップしてください。
| 入力 | 意味 |
|---|---|
changed-since | この git ref とのマージベース以降に追加または変更されたマイグレーションだけをチェックします。 |
files | チェックするファイルまたは glob。スペース区切りです。デフォルトは設定ファイル、またはすべての migrations フォルダーです。 |
config | 設定ファイルのパス。 |
working-directory | リポジトリのルートからの相対パスで指定する、実行ディレクトリ。デフォルトは . です。 |
max-warnings | 警告がこの数を超えた場合に失敗します。 |
mysql | マイグレーションが MySQL を対象とする場合は true にして、MySQL パーサーをインストールします。 |
sarif | 検出結果も GitHub コードスキャンにアップロードする場合は true にします。以下を参照してください。 |
version | 実行する orm-preflight のバージョン。デフォルトはアクションのタグのバージョンです。 |
pull_request トリガーを使用してください。この用途では pull_request_target を絶対に使用しないでください。フォークからのプルリクエストに書き込み権限のあるトークンとシークレットを与えることになりますが、orm-preflight はどちらも必要としません。
GitHub では、各ステップで各レベルの注釈は最大 10 件まで表示されます。ログの最終行には、すべての検出結果が常に表示されます。
リポジトリのコードスキャンアラートにも検出結果を表示するには、sarif: true を設定し、security-events: write を付与します。GitHub はフォークからのプルリクエストにはこの権限を付与しないため、その場合、アクションはアップロードをスキップし、注釈は引き続き表示します。
permissions:
contents: read
security-events: write
その他の CI システム
CLI を実行します。エラーがある場合、終了コードは 1 です。
npx orm-preflight --changed-since origin/main
マージベースを取得できるだけの履歴をチェックアウトしてください(GitHub Actions では fetch-depth: 0)。
AI コーディングエージェントで使用する
AI コーディングエージェントはマイグレーションをすばやく作成できますが、危険なマイグレーションを作成することもあります。orm-preflight に接続すると、エージェントは作成した各マイグレーションをチェックし、検出した問題を修正してから、あなたが内容をレビューできます。
Claude Code プラグイン
このプラグインを使うと、多くの作業を自動化できます。Claude Code 内で一度インストールするだけです。
/plugin marketplace add sikandar100/orm-preflight
/plugin install orm-preflight@orm-preflight
次の3つの機能が追加されます。
- 自動チェック。 Claude がマイグレーションを作成または編集するたびに、orm-preflight がチェックし、その結果を Claude に直接返します。Claude はマイグレーションを修正するか、安全である理由を説明します。警告を自分で読む必要はありません。それ以外のファイルは即座にスキップされます。
- スキーマを安全に変更する方法を Claude に教えるスキル。たとえば、カラムを削除せずにその場で変更する方法を教えます。
- 以下で説明する MCP ツール。
プラグインは、リリース時に同梱された正確なバージョンの orm-preflight を、初回使用時に npm からダウンロードして実行します。プロジェクトの orm-preflight.config.json は引き続き適用されます。たとえば MySQL パーサーを使用するために、自動チェックでプロジェクトにインストールされている orm-preflight を実行するには、/config でプラグイン設定の Use the project's own orm-preflight をオンにします。
MCP を使って任意のエージェントで利用する
orm-preflight mcp は orm-preflight を MCP サーバーとして実行します。MCP はエージェントに新しいツールを提供する標準的な方法です。一度追加するだけです。
プラグインを使わずに Claude Code で設定する場合:
claude mcp add orm-preflight -- npx -y orm-preflight mcp
Cursor、VS Code、Codex、Gemini CLI などのほかのエージェントでは、このコマンドを実行するサーバーを MCP 設定に追加します。各アプリにはそれぞれ設定ファイルがありますが、コマンドは常に同じです。
npx -y orm-preflight mcp
各エージェントの具体的な設定方法と、AGENTS.md 用の指示スニペットは、AI エージェントでの使用をご覧ください。
エージェントは次の3つのツールを利用できます。
| ツール | エージェントが得られる情報 |
|---|---|
check_migrations | 一部のファイル、プロジェクト全体、または origin/main などの git ref 以降に変更されたマイグレーションの検出結果。各検出結果には、何が起きるか、なぜ問題なのか、安全な実施方法が含まれます。 |
explain_rule | ルールのドキュメント全文。 |
list_rules | カテゴリとデフォルトの重要度を含む、すべてのルール。 |
知っておくと便利なこと:
- ツールはファイルを読み取るだけです。マイグレーションを実行したり、データベースに接続したりすることはありません。また、MCP 経由では
--executeを使用できません。 - サーバーは、起動したディレクトリのプロジェクトをチェックします。別の場所で起動したエージェントは
projectDirを渡すことができます。 mcpの後に指定したフラグはデフォルト値になります。たとえばnpx -y orm-preflight mcp --dialect mysqlです。MySQL の場合は、プロジェクトにorm-preflightとnode-sql-parserをインストールし、パーサーが見つかるように-yを付けずにnpx orm-preflight mcpを使用してください。- サーバーは、事前に確認せず抑制コメントを追加しないようエージェントに指示します。
- エージェントから、ツールの使用許可を一度求められることがあります。
検出結果の抑制
検出結果が想定どおりの場合は、その理由をステートメントの上のコメントに記載します。
// preflight safety-assured no-drop-column -- bio removed from the entity in 2.3, deployed everywhere
await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "bio"`)
抑制には理由が必須です。これにより、抑制の監査証跡が作成されます。ファイル全体を対象にする場合は、/* preflight safety-assured-file <rule> -- <reason> */ をファイル内の任意の場所に記述します。理由がない抑制や未知のルールを指定した抑制は、それ自体がエラーになります。
仕組み
orm-preflight は各マイグレーションファイルを Babel で解析し、queryRunner.query() に渡される SQL 文字列と、addColumn() や createIndex() などのビルダー呼び出しを読み取ります。また、同じファイル内で値が分かる場合は、SQL 内の ${...} も展開します。たとえば、定数、固定引数で呼び出されるローカル関数、既知の配列に対する .join() が対象です。既知の配列を対象とするループも、項目ごとに一度ずつ読み取ります。SQL は PostgreSQL パーサー(libpg-query)または MySQL パーサーで解析し、その結果にルールを適用します。
マイグレーションをインポートしたり実行したりすることはなく、データベースにも接続せず、TypeORM も読み込みません。実行時に構築される SQL など、読み取れないものは黙ってスキップされず、unanalyzable-statement として報告されます。
--execute を使ったマイグレーションの実行
データベースから読み取った名前や、別ファイルからインポートしたヘルパーなど、実行時にならないと分からない値から SQL を構築するマイグレーションがあります。静的解析ではその SQL を読み取れません。--execute を使うと可能になります。
npx orm-preflight --execute
各マイグレーションファイルを読み込み、TypeORM のクエリランナーの代役を使って up() を実行します。この代役は、データベースに送信する代わりにすべてのステートメントを記録します。そのため、次のようになります。
- データベースは不要で、データベースにアクセスすることもありません。
typeormのインポートには簡易的な代役が使われ、実際の TypeORM が読み込まれることはありません。up()がgetTable()などでデータベースを読み取る場合、空の結果が返されます。そのため、実際のデータベースでは異なるステートメントになる可能性があると orm-preflight が報告します。up()が失敗した場合、または 10 秒を超えて実行された場合は報告され、リンティングは続行されます。
--execute はコードを実行します。 信頼できるコードにのみ使用してください。
pull_request_targetトリガーが設定されたフォークからのプルリクエストでは、シークレットが渡されるため、絶対に使用しないでください。--allow-untrusted-executeを追加しない限り、orm-preflight は実行を拒否します。- GitHub Action は
--executeを使用しません。フォークに対しても静的解析を行い、安全性を保ちます。
クリーンな実行が意味すること
クリーンな実行とは、文書化された危険性が見つからなかったことを意味します。マイグレーションの安全性を保証するものではありません。orm-preflight はテーブルの規模やトラフィックを把握できないため、既存のテーブルはすべて大規模で、頻繁に利用されているものと仮定します。
制限事項:
- TypeORM のみが対象です。コアは ORM に依存しないため、他の ORM 用のアダプターも開発できます。
- PostgreSQL と MySQL に対応しています。MySQL では、データ損失、デプロイの安全性、正確性に関するルールが適用されます。MySQL のロック解析(
ALGORITHM=INSTANT、INPLACE、COPY)は 1.0 以降に予定されています。MySQL を使うにはnpm install --save-dev node-sql-parserが必要です。 - 解析対象は
up()のみです。down()は空であることのみ確認します(require-down)。 - 実行時に構築される SQL は、
--executeを使用しない限り、解析されずに報告されます。
プログラムからの使用
import { formatJson, lint } from 'orm-preflight'
const result = await lint({ cwd: process.cwd(), patterns: ['src/migrations/*.ts'] })
process.stdout.write(formatJson(result))
if (result.summary.errors > 0) process.exitCode = 1
貢献
CONTRIBUTING.md をご覧ください。セキュリティ上の問題を報告する場合は、SECURITY.md をご覧ください。
プライバシー
orm-preflight は何も収集せず、何も送信しません。テレメトリ、分析、アカウントはありません。お使いのマシンまたは CI ランナー上で実行され、データベースに接続することはありません。詳細はプライバシーポリシーをご覧ください。
謝辞
orm-preflight は、Rails 向けの strong_migrations と PostgreSQL 向けの squawk に着想を得ています。
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。