{"meta":{"title":"Copilot CLI でフックを使用して、ポリシーに準拠した予測可能な実行を行う","intro":"フックを使用してユーザー プロンプトをログに記録し、リポジトリで実行できるツール Copilot CLI 制御することで、チームは組織のセキュリティとコンプライアンスの要件内で安全に自動化できます。","product":"GitHub Copilot","breadcrumbs":[{"href":"/ja/copilot","title":"GitHub Copilot"},{"href":"/ja/copilot/tutorials","title":"チュートリアル"},{"href":"/ja/copilot/tutorials/copilot-cli-hooks","title":"Copilot CLI でフックを使用する"}],"documentType":"article"},"body":"# Copilot CLI でフックを使用して、ポリシーに準拠した予測可能な実行を行う\n\nフックを使用してユーザー プロンプトをログに記録し、リポジトリで実行できるツール Copilot CLI 制御することで、チームは組織のセキュリティとコンプライアンスの要件内で安全に自動化できます。\n\nこのチュートリアルは、 Copilot CLIを使用して開発者をサポートする DevOps エンジニア、プラットフォーム チーム、エンジニアリング リーダーを対象としています。\n\nフックは、 Copilot CLI セッション中に特定のポイントで実行されるカスタム スクリプトです。 プロンプトやツールの呼び出し、監査のログ情報を検査したり、特定のコマンドの実行をブロックしたりできます。\n\n次のようなリポジトリ スコープのフックを構成します。\n\n* プロンプトとツールの使用を可視化します。\n* 実行前に危険度の高いコマンド パターンをブロックします。\n* 開発者が明確なメッセージングを使用して組織のポリシーを理解できるようにします。\n\n## \\[前提条件]\n\n* シェル スクリプト (Bash または PowerShell) に関する知識。\n* JSON 構成ファイルの基本的な理解。\n* Copilot CLIが使用されているリポジトリへのアクセス。\n* Bash の例では、 `jq` をインストールする必要があります。\n* PowerShell の例では、PowerShell 7.0 以降をインストールする必要があります。\n\n## 1. 組織ポリシーを定義する\n\nフック スクリプトを記述する前に、自動的に許可するアクションと、人間によるレビューを必要とするアクションを決定します。\n\n明確なポリシーを使用すると、オーバーブロッキングを回避しながら、リスクを軽減できます。\n\n### レビューが常に必要なコマンドを特定する\n\nまず、 Copilot CLIによって自動実行されないようにするパターンを特定します。 たとえば、次のような場合です。\n\n* **特権エスカレーション**: `sudo`、 `su`、 `runas`\n* **破壊的なシステム操作**: `rm -rf /`、 `mkfs`、 `dd`、 `format`\n* **ダウンロードと実行のパターン**: `curl ... | bash`、 `wget ... | sh`、PowerShell `iex (irm ...)`\n\nこれらのコマンドは、意図せずに実行された場合、元に戻せない影響を与える可能性があります。\n\n### ログに記録する内容を決定する\n\nフックを使用すると、Copilot CLI がリポジトリでどのように使用されているかに関する情報をキャプチャできます。これには、ユーザーによって送信されたプロンプトや、Copilot CLI が実行を試みるツールが含まれます。\n\n少なくとも、ほとんどの組織では次のログが記録されます。\n\n* タイムスタンプとリポジトリのパス\n* プロンプト テキスト (または編集済みのフォーム)\n* ツール名とツール引数\n* ポリシーの決定 (拒否されたコマンドとその理由など)\n\nシークレットまたは資格情報のログ記録は避けてください。 プロンプトまたはコマンドに機密データが含まれている可能性がある場合は、ログを書き込む前にやり直しを適用します。\n\nこのチュートリアルでは、簡単でわかりやすい例として、ローカル `.github/hooks/logs` ディレクトリを使用します。 これらのログ ファイルは **リポジトリにコミットすることを意図したものではなく** 、通常は開発者のコンピューター上にのみ存在します。\n\n運用環境では、多くの組織がローカルでログを書き込むのではなく、一元的なログ記録または監視システムにイベントを転送します。 これにより、チームはリポジトリとユーザー間で一貫した編集、アクセス制御、保持ポリシー、監視を適用できます。\n\n### 利害関係者と連携する\n\nポリシーを適用する前に、以下を使用してポリシーを確認します。\n\n* リスクの境界を確認するためのセキュリティチームまたはコンプライアンス チーム\n* より広範なアクセス許可が必要なプラットフォームまたはインフラストラクチャ チーム\n* 開発チームは、ブロックされる内容とその理由を理解します\n\n明確な期待により、ポリシーの適用の導入と維持が容易になります。\n\n## 2. リポジトリフックファイルを設定する\n\nこのチュートリアルでは、\\*\\*\\*\\* に格納されている `.github/hooks/` を使用します。 これらのフックは、 Copilot CLI がこのリポジトリ内から実行されるたびに適用されます。\n\n> \\[!NOTE]\n> Copilot エージェントは、リポジトリ内の `.github/hooks/*.json` ファイルからフック構成を読み込みます。 フックは同期的に実行され、実行をブロックできます。\n\n### ディレクトリ構造を作成する\n\nリポジトリ ルートから、フック構成、スクリプト、およびログのディレクトリを作成します。\n\n```bash copy\nmkdir -p .github/hooks/scripts\nmkdir -p .github/hooks/logs\n```\n\nローカル監査ログがコミットされないように、.gitignore に `.github/hooks/logs/` を追加します。\n\n```bash copy\necho \".github/hooks/logs/\" >> .gitignore\n```\n\nこのチュートリアルでは、次の構造を使用します。\n\n```text\n.github/\n└── hooks/\n    ├── copilot-cli-policy.json\n    ├── logs/\n    │   └── audit.jsonl\n    └── scripts/\n        ├── session-banner.sh\n        ├── session-banner.ps1\n        ├── log-prompt.sh\n        ├── log-prompt.ps1\n        ├── pre-tool-policy.sh\n        └── pre-tool-policy.ps1\n```\n\n> \\[!NOTE]\n> このチュートリアルでは、Windows、Linux、macOS で使用できる移植可能なフック構成とスクリプトを作成します。 そのため、 `scripts` ディレクトリには Bash スクリプトと PowerShell スクリプトの両方が含まれます。フック構成ファイルには、 `bash` エントリと `powershell` エントリが含まれます。 CLI では、オペレーティング システムに基づいて適切なエントリが使用されます。\n\n### フック構成ファイルを作成する\n\n`.github/hooks/copilot-cli-policy.json` にフック構成ファイルを作成します。\n\nこのファイルでは、実行するフック、実行するタイミング、実行するスクリプトを定義します。\n\n```json copy\n{\n  \"version\": 1,\n  \"hooks\": {\n    \"sessionStart\": [\n      {\n        \"type\": \"command\",\n        \"bash\": \"./scripts/session-banner.sh\",\n        \"powershell\": \"./scripts/session-banner.ps1\",\n        \"cwd\": \".github/hooks\",\n        \"timeoutSec\": 10\n      }\n    ],\n    \"userPromptSubmitted\": [\n      {\n        \"type\": \"command\",\n        \"bash\": \"./scripts/log-prompt.sh\",\n        \"powershell\": \"./scripts/log-prompt.ps1\",\n        \"cwd\": \".github/hooks\",\n        \"timeoutSec\": 10\n      }\n    ],\n    \"preToolUse\": [\n      {\n        \"type\": \"command\",\n        \"bash\": \"./scripts/pre-tool-policy.sh\",\n        \"powershell\": \"./scripts/pre-tool-policy.ps1\",\n        \"cwd\": \".github/hooks\",\n        \"timeoutSec\": 15\n      }\n    ]\n  }\n}\n```\n\n### この構成の内容を理解する\n\nこの構成では、次の 3 つのフックが設定されます。\n\n* `sessionStart`: 新しいエージェント セッションの開始時または再開時の情報メッセージを表示します。\n* `userPromptSubmitted`: ユーザーがプロンプトを送信するたびに実行されます。\n* `preToolUse`: ツールが実行される前に実行され、実行を明示的に許可または拒否できます。\n\n### フック構成をコミットして共有する\n\nフック構成をコラボレーターと共有する準備ができたら (たとえば、pull request またはテスト リポジトリで)、フック構成とスクリプトをコミットします。 ローカル監査ログはコミットしないでください。\n\n```bash copy\ngit add .github/hooks/copilot-cli-policy.json .github/hooks/scripts\ngit commit -m \"Add Copilot CLI hook configuration\"\ngit push\n```\n\nこの時点で、フック スクリプトをまだ作成していない場合でも、 Copilot CLI はフック構成を検出できます。\n\n## 3. セッション開始時にポリシー バナーを追加する\n\n`sessionStart` フックを使用して、新しいCopilot CLI セッションが開始または再開されるたびにバナーを表示します。 これにより、組織のポリシーがアクティブであることを開発者に明確に示します。\n\n`sessionStart` フックは、現在の作業ディレクトリや初期プロンプトなどのコンテキスト情報を受け取ります。 このフックからの出力は Copilot CLIによって無視されるため、情報メッセージに適しています。\n\n### セッション バナー スクリプトを作成する (Bash)\n\n`.github/hooks/scripts/session-banner.sh`を作成します。\n\n```bash copy\n#!/bin/bash\nset -euo pipefail\n\ncat << 'EOF'\nCOPILOT CLI POLICY ACTIVE\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n• Prompts and tool use may be logged for auditing\n• High-risk commands may be blocked automatically\n• If something is blocked, follow the guidance shown\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nEOF\nexit 0\n```\n\n### セッション バナー スクリプトを作成する (PowerShell)\n\n`.github/hooks/scripts/session-banner.ps1`を作成します。\n\n```powershell copy\n$ErrorActionPreference = \"Stop\"\n\nWrite-Host @\"\nCOPILOT CLI POLICY ACTIVE\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n• Prompts and tool use may be logged for auditing\n• High-risk commands may be blocked automatically\n• If something is blocked, follow the guidance shown\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\"@\nexit 0\n```\n\n### セッション バナーをテストする\n\nバナー スクリプトを直接テストできます。\n\n```bash\n.github/hooks/scripts/session-banner.sh\n# or, for PowerShell\n.github/hooks/scripts/session-banner.ps1\n```\n\nいずれかのスクリプトを実行すると、ターミナルにポリシー バナーが表示されます。\n\n## 4. 監査のログ プロンプト\n\n`userPromptSubmitted` フックを使用して、ユーザーがCopilot CLIにプロンプトを送信したときに記録します。 このフックは、ツールが呼び出される前に、プロンプトが送信されるたびに実行されます。\n\nフックは、タイムスタンプ、現在の作業ディレクトリ、および完全なプロンプト テキストを含む構造化された JSON 入力を受け取ります。 このフックの出力は無視されます。\n\n> \\[!IMPORTANT]\n> プロンプトには機密情報が含まれている場合があります。 このデータをログに記録するときは、編集を適用し、組織のデータ処理と保持ポリシーに従います。\n\n### プロンプト ログ スクリプトを作成する (Bash)\n\n`.github/hooks/scripts/log-prompt.sh`を作成します。\n\n```bash copy\n#!/bin/bash\nset -euo pipefail\n\nINPUT=\"$(cat)\"\n\nTIMESTAMP_MS=\"$(echo \"$INPUT\" | jq -r '.timestamp // empty')\"\nCWD=\"$(echo \"$INPUT\" | jq -r '.cwd // empty')\"\n\n# This example logs only metadata, not the full prompt, to avoid storing\n# potentially sensitive data. Adjust to match your organization’s needs.\nLOG_DIR=\".github/hooks/logs\"\nmkdir -p \"$LOG_DIR\"\nchmod 700 \"$LOG_DIR\"\n\njq -n \\\n  --arg ts \"$TIMESTAMP_MS\" \\\n  --arg cwd \"$CWD\" \\\n  '{event:\"userPromptSubmitted\", timestampMs:$ts, cwd:$cwd}' \\\n  >> \"$LOG_DIR/audit.jsonl\"\n\nexit 0\n```\n\n### プロンプト ログ スクリプトを作成する (PowerShell)\n\n`.github/hooks/scripts/log-prompt.ps1`を作成します。\n\n```powershell copy\n$ErrorActionPreference = \"Stop\"\n\n$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json\n\n$timestampMs = $inputObj.timestamp\n$cwd = $inputObj.cwd\n$prompt = $inputObj.prompt\n\n# Optional example redaction. Adjust to match your organization’s needs.\n$redactedPrompt = $prompt -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]'\n\n$logDir = \".github/hooks/logs\"\nif (-not (Test-Path $logDir)) {\n  New-Item -ItemType Directory -Path $logDir -Force | Out-Null\n}\n\n$logEntry = @{\n  event       = \"userPromptSubmitted\"\n  timestampMs = $timestampMs\n  cwd         = $cwd\n  prompt      = $redactedPrompt\n} | ConvertTo-Json -Compress\n\nAdd-Content -Path \"$logDir/audit.jsonl\" -Value $logEntry\nexit 0\n```\n\n### プロンプト ログ スクリプトをテストする\n\nサンプル入力をパイプ処理することで、スクリプトを直接テストできます。\n\n```bash\necho '{\"timestamp\":1704614500000,\"cwd\":\"/repo\",\"prompt\":\"List all branches\"}' \\\n  | .github/hooks/scripts/log-prompt.sh\n# or, for PowerShell\necho '{\"timestamp\":1704614500000,\"cwd\":\"/repo\",\"prompt\":\"List all branches\"}' |\n  .github/hooks/scripts/log-prompt.ps1\n```\n\nスクリプトを実行した後、`.github/hooks/logs/audit.jsonl` で新しいログ エントリを確認します。\n\n```bash copy\ncat .github/hooks/logs/audit.jsonl\n```\n\nこの時点で、このリポジトリの Copilot CLI に送信されたプロンプトが監査のために記録されます。\n\n## 5. 次の方法でポリシーを適用する `preToolUse`\n\n`preToolUse` フックを使用して、ツール呼び出しを**実行前に評価します**。 このフックを使用すると、(何もしない) 実行または実行の拒否 (構造化された応答を返すことによって) 実行を許可できます。\n\n### `preToolUse`入力を理解する\n\n`preToolUse`フック入力には、次のものが含まれます。\n\n* `toolName`: Copilot CLI が実行されようとしているツール (たとえば、 `bash`)\n* `toolArgs`: そのツールの引数を含む **JSON 文字列**\n\n`toolArgs`は JSON 文字列であるため、スクリプトでは、`command`などのフィールドを読み取る前に解析する必要があります。\n\n> \\[!IMPORTANT]\n> ツールの引数とコマンドには、API トークン、パスワード、その他の資格情報などの機密情報が含まれている場合があります。 このデータをログに記録する前に編集を適用し、組織のセキュリティ ポリシーに従います。 機密性の高いメタデータ (ツール名、タイムスタンプ、ポリシー決定) のみをログに記録し、適切なaccess制御と保持ポリシーを使用して、セキュリティで保護された一元化されたログ システムに監査イベントを転送することを検討してください。\n\n### ポリシー スクリプトを作成する\n\n次に、ポリシー スクリプトを作成します。 この例では次のとおりです。\n\n* 試行されたすべてのツールの使用状況をログに記録します。\n* 拒否規則を bash コマンドにのみ適用します。\n* 特権エスカレーション、破壊的操作、ダウンロードおよび実行コマンドなどのリスクの高いパターンをブロックします。\n\n拒否フローを安全に検証できるように、スクリプトには無害なテスト コマンドをブロックする一時的なデモ ルールも含まれています。 フックが期待どおりに動作することを確認したら、デモルールを削除し、組織のポリシーを反映するパターンに置き換えます。\n\n#### スクリプトの例 (Bash)\n\n`.github/hooks/scripts/pre-tool-policy.sh`を作成します。\n\n```bash copy\n#!/bin/bash\nset -euo pipefail\n\nINPUT=\"$(cat)\"\n\nTOOL_NAME=\"$(echo \"$INPUT\" | jq -r '.toolName // empty')\"\nTOOL_ARGS_RAW=\"$(echo \"$INPUT\" | jq -r '.toolArgs // empty')\"  # JSON string\n\nLOG_DIR=\".github/hooks/logs\"\nmkdir -p \"$LOG_DIR\"\n\n# Example redaction logic.\n# GitHub does not currently provide built-in secret redaction for hooks.\n# This example shows one possible approach; many organizations prefer to\n# forward events to a centralized logging system that handles redaction.\n# Redact sensitive patterns before logging.\n# Adjust these patterns to match your organization's needs.\nREDACTED_TOOL_ARGS=\"$(echo \"$TOOL_ARGS_RAW\" | \\\n  sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n  sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n  sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n  sed -E 's/ghs_[A-Za-z0-9\\._\\-]{20,}/[REDACTED_TOKEN]/g' | \\\n  sed -E 's/Bearer [A-Za-z0-9_\\-\\.]+/Bearer [REDACTED]/g' | \\\n  sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \\\n  sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')\"\n\n# Log attempted tool use with redacted toolArgs.\njq -n \\\n  --arg tool \"$TOOL_NAME\" \\\n  --arg toolArgs \"$REDACTED_TOOL_ARGS\" \\\n  '{event:\"preToolUse\", toolName:$tool, toolArgs:$toolArgs}' \\\n  >> \"$LOG_DIR/audit.jsonl\"\n\n# Only enforce command rules for bash.\nif [ \"$TOOL_NAME\" != \"bash\" ]; then\n  exit 0\nfi\n\n# Parse toolArgs JSON string.\n# If toolArgs isn't valid JSON for some reason, allow (and rely on logs).\nif ! echo \"$TOOL_ARGS_RAW\" | jq -e . >/dev/null 2>&1; then\n  exit 0\nfi\n\nCOMMAND=\"$(echo \"$TOOL_ARGS_RAW\" | jq -r '.command // empty')\"\n\n# ---------------------------------------------------------------------------\n# Demo-only deny rule for safe testing.\n# This blocks a harmless test command so you can validate the deny flow.\n# Remove this rule after confirming your hooks work as expected.\n# ---------------------------------------------------------------------------\nif echo \"$COMMAND\" | grep -q \"COPILOT_HOOKS_DENY_DEMO\"; then\n  deny \"Blocked demo command (test rule). Remove this rule after validating hooks.\"\nfi\n\ndeny() {\n  local reason=\"$1\"\n\n  # Redact sensitive patterns from command before logging.\n  local redacted_cmd=\"$(echo \"$COMMAND\" | \\\n    sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n    sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n    sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \\\n    sed -E 's/ghs_[A-Za-z0-9\\.\\-_]{20,}/[REDACTED_TOKEN]/g' | \\\n    sed -E 's/Bearer [A-Za-z0-9_\\-\\.]+/Bearer [REDACTED]/g' | \\\n    sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \\\n    sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')\"\n\n  # Log the denial decision with redacted command.\n  jq -n \\\n    --arg cmd \"$redacted_cmd\" \\\n    --arg r \"$reason\" \\\n    '{event:\"policyDeny\", toolName:\"bash\", command:$cmd, reason:$r}' \\\n    >> \"$LOG_DIR/audit.jsonl\"\n\n  # Return a denial response.\n  jq -n \\\n    --arg r \"$reason\" \\\n    '{permissionDecision:\"deny\", permissionDecisionReason:$r}'\n\n  exit 0\n}\n\n# Privilege escalation\nif echo \"$COMMAND\" | grep -qE '\\b(sudo|su|runas)\\b'; then\n  deny \"Privilege escalation requires manual approval.\"\nfi\n\n# Destructive filesystem operations targeting root\nif echo \"$COMMAND\" | grep -qE 'rm\\s+-rf\\s*/($|\\s)|rm\\s+.*-rf\\s*/($|\\s)'; then\n  deny \"Destructive operations targeting the filesystem root require manual approval.\"\nfi\n\n# System-level destructive operations\nif echo \"$COMMAND\" | grep -qE '\\b(mkfs|dd|format)\\b'; then\n  deny \"System-level destructive operations are not allowed via automated execution.\"\nfi\n\n# Download-and-execute patterns\nif echo \"$COMMAND\" | grep -qE 'curl.*\\|\\s*(bash|sh)|wget.*\\|\\s*(bash|sh)'; then\n  deny \"Download-and-execute patterns require manual approval.\"\nfi\n\n# Allow by default\nexit 0\n```\n\n#### ポリシー スクリプトを作成する (PowerShell)\n\n`.github/hooks/scripts/pre-tool-policy.ps1`を作成します。\n\n```powershell copy\n$ErrorActionPreference = \"Stop\"\n\n$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json\n$toolName = $inputObj.toolName\n$toolArgsRaw = $inputObj.toolArgs  # JSON string\n\n$logDir = \".github/hooks/logs\"\nif (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }\n\n# Example redaction logic.\n# GitHub does not currently provide built-in secret redaction for hooks.\n# This example shows one possible approach; many organizations prefer to\n# forward events to a centralized logging system that handles redaction.\n# Redact sensitive patterns before logging.\n# Adjust these patterns to match your organization's needs.\n$redactedToolArgs = $toolArgsRaw `\n  -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n  -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n  -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n  -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n  -replace 'Bearer [A-Za-z0-9_\\-\\.]+', 'Bearer [REDACTED]' `\n  -replace '--password[= ][^ ]+', '--password=[REDACTED]' `\n  -replace '--token[= ][^ ]+', '--token=[REDACTED]'\n\n# Log attempted tool use with redacted toolArgs.\n(@{\n  event    = \"preToolUse\"\n  toolName = $toolName\n  toolArgs = $redactedToolArgs\n} | ConvertTo-Json -Compress) | Add-Content -Path \"$logDir/audit.jsonl\"\n\nif ($toolName -ne \"bash\") { exit 0 }\n\n# Parse toolArgs JSON string.\n$toolArgs = $null\ntry { $toolArgs = $toolArgsRaw | ConvertFrom-Json } catch { exit 0 }\n\n$command = $toolArgs.command\n\n# ---------------------------------------------------------------------------\n# Demo-only deny rule for safe testing.\n# This blocks a harmless test command so you can validate the deny flow.\n# Remove this rule after confirming your hooks work as expected.\n# ---------------------------------------------------------------------------\nif ($command -match 'COPILOT_HOOKS_DENY_DEMO') {\n  Deny \"Blocked demo command (test rule). Remove this rule after validating hooks.\"\n}\n\nfunction Deny([string]$reason) {\n  # Redact sensitive patterns from command before logging.\n  $redactedCommand = $command `\n    -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n    -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n    -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n    -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `\n    -replace 'Bearer [A-Za-z0-9_\\-\\.]+', 'Bearer [REDACTED]' `\n    -replace '--password[= ][^ ]+', '--password=[REDACTED]' `\n    -replace '--token[= ][^ ]+', '--token=[REDACTED]'\n\n  # Log the denial decision with redacted command.\n  (@{\n    event    = \"policyDeny\"\n    toolName = \"bash\"\n    command  = $redactedCommand\n    reason   = $reason\n  } | ConvertTo-Json -Compress) | Add-Content -Path \"$logDir/audit.jsonl\"\n\n  (@{\n    permissionDecision = \"deny\"\n    permissionDecisionReason = $reason\n  } | ConvertTo-Json -Compress)\n\n  exit 0\n}\n\nif ($command -match '\\b(sudo|su|runas)\\b') { Deny \"Privilege escalation requires manual approval.\" }\nif ($command -match 'rm\\s+-rf\\s*/(\\s|$)|rm\\s+.*-rf\\s*/(\\s|$)') { Deny \"Destructive operations targeting the filesystem root require manual approval.\" }\nif ($command -match '\\b(mkfs|dd|format)\\b') { Deny \"System-level destructive operations are not allowed via automated execution.\" }\nif ($command -match 'curl.*\\|\\s*(bash|sh)|wget.*\\|\\s*(bash|sh)') { Deny \"Download-and-execute patterns require manual approval.\" }\n\nexit 0\n```\n\n### ポリシー スクリプトをテストする\n\nサンプルの `preToolUse` 入力をパイプ処理してスクリプトをテストできます。\n\n許可する例:\n\n```bash\necho '{\"toolName\":\"bash\",\"toolArgs\":\"{\\\"command\\\":\\\"git status\\\"}\"}' \\\n  | .github/hooks/scripts/pre-tool-policy.sh\n# or, for PowerShell\necho '{\"toolName\":\"bash\",\"toolArgs\":\"{\\\"command\\\":\\\"git status\\\"}\"}' |\n  .github/hooks/scripts/pre-tool-policy.ps1\n```\n\n拒否の例:\n\n```bash\necho '{\"toolName\":\"bash\",\"toolArgs\":\"{\\\"command\\\":\\\"sudo rm -rf /\\\"}\"}' \\\n  | .github/hooks/scripts/pre-tool-policy.sh\n# or, for PowerShell\necho '{\"toolName\":\"bash\",\"toolArgs\":\"{\\\"command\\\":\\\"sudo rm -rf /\\\"}\"}' |\n  .github/hooks/scripts/pre-tool-policy.ps1\n```\n\n拒否の例を実行した後、`.github/hooks/logs/audit.jsonl` で新しい拒否ログ エントリを確認します。\n\n```json\n{\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Privilege escalation requires manual approval.\"}\n```\n\nこの時点で、リスクの高い `bash` コマンドは、このリポジトリでの自動実行からブロックされます。\n\n## 6. リポジトリでエンド ツー エンドのテストを行う\n\n構成ファイルとスクリプトを作成したら、このリポジトリで Copilot CLI を使用するときに、フックが期待どおりに実行されることを確認します。\n\n### フック構成ファイルを検証する\n\nフック構成ファイルが有効な JSON であることを確認します。\n\n```bash copy\njq '.' < .github/hooks/copilot-cli-policy.json\n```\n\n### スクリプトのアクセス許可を確認する (Unix ベースのシステム)\n\nmacOS と Linux では、Bash スクリプトが実行可能であることを確認します。\n\n```bash copy\nchmod +x .github/hooks/scripts/*.sh\n```\n\n### 基本的なセッションを実行する\n\nリポジトリで新しい Copilot CLI セッションを開始します。\n\n```bash copy\ncopilot -p \"Show me the status of this repository\"\n```\n\n予想される結果:\n\n* ( `sessionStart` から) ポリシー バナーが表示されます。\n* 新しいエントリが (`.github/hooks/logs/audit.jsonl` から) `userPromptSubmitted`に追加されます。\n\n### トリガー ツールの使用とログ記録の確認\n\nCopilot CLI でツール (bash など) を使用させるプロンプトを実行します:\n\n```bash copy\ncopilot -p \"Show me the last 5 git commits\"\n```\n\n予想される結果:\n\n* `preToolUse` エントリが `.github/hooks/logs/audit.jsonl` に追加されます。\n* ツール呼び出しが許可されている場合は、通常どおり実行が続行されます。\n\n### 拒否されたコマンドをテストする\n\nポリシー スクリプトの例には、文字列 `COPILOT_HOOKS_DENY_DEMO`を含むコマンドをブロックする一時的なデモ ルールが含まれています。 これにより、破壊的なコマンドを実行せずに、拒否フローを安全に検証できます。\n\n拒否されたコマンドをトリガーするプロンプトを実行します。\n\n```bash copy\ncopilot -p \"Run a test command: echo COPILOT_HOOKS_DENY_DEMO\"\n```\n\n予想される結果:\n\n* Copilot CLI はコマンドを実行しません。\n* フックは具体的な理由を伴って拒否応答を返します。\n* `policyDeny` エントリは、`.github/hooks/logs/audit.jsonl` に書き込まれます。\n\n拒否フローが正しく動作することを確認したら、スクリプトからデモ ルールを削除し、組織のポリシーを反映する拒否パターンに置き換えます。\n\n### 監査ログを検査する\n\n最近のエントリを表示するには:\n\n```bash copy\ntail -n 50 .github/hooks/logs/audit.jsonl\n```\n\n拒否された決定のみをフィルター処理するには:\n\n```bash copy\njq 'select(.event==\"policyDeny\")' .github/hooks/logs/audit.jsonl\n```\n\n## 7. チーム間で安全にロールアウトする\n\n1 つのリポジトリでフックを検証した後、開発ワークフローを中断しないように徐々に展開します。\n\n### ロールアウト戦略を選択する\n\n一般的なロールアウト方法は次のとおりです。\n\n* **ログ優先ロールアウト (推奨):** 実行を拒否せずに、プロンプトとツールの使用状況をログに記録することから始めます。 一定期間ログを確認し、一般的な使用パターンを理解したら拒否ルールを導入します。\n* **チームごとのロールアウト**: 一度に 1 つのチームまたはリポジトリにフックをデプロイし、フィードバックを収集してから、追加のチームに展開します。\n* **リスクベースのロールアウト**: 機密性の高いシステムまたは運用インフラストラクチャを処理するリポジトリから始めて、リスクの低いリポジトリに拡張します。\n\n### 期待を伝える\n\n拒否規則を適用する前に、開発者が以下を理解していることを確認してください。\n\n* そのフックがリポジトリでアクティブになっている\n* ブロックされる可能性があるコマンドの種類\n* コマンドが拒否された場合の続行方法\n\n明確なコミュニケーションにより、混乱とサポート要求が軽減されます。\n\n### ポリシーを保守可能な状態に保つ\n\n使用が進化するにつれて、次のようになります。\n\n* フックの構成とスクリプトをバージョン 管理に格納します。\n* 監査ログを定期的に確認して、新しいリスク パターンを検出します。\n* 広範な一致を追加するのではなく、拒否ルールを段階的かつ細かく更新します。\n* 各拒否規則が存在する理由 (特に影響の大きい制限の場合) を文書化します。\n\n### 例外を慎重に処理する\n\n一部のチーム (インフラストラクチャチームやプラットフォーム チームなど) には、より広範なアクセス許可が必要な場合があります。 これを安全に処理するには:\n\n* 異なるリポジトリに対して個別のフック構成を維持します。\n* 例外を絞り込み、十分に文書化します。\n* 監査可能性を損なうアドホック ローカル バイパスを回避します。\n\n## 詳細については、次を参照してください。\n\nフックのトラブルシューティングについては、 [フックを使用してエージェント ワークフローをカスタマイズする](/ja/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/use-hooks#troubleshooting) を参照してください。"}