PR

「AIにファイルを壊されたくない」個人開発者へ。Gitと実行権限で作るローカル環境の防御策

AI・自動化・開発
この記事の要約(TL;DR):
  • 課題の核心: AIエージェントにコード修正や自動化スクリプトの実行を任せる際、「指示していないファイルまで勝手に書き換えられる」「APIキーをコード内に平文で直書きされる」という事故リスクが開発者の精神を削っています。
  • 現場の処方箋: プロンプトでの「壊さないで」「秘密鍵を書かないで」というお願いを卒業し、「Git pre-commitフックによるフェイルクローズ型の検査」「指示と権限の多層分離」「部分置換による編集」「安全な確認・復元フロー」という4つの防壁と、最後の「人間の承認ゲート」を組み合わせます。
  • 手に入る価値: 万が一AIが誤った修正や鍵の平文出力を試みても、Gitと環境の仕組みが段階的にブレーキをかけてくれるため、過度な緊張感を抱えずに安心してAIエージェントと高速並走できるようになります。

はじめに:AIのコーディング速度に、人間の心臓が追いつかない瞬間

最近、Claude CodeやAntigravityなどの自律型コーディングエージェントをローカル環境で動かす開発者が一気に増えました。

ターミナルから自然言語で指示を投げるだけで、関連ファイルを探索し、依存関係を読み解き、数十行のコードを一瞬で書き換えてテストまで走らせてくれる。その圧倒的な生産性は、一度体験すると二度と以前のコーディングスタイルには戻れないほどの魅力があります。

しかし同時に、キーボードから手を離した瞬間、胸の奥に冷たい汗が流れるような感覚を覚えたことはないでしょうか。

「いまAIが書き換えたファイルの中に、他の機能で使っている大切な関数が含まれていないか?」
「手っ取り早く動かそうとして、APIキーやトークンをコードの中に直接ベタ書きしていないか?」
「そのままうっかりGitHubにプッシュしてしまったら、取り返しのつかない大事故になるのでは……」

これは決して取り越し苦労ではありません。AIエージェントは非常に優秀ですが、同時に「目的を最速で達成するためなら、既存のコードを豪快に削ったり、一時しのぎで秘密鍵を直書きしてしまう」というリスクを常に孕んでいます。

言葉(プロンプト)でどれほど「既存コードを壊さないで」「APIキーは直書きしないで」と懇願しても、コンテキストが長くなったり複雑なリファクタリングをこなす中で、指示がすり抜けてしまう可能性はゼロにはできません。

必要なのは、精神論やお願いのプロンプトではありません。
「もしAIが失敗しても、Gitとツールの仕組みが段階的に被害を食い止めてくれる防御策」を整えることです。

私自身が個人開発の現場で運用している、ローカル環境とGitを守るための実践的な多層防御設計をお話しします。


1. AIエージェントが現場で引き起こす「3大事故パターン」

対策を打つ前に、まずローカル開発環境でAIエージェントが引き起こしやすい代表的な事故を整理しておきます。

事故パターン 起きやすいシチュエーション 潜んでいる実際のリスク
① 巻き込み削除・過剰上書き 一部の関数だけ修正を頼んだのに、ファイル全体を再生成して他の重要なロジックを吹き飛ばす 動いていた機能がサイレントに破壊され、後から原因究明に何時間も溶かす
② APIキーのハードコード(平文露出) 外部API連携の動作テストを急ぐあまり、コード内に生トークンを直書きして動かしてしまう そのままGitコミット・GitHub公開され、ボットに検知されて高額請求や不正利用を招く
③ 前提確認なしのフライング実行 変更提案のレビューを待たずに、勝手にマイグレーションや外部送信スクリプトを走らせる データベースの既存レコードが上書きされたり、未完成のデータが本番APIへ飛ぶ

これらの問題に共通しているのは、「AIエージェントの自律性が高すぎるあまり、安全確認の手順を飛び越えてしまう可能性がある」という点です。

これを防ぐためには、「AIに気をつけてもらう」のではなく、「ルールから外れた操作は、システムの仕組みによって段階的に検知・抑止する」というアプローチへ切り替える必要があります。


2. 第1の防壁:Git pre-commitによる「シークレット混入のフェイルクローズ遮断」

最も致命的な事故である「APIキーやパスワードのコミット」のリスクを最小化するために、現場で絶対に欠かせないのが Gitの pre-commit フックと Gitleaks の連携 です。

AIエージェントに作業を任せていると、どれほど気をつけていても、デバッグ用のコードや設定ファイルに生のAPIキーが紛れ込むリスクを完全に排除することは困難です。

