0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pre-commit シークレットスキャナ「KeyGate」を Claude Code プラグイン化して公開しました

0
Last updated at Posted at 2026-04-28

はじめに

少し前に Qiita で紹介した、Git の pre-commit でシークレット混入を止める CLI ツール KeyGate を、Claude Code プラグイン として配布できるようにしました。

Claude Code の /plugin marketplace add から導入でき、Claude Code 上では Skill がコミット前の文脈で keygate を呼び出せます。Slash Command から明示的にスキャンや hook 導入を実行することもできます。

# Claude Code 内で
/plugin marketplace add kanekoyuichi/keygate
/plugin install keygate

これで、Claude Code から KeyGate を呼び出せるようになります。コミット前の文脈では Skill が使われ、明示的に確認したいときは /keygate:scan を実行できます。


なぜ Claude Code プラグイン化したのか

Claude Code を日常的に使っていると、以下のような流れが当たり前になります。

  1. Claude Code に「この機能を実装して」と頼む
  2. Claude Code が複数ファイルにまたがる差分を一気に作る
  3. レビューしながら受け入れる
  4. git commit -m "..." をユーザーまたは Claude Code 自身が実行

このとき問題になるのは、3 と 4 の間で人間がすべての差分を完璧に確認できるとは限らない ことです。.env を参考に生成されたコード、テストフィクスチャから引きずってきた値、コメントに残ったままの API キー候補 ── これらが混入しているのに気づかずコミットされる事故は、スピードが速いほど起きやすくなります

KeyGate 本体は CLI として既に解決していました。keygate activate で Git pre-commit hook を入れれば、機械的に止まります。

ただ Claude Code のワークフローでは、Claude Code がコミット直前の文脈で「ここはシークレット検査を挟むべきだ」と気づける ほうが自然です。これが Claude Code プラグイン化のモチベーションでした。


プラグインの中身

構成はシンプルで、以下の 3 つです。

Claude Code プラグインは、Claude Code に機能を追加するための小さなパッケージです。今回の KeyGate プラグインは、シークレット検知のロジックを Claude Code に持たせるものではありません。既存の KeyGate CLI を、Claude Code から呼びやすくするためのラッパーです。

1. Skill(自律発火)

keygate-secret-scan という Skill を 1 本定義しています。

Skill は、Claude Code に「こういう場面ではこの手順を使ってね」と教える Markdown ファイルです。プラグインとして入れると、呼び出し名にはプラグイン名の名前空間が付きます。この場合は /keygate:keygate-secret-scan として扱われます。

Skill の description に「コミット直前 / git add 直後 / API キー風の値が含まれるコード変更時に使う」と書いてあるので、Claude Code は会話や作業内容に応じてこの Skill を使えます。

中身は以下の処理だけです:

  1. keygate --version で CLI が入っているか確認(未インストールなら pipx install keygate 等を案内)
  2. keygate scan --profile agent を実行(JSON のみを stdout に返すモード)
  3. statuspass / warn / block のどれかで応答を出し分け
  4. block ならコミット停止 + 鍵ローテーションを強く推奨

Skill 自身が検知ロジックを持たない のがポイントです。判定はすべて CLI 側で完結し、Skill は単に CLI を呼んで JSON を解釈するだけ。これで「LLM が独自に判定する」ことによる検知のブレを排除しています。

2. Slash Commands(明示的に実行するコマンド)

Slash Command は、Claude Code の入力欄で / から始めて実行するコマンドです。自律的な Skill と違い、ユーザーが「今これを実行して」と明示できます。

Claude Code のチャットから呼べる 4 本のコマンドを用意しました。

/keygate:scan              # 任意のタイミングでスキャン
/keygate:install-hook      # Git pre-commit hook を入れる
/keygate:baseline-create   # 既存検知を baseline に登録
/keygate:baseline-update   # 新規検知を baseline に追加

Claude Code 側のタブ補完が効くので、「あのコマンドなんだっけ」となりにくいよう、baseline 系も 1 本にまとめずに分けました。

3. Marketplace カタログ

Claude Code のマーケットプレイスは、プラグインの一覧と取得元を書いたカタログです。

keygate では .claude-plugin/marketplace.json を同じリポジトリに同居させています。これにより kanekoyuichi/keygate だけでマーケットプレイスとプラグイン両方を兼ねる構造になり、配布チャネル用の別リポは作らずに済みました。


技術選択:なぜ Hook ではなく Skill + Slash Command か

Claude Code のプラグインには「Hook」という機能もあります。PreToolUse などのライフサイクルイベントに割り込んで処理を挟める仕組みです。

実は最初は「PreToolUsegit commit を検知して KeyGate を走らせる」という案も検討しました。が、すぐに却下しました。理由は次の通りです。

  • Git pre-commit hook と完全に役割が重複するkeygate activate を入れている人にとってはダブルで走るだけ。入れていない人だけ Hook で守るのは「2 種類の経路で同じ検知を維持する」ことになり、デバッグが難しくなる
  • Hook はユーザーから見えにくい。なぜコミットが止められたのかが伝わりづらく、UX として劣る
  • Skill は文脈に応じて使える ので、Claude Code の作業フローに乗せやすい

結果、

  • 機械的な強制力 → 既存の Git pre-commit hookkeygate activate
  • AI エージェントによる「気づき」と修正提案 → Skill
  • ユーザーの明示的な操作 → Slash Commands

という 3 層に分担させるのが一番きれいでした。


