bouncer-gates について
bouncer-gatesは、チームやコーディングエージェント向けに、マージ前に5種類の重大な問題を検出するリポジトリチェッカーです。CLI、エディターフック、CI、MCPサーバーとして実行できます。
主な機能
- 01シークレットと危険なコマンドパターンの検出
- 02テナント条件のないクエリの指摘
- 03浮動小数点による通貨処理の確認
- 04危険なSQLマイグレーションの検出
- 05Markdownのファイルリンク検証
- 06ベースラインと理由付き例外の対応
活用シーン
- 01マージ前のローカル変更スキャン
- 02編集後のClaude CodeやCursorへの指摘提示
- 03GitHub Actionsでの新規問題のブロック
- 04既存問題を許容しつつ新規問題を追跡
MCP 対応
MCPサーバー経由でチェック機能を提供し、エージェントや他のMCPクライアントから呼び出せます。編集後フックでエージェントが書いたファイルをスキャンすることもできます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
bouncer-gates
人が書いたコードでもエージェントが書いたコードでも、マージ前に高くつくミスを防ぐ5つのチェックです。
ハードコードされたシークレット。ある顧客のデータが別の顧客に漏れるデータベースクエリ。金額の浮動小数点演算。実行中のアプリを壊すマイグレーション。存在しなくなったファイルへのリンクを含むドキュメント。
今では新しいコードのほとんどをエージェントが書いており、まさにこうしたミスをします。テストを通すために貼り付けたキーや、プロンプトにテナントのことが書かれていなかったためにテナントフィルターがないクエリなどです。bouncer-gates は Claude Code と Cursor の内部で動作するため、エージェントはコードを書いた同じターン内に指摘を受け取ります。さらに CI でも実行されるので、問題を見逃しません。
10秒で、どのリポジトリでも試せます。
npx bouncer-gates
または、プレイグラウンドにコードを貼り付けて、同じチェックが実行される様子をご覧ください。
クイックスタート
npx bouncer-gates --init # writes bouncer-gates.config.json, reads your Prisma schema if you have one
npx bouncer-gates --init-agents # wires the same checks into Claude Code and Cursor for this repo
npx bouncer-gates # runs every check and prints what it found
GitHub Actions に追加します。
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed so the migration check can see what is new
- uses: ajeermahmood/bouncer-gates@v0
with:
version: "0.5.0"
セットアップはこれだけです。以下はすべて詳細です。
エディター内でエージェントと使う
--init-agents を実行すると、エージェントが呼び出せる MCP サーバーと、エージェントが書き込むすべてのファイルをスキャンするフックの2つがリポジトリにコミットされます。ファイルにブロッキング対象の検出結果があると、エージェントは同じターン内に、ファイル名、行番号、問題の内容、代わりにすべきことを確認できます。
x src/orders.ts:12 scope/unscoped-query
"order" is tenant-owned, but nothing in this query mentions "tenantId", so it returns rows from every tenant.
fix: Add tenantId to the where clause, or go through a tenant-scoped client.
ほかの MCP クライアントでも npx -y bouncer-gates --mcp を実行できます。また、編集後のフックからイベントを npx -y bouncer-gates --hook にパイプで渡すこともできます。
仕組みと、実行しないこと。
チェック項目
| チェック | 検出するもの | 防止できる例 |
|---|---|---|
| secrets | リポジトリにコミットされたパスワード、API キー、秘密鍵、および curl ... | sh のようなリスクのある形式 | const apiKey = "sk_live_..."、実際のパスワードが入った .env のコミット |
| scope | テナントごとに分離されたテーブルに対する、1つのテナントに限定されていないクエリ | tenantId がない prisma.order.findMany({ where: { status: "paid" } }) |
| money | 浮動小数点数での通貨処理、またはすべての通貨が小数点以下2桁だと仮定した * 100 | Math.round(parseFloat(price) * 100) |
| migration-safety | デプロイ中にまだ実行されているバージョンのアプリを壊す SQL マイグレーション | 古いコードがまだ読み込んでいる最中に実行する ALTER TABLE orders DROP COLUMN total |
| doc-links | 存在しないファイルへの Markdown リンク | ファイルの移動後に残った [setup](docs/setup.md) |
どのチェックも、実際に発生した高くつくバグをもとに作られています。スタイル上の好みを押し付けるものはありません。 ゲートのリファレンスでは、すべてのルールについて、問題のある例と修正例を説明しています。
検出されたとき
すべての検出結果に、ファイル名、行番号、問題の内容、代わりにすべきことが示されます。
FAIL scope
x src/orders.ts:2 scope/unscoped-query
"order" is tenant-owned, but nothing in this query mentions "tenantId", so it returns rows from every tenant.
fix: Add tenantId to the where clause, or go through a tenant-scoped client.
次の3つの方法があります。以下の順で検討してください。
- 修正する。 たいていの場合、これが正解です。
- 問題ない理由を説明する。 該当行またはその1行上に理由をコメントとして記述します。理由は必須です。印だけでは何も起きません。
// bouncer-gates-ok(scope): nightly revenue report spans every tenant by design const all = await prisma.order.findMany(); - 既存の問題を記録して、新しい問題だけをブロッキング対象にする。 すでに検出結果があるコードベースでは、これを一度実行し、生成されたファイルをコミットします。
古い検出結果はブロッキング対象ではなくなります。新しい問題は引き続きブロッキング対象です。このファイルは読みやすく、記録される件数は減る一方であるべきです。npx bouncer-gates --baseline-write
設定
bouncer-gates --init を実行すると、この設定が自動で作成されます。いつでも手動で編集できます。
{
"exclude": ["fixtures/**"],
"scope": {
"models": ["order", "customer"],
"tables": ["orders", "customers"],
"column": "tenantId",
"clients": ["prisma"],
"rawAccessor": "raw"
},
"doc-links": { "repoUrl": "https://github.com/you/your-repo" }
}
- exclude:スキャン対象から完全に除外するファイルです。実行のたびに各パターンで除外されたファイル数が表示されるため、リストが知らないうちに増えることはありません。
- scope.models / tables:テナントに属するモデルとテーブルです。
--initは、Prisma スキーマ内でtenantIdフィールドを持つモデルをすべて設定します。 - scope.clients:
prismaのような通常のクライアント名です。そのクエリでテナント列がチェックされます。スコープ付きラッパーがない場合に使用します。 - scope.rawAccessor:スコープ付きラッパーがある場合、ラッパーの内部で使用される未加工のクライアント名です。たとえば
db.rawのような名前を設定します。これにアクセスすると警告されます。 - doc-links.repoUrl:自分のリポジトリへの絶対リンクもファイルパスとしてチェックできるようにします。
スコープのセクションがない場合、スコープチェックは合格ではなくスキップと報告されます。
すべてのコマンド
npx bouncer-gates # every check, whole repository
npx bouncer-gates --init # write a starter config
npx bouncer-gates --init-agents # wire the gates into Claude Code and Cursor
npx bouncer-gates --mcp # serve the gates over MCP, for any agentic editor
npx bouncer-gates --hook # scan the file named by a hook event on stdin
npx bouncer-gates --changed # only files this branch touched
npx bouncer-gates --only scope,money # just some checks
npx bouncer-gates --explain scope # what a check does and how to excuse a case
npx bouncer-gates --baseline-write # record existing findings
npx bouncer-gates --json # machine-readable output
npx bouncer-gates --sarif # for the GitHub Security tab
終了コード 0 は問題なし、1 はブロック対象あり、2 はツール自体を実行できなかったこと(不正なフラグ、壊れた設定、Git リポジトリではない場合)を意味します。CI では意図的に 1 と 2 を区別します。ツールの不具合が、コードベースに問題が山積みであるかのように見えてはいけません。
このツールが行わないこと
過度に信頼されないよう、制限事項を正直に説明します。
- テキスト内のパターンを照合します。コードの意味を理解するわけではありません。チェックで確認できないヘルパー関数内にテナントフィルターが組み立てられている場合も報告されます。その場合は上のコメントで対処してください。
- 金額チェックとスコープチェックが読み取るのは JavaScript と TypeScript のみです。
- マイグレーションチェックが読み取るのは
.sqlファイルのみです。JavaScript または TypeScript で記述されたマイグレーションはチェックされません。 - 複数行に分割されたシークレットや、識別可能なプレフィックスを持たないシークレットは検出されません。履歴をさかのぼって詳しくスキャンするには gitleaks または trufflehog を使用してください。これは監査ではなく、ドアに設置する簡易的な防御策です。
prisma.$transaction(async (tx) => ...)内のクエリでは、チェックが追跡できないクライアントが使われます。
各ルールの検出できないケースは、ゲートのリファレンスに記載されています。
ここで使う用語
- ゲートまたはチェック:検査対象となる 5 つの項目のいずれかです。
- 検出事項:報告される問題 1 件のことで、ファイルと行番号が示されます。
- ブロック対象:実行を
1で終了させる検出事項です。警告では終了しません。 - ベースライン:当面許容すると決めた検出事項を記録するファイルです。これにより、新しい検出事項だけがブロック対象になります。
- 承認または免除:特定の行に問題がない理由を示す
bouncer-gates-okコメントです。
テレメトリー
匿名の ping を 1 日に 1 回送信します。送信内容はランダム ID、バージョン、ランタイム、OS、Node のメジャーバージョンです。コードに関する情報は一切送信しません。BOUNCER_TELEMETRY=0 を設定すると無効になります。
送信される情報のすべて。
詳細
- エディター内での動作:MCP サーバーとフック、エージェントに表示される内容、その他のエディター
- ゲートのリファレンス:すべてのルール、悪い例と良い例、検出できないケース
- 既存のコードベースへの導入
- 設計メモ:フェイルオープンしない理由、検出事項にシークレットを引用しない理由、誤検知への対応、速度改善の取り組み
- アーキテクチャ:ゲートは純粋関数であるため、CLI、Cloudflare Worker、ブラウザーで同じコードを実行できます
- デプロイ:プレイグラウンド、API、npm
- コントリビューション:ゲートの追加方法と、ある項目をゲートにすべきかどうかの判断方法
開発
npm install
npm test # unit tests
npm run check # bouncer-gates on itself
npm run bench -- ../some-repo # measure against a real codebase
npm run dev # the playground site
ライセンス
MITです。ご自由にお使いください。
Ajeer Mohammedが作成しました。このルールは、コードの大半をコーディングエージェントが書くマルチテナントプラットフォームの、処理をブロックするチェックに基づいています。チェックを一つでも漏らすと、ある加盟店が別の加盟店の注文を見てしまう可能性がありました。このワークフローの仕組み。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。