そこで、「git commit コマンドが実行された瞬間、ステージングされた変更差分の中に秘密情報パターンが含まれていないかを自動スキャンし、検知されたらコミットを中止する」というフックを仕掛けておきます。

pre-commit フックスクリプト(Gitleaks 8.30.1 / macOS で動作確認)

まず前提として、ローカルPCにGitleaksがインストールされている必要があります(Macの場合はHomebrewで導入できます)。

# Gitleaksのインストール(Mac / Homebrew環境)
brew install gitleaks

準備ができたら、プロジェクトの .git/hooks/pre-commit に以下の検査スクリプトを配置し、実行権限(chmod +x .git/hooks/pre-commit)を付与します。

#!/bin/sh
# ==============================================================================
# 036 Factory Git Pre-Commit Security Hook (Gitleaks 自動防壁)
# コミット前にAPIキーやシークレットの混入を検査し、検知したらコミットを中止する
# ==============================================================================

# 【フェイルクローズ設計】Gitleaksが見つからない場合は、検査できないのでコミットを中止
if ! command -v gitleaks >/dev/null 2>&1; then
    echo ""
    echo "🚨 ==================================================================="
    echo "🚨 【セキュリティエラー】Gitleaks がインストールされていません!"
    echo "🚨 秘密情報検査を実行できないため、コミットを安全停止しました。"
    echo "🚨 brew install gitleaks で導入してから再度コミットしてください。"
    echo "🚨 ==================================================================="
    echo ""
    exit 1
fi

# Gitleaks 8.30.1 で動作確認したコマンド
# (古いバージョンでは gitleaks protect --staged を使う。手元の版は gitleaks git --help で確認)
# ステージング済みの変更に秘密鍵・APIキーが含まれていないかをスキャン
gitleaks git --pre-commit --staged --verbose --redact
EXIT_CODE=$?

if [ $EXIT_CODE -ne 0 ]; then
    echo ""
    echo "🚨 ==================================================================="
    echo "🚨 【セキュリティ停止】Gitleaksの検査が失敗したか、機密情報が検出されました。"
    echo "🚨 詳細を確認し、安全が確認できるまでこのコミットを中止します。"
    echo "🚨 コード内に直書きされた鍵がないか確認し、必要に応じて .env へ退避してください。"
    echo "🚨 ==================================================================="
    echo ""
    exit 1
fi

exit 0

ここでの設計ポイント:フェイルクローズ(安全停止)

以前の単純なスクリプトでは if command -v gitleaks で囲うだけで、もしGitleaksが未導入だったりPATHが通っていない環境では、検査がスキップされてコミットが素通り(exit 0)してしまう穴がありました。

本スクリプトでは、「検査ツールが正常に動かない場合は、安全側に倒してコミット自体を停止する(exit 1)」というフェイルクローズ設計を採用しています。また、終了コードが0以外の原因をシークレット検出だけに断定せず、「検査自体の失敗(異常終了)」も含めて安全にブロックするメッセージ設計としています。

[!CAUTION]

【pre-commitフックの限界を正しく理解する】

Gitleaksは既知のトークン形式や正規表現パターンに基づいて検知するツールであり、あらゆる独自シークレットを100%完璧に網羅する魔法ではありません。また、フックが作動するのは「コミット時」であるため、コミット前のローカルファイルへの平文書き込みや、Gitを経由しない外部通信を直接遮断するものではありません。

ローカルフックだけに過信せず、利用条件を満たす場合はGitHub Secret Scanningを有効化し、CIでも秘密情報の検査を実施するなど、複数の防御を組み合わせてください。各検査には検出できない形式や設定上の限界があるため、単一の仕組みですべてを防げるとは考えないことが重要です。

動作確認の結果と、テスト時の落とし穴

私の環境(Gitleaks 8.30.1 / macOS)で、テスト専用のリポジトリを作って次の4パターンを確認しました。テストに使用した文字列は、除外語に該当しない十分なエントロピー(ランダム性)を持たせた実在しないダミー値です。

確認したケース テストに用いたダミー文字列形式 検証結果
既存コミットありのリポジトリ ghp_ + ランダム英数字36桁(GitHub PAT形式) 検知され、コミットは中止
初回コミット(HEADなし状態) ghp_ + ランダム英数字36桁(GitHub PAT形式) 検知され、コミットは中止
Issue #2281 で報告されたケースの追試 SECRET_KEY_BASE: + 64バイトの16進数文字列 手元の環境では検知され、コミットは中止
Gitleaksが未インストールの状態 (PATHからgitleaksを除外して実行) エラーを表示し、安全停止(exit 1)

[!WARNING]

【テスト時の注意点とGitleaksの限界】