Skill の中身(抜粋)

SKILL.md の冒頭はこんな感じです。description を厚めに書くことで、Claude Code が「いつ使うべきか」を判断しやすくなります。

---
name: keygate-secret-scan
description: |
  Scan staged Git changes for leaked secrets (API keys, tokens, passwords)
  before commit. Use when the user is about to commit code, after staging
  changes, or when files contain values that look like API keys, tokens,
  or credentials.
---

# Keygate Secret Scan

## When to use
- The user is about to run `git commit`
- After `git add`
- When the recent diff contains values that look like API keys, JWTs,
  PEM blocks, OAuth tokens, or `.env` style assignments
- When the user explicitly asks to scan for secrets or run keygate

## Step 1. Verify the CLI
Run `keygate --version`. If it fails, ask the user to install it via:
- `pipx install keygate`
- `uv tool install keygate`
- `pip install --user keygate`
Then stop until the CLI is available.

## Step 2. Scan
Run `keygate scan --profile agent` and parse the resulting JSON.

## Step 3. Interpret
- `status: "pass"` → quietly confirm "no secrets detected"
- `status: "warn"` → summarize each finding with file:line, rule, snippet
- `status: "block"` → STRONGLY advise stopping the commit and rotating
  any exposed credential

The `snippet` field is already masked (first 4 chars + *** + last 2),
so it can be displayed as-is without leaking the value.

実装としてはこれだけです。Claude Code プラグイン側では、危険な値かどうかを独自に判定していません。CLI の結果を読み、ユーザーにわかりやすく伝える役割に絞っています。


AI エージェント向け JSON 出力との連携

keygate scan --profile agentstdout に JSON だけを返す モードで、Claude Code プラグイン化を見据えて先に作っておいたものです。

$ keygate scan --profile agent
{
  "schema_version": "1",
  "status": "block",
  "summary": { "findings": 1, "blocked": 1, "warned": 0, "scanned_lines": 12 },
  "findings": [
    {
      "rule_id": "aws-access-key",
      "policy": "must_block",
      "score": 100,
      "verdict": "block",
      "file": "config.py",
      "line": 12,
      "message": "AWS Access Key detected; sensitive context detected",
      "snippet": "AKIA***XY",
      "recommended_action": "move_to_secret_manager"
    }
  ]
}

ポイントは snippet が CLI 側で既にマスクされている こと。先頭 4 文字 + *** + 末尾 2 文字の形に CLI 側で揃えてから出力するので、Skill はこれをそのまま画面に出して問題ありません。

LLM 出力にトークン全文が露出する事故を、出力フォーマットの設計レイヤーで防いでいます。


リリース運用:GitHub Actions で PyPI へ自動公開

おまけ的な話ですが、CLI 本体の更新ごとにプラグインのバージョンも合わせる運用にしているので、リリースを完全自動化しました。

# .github/workflows/publish.yml の抜粋
on:
  release:
    types: [published]
jobs:
  publish:
    permissions:
      id-token: write   # OIDC trusted publishing
      contents: read
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: '3.11'
      - run: python -m pip install build
      - run: python -m build
      - uses: pypa/gh-action-pypi-publish@release/v1

PyPI 側の Trusted Publisher 設定で kanekoyuichi/keygate リポと publish.yml を紐付けておけば、GitHub Release を publish するだけで PyPI 公開されます。twine upload も API トークンも不要です。タグ push だけでは公開されず、必ず GitHub Release の作成が必要です。

これで Claude Code プラグイン側の version フィールド・CLI 側の --version の両方が同じ番号で揃い、「Claude Code が呼んでいる CLI」と「プラグインが告げているバージョン」がずれない状態を維持できます。

今回の 0.2.0 では、keygate activate / keygate deactivate コマンドを追加し、ユーザー向けの導線をシンプルにしました。プラグイン公開前には claude plugin validate . で validation を通しておくと安心です。


試してみる

CLI 本体をいずれかでインストールしてください(プラグインは PyPI の keygate パッケージを呼ぶので、本体が必要です)。

pipx install keygate
# または
uv tool install keygate
# または
pip install --user keygate

その上で Claude Code 内で:

/plugin marketplace add kanekoyuichi/keygate
/plugin install keygate

試しに .env ファイルに本物っぽい AWS access key を書いて git add した状態で、Claude Code に「コミットして」と頼んでみてください。文脈に応じて Skill が使われ、「シークレットが検知されたのでコミットを止めるべき」と提案してきます。

明示的に呼びたい場合は:

/keygate:scan
/keygate:install-hook
/keygate:baseline-create
/keygate:baseline-update

おわりに

Claude Code プラグインの仕組みは、よくある「LLM 拡張用フレームワーク」と比べて非常に薄いです。既存 CLI を --profile agent で JSON 化し、Skill から呼ぶだけで、AI エージェントから自然に使える機能が増やせる

なので、もし「うちの CLI ツールも Claude Code から呼べると嬉しいな」と思っているメンテナの方は、だいたい次の流れで始められます。

  1. JSON 出力モードを CLI に足す
  2. .claude-plugin/plugin.json を作り、必要なら skills / commands のパスを指定する
  3. skills/<name>/SKILL.mdcommands/*.md を用意する
  4. .claude-plugin/marketplace.json を同居させる
  5. claude plugin validate . で検証してから push する

今回の keygate はその実例として参考になれば幸いです。

フィードバック・Issue・PR 歓迎です:https://github.com/kanekoyuichi/keygate

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?