1. 除外設定(Allowlist)によるすり抜けに注意: AWS公式ドキュメント等のサンプルキー(AKIA で始まり EXAMPLE で終わる文字列)や、過去に報告された特定の固定ダミー文字列は、Gitleaksの標準ルールで既知の安全なテスト用として除外(Allowlist)されているためコミットが素通りします。テスト時は十分な長さのランダムな英数字を用いてください。

2. Issue #2281等の報告と検証の前提: Gitleaks公式リポジトリでは、gitleaks git --pre-commit --staged が特定のステージ済み汎用シークレットを検出できなかったという報告(Issue #2281)が未解決状態で残っています。手元のmacOS環境での追試では SECRET_KEY_BASE 形式のダミー値も正常に遮断されましたが、OSやGitの環境差、設定ファイルの違いによって挙動が異なる可能性は否定できません。「手元テストの成功=あらゆるシークレットの完全遮断」とは過信せず、複数レイヤーでの多重防御を維持してください。


3. 第2の防壁:作業ディレクトリの隔離と「指示・権限の多層分離」

AIエージェントにプロジェクトルート全体の自由な編集を許可していると、思わぬ設定ファイルや過去の完成資産まで書き換えられるリスクがあります。

ここで重要なのは、「プロンプト上の指示」と「実際のOS・ツールレベルの権限」を明確に区別して多層的に防御することです。

現場で実践している多層分離モデル

防御レイヤー 具体的な対策内容 強制力・役割
① 指示書によるルール策定(論理制約) AGENTS.md 等で作業机(scratch/)と不可侵領域(.env や個人ノート)を明記する エージェントの行動指針となるが、これ単体では物理的アクセス制限にはならない
② ツール仕様による制限(機能制約) エージェントに渡すファイル操作ツールの書き込み対象パスを検証・限定する 指定外ディレクトリへの書き込みAPI呼び出しをツール側でエラーとして弾く
③ OS・環境レベルの保護(物理制約) 機密ファイル(.env)のパーミッション設定(chmod 600)、またはサンドボックス実行環境の分離 他ユーザーからの不正参照を防ぐ。ただし同一OSユーザーで動くAIには無効なため、後述の注意が必要

[!WARNING]

【注意:chmod 600 だけでは同一ユーザーで動くAIエージェントを防げない】

chmod 600 .env は「ファイルの所有者のみに読み書きを許可する」設定です。そのため、AIエージェントが自分と同じOSユーザー権限で動いている場合(一般的なターミナル起動時など)、エージェント自身も所有者とみなされるため、読み取りや書き換えをOSレベルで止めることはできません。

AIエージェントから .env などの神聖領域を物理的に不可侵にするには、「エージェント専用の別OSユーザーを作成して実行する」「Docker等のコンテナや隔離サンドボックス内で動かす」といった実行プロセスの分離が本質的に不可欠です。


4. 第3の防壁:ファイル全体置換の抑制と「ピンポイント差分置換」

多くのAIエージェントが既存コードを壊す最大の原因は、「ファイル全体を一括で書き直そうとすること」にあります。

300行あるスクリプトのうち、たった5行の修正を依頼しただけなのに、AIが300行丸ごと出力し直した結果、中盤にあった重要な例外処理やコメントが綺麗さっぱり消え去っていた……という経験はないでしょうか。

このリスクを減らすため、エージェントへの指示やツールの設定では、次の考え方を基本にしています(ツール名は製品によって異なりますが、多くのエージェントに「ファイル全体を書き出す操作」と「一部だけを置き換える操作」の2種類があります)。

編集手法 動作の仕組み 安全性評価
× ファイル全体の書き出し(上書き) 既存の中身を完全に消去し、新しいテキストで丸ごと置き換える 🚨 危険度高。未指定のロジックやコメントが消失する主因。新規ファイル作成時以外は避ける。
◯ 一致した箇所だけの部分置換 置き換えたい元の文字列を指定し、そこだけをピンポイントで差し替える ✅ リスク低減。既存コードとの完全一致が確認できない場合はエラーとなり、巻き込み破壊を防ぐ。

※ただし、部分置換であっても「書き換えたロジックそのものがバグを含んでいるリスク」までは防げません。編集方法の絞り込みはあくまで「意図しないコードの消失」を防ぐための第一歩であり、コード自体の正しさは次の検証ステップで担保します。


5. 第4の防壁:Git本来の回復力と「安全な確認・復元手順」

どれほど慎重に部分置換を行っても、AIが修正したロジックが動かなかったり、思わぬバグを生む可能性は残ります。
しかし、恐れる必要はありません。なぜなら、私たちは Gitの管理下で作業しているから です。

ただし、ここで1点非常に危険な落とし穴があります。
世間の解説でよく見かける git restore . ですが、「何が変更されたかを見ずにいきなり実行する」のは極めて危険です。

git restore . は作業ツリーの未ステージ変更をすべて破棄するため、「自分が手作業で直していた大切なコード」まで巻き込んで永久に失われる恐れがあります。

現場で実践している安全な確認・復元フロー

AIがコードを変更した後は、やみくもに git restore . を打つのではなく、必ず以下の状況に応じた手順を踏みます。

# 【手順1:変更内容を正確に把握する】
git status
git diff              # ワーキングツリー(未ステージ)の差分を確認
git diff --cached     # ステージング済み(git add 済み)の差分を確認

# 【パターンA:特定の問題ファイルだけを元に戻したい場合】
git restore path/to/broken_file.py
# ※すでに git add されている場合はステージと作業ツリー両方を戻す
git restore --source=HEAD --staged --worktree path/to/broken_file.py

# 【パターンB:現在のAIの試行錯誤を「消さずに一旦脇に置いて」作業をやり直したい場合】
# ※全破棄するのではなく、安全に退避(スタッシュ)してクリーンな状態に戻す
git stash -u -m "AI試行コードの一時退避"
# (後から見返したいときは git stash pop または git stash list で確認可能)
# ※注意:-u は未追跡ファイルを退避しますが、.gitignore等で無視されているファイルまでは退避しません。環境変数や外部ファイルは別途保全してください。

「やみくもな全破棄」ではなく、まず差分を目視し、必要な変更を守りつつ対象ファイルだけをピンポイントで戻す。あるいは git stash で退避しておく。この手順さえ頭に入っていれば、AIの大規模なコード提案にも心拍数を乱されずに立ち向かえます。


6. 最後の砦:人間の承認ゲート(二層防御)

自動化を進めていると、「すべてをボタンひとつ、あるいは完全自律で終わらせたい」という誘惑に駆られます。
しかし、個人開発において最もコスパの高い安全装置は、「最後の一歩(コミット・プッシュ・本番送信)だけは人間が目視で確認してボタンを押す」という承認ゲートを残しておくことです。

  • AIの役割: 面倒な下調べ、テストコードの作成、差分の作成、セキュリティ検査までを高速に下準備する。
  • 人間の役割: 提示された git diff を冷徹に眺め、「意図しない変更がないか」「余計なファイルが含まれていないか」を確認して承認(Approve)を出す。

[!TIP]

【補足:承認ゲートの実効性を保つルール】

「人間が目視確認する」というルールを掲げていても、AIエージェントに git commit や git push を含む任意のシェルコマンド実行権限を無制限に与えていると、エージェントが人間の承認を待たずに自律的にプッシュまで完了してしまうリスクがあります。

承認ゲートを真に機能させるためには、「コミットやプッシュを伴うコマンドはAIに直接打たせず、必ず人間がターミナルで手動実行する」か、ツールの許可リスト(Allowlist)でGit送信系コマンドを明示的にブロックしておく運用が不可欠です。

アクセルを思い切り踏み込めるのは、確実に効く強力なブレーキが足元にあるからです。


まとめ:仕組みでリスクを抑え込み、軽やかにコードを書く

AIエージェントを使った開発は、これまでのプログラミングの常識を心地よく塗り替えてくれます。
しかし、そのスピードを真に享受するためには、不安をプロンプトのお願いで紛らわすのではなく、システムとして飼いならす知恵が必要です。

  • Git pre-commit(Gitleaks)で、フェイルクローズなコミット遮断を仕掛ける
  • 指示書のルールだけでなく、ツールやOSレベルの権限分離を意識する
  • 丸ごと上書きを避け、ピンポイントの差分置換でコード消失を防ぐ
  • やみくもな一括破棄を避け、差分確認と個別ファイル復元を徹底する
  • コミットや本番送信の手前に、人間の承認ゲートを必ず残す

「AIを信用しない」のではなく、「AIが失敗しても誰も傷つかない環境を作る」。
この足場さえ固まれば、AIエージェントはあなたの開発を何倍にも加速させる、最高に頼もしい相棒になってくれます。

まずはご自身のGitリポジトリに、小さな pre-commit フックを1本仕掛けるところから、安心な自動化の一歩を踏み出してみてください。


☕ 思考を巡らせた頭を、一杯の珈琲で整える

036 Factoryの本業は、ご注文をいただいてから生豆を一粒ずつ手作業で選別(ハンドピック)して焙煎する、小さな自家焙煎珈琲工房です。

AIやツールの設計で少し疲れた頭をふっとリセットする、雑味のない「毎日飲める普通のコーヒー」を静かに焼いています。日々の作業のお供や息抜きに、ぜひ工房の豆を覗いてみてください。


タイトルとURLをコピーしました