Skip to main content

Copilot CLI でフックを使用して、ポリシーに準拠した予測可能な実行を行う

フックを使用してユーザー プロンプトをログに記録し、リポジトリで実行できるツール Copilot CLI (コパイロット CLI) 制御することで、チームは組織のセキュリティとコンプライアンスの要件内で安全に自動化できます。

このチュートリアルは、 Copilot CLI (コパイロット CLI)を使用して開発者をサポートする DevOps エンジニア、プラットフォーム チーム、エンジニアリング リーダーを対象としています。

フックは、 Copilot CLI (コパイロット CLI) セッション中に特定のポイントで実行されるカスタム スクリプトです。 プロンプトやツールの呼び出し、監査のログ情報を検査したり、特定のコマンドの実行をブロックしたりできます。

次のようなリポジトリ スコープのフックを構成します。

  • プロンプトとツールの使用を可視化します。
  • 実行前に危険度の高いコマンド パターンをブロックします。
  • 開発者が明確なメッセージングを使用して組織のポリシーを理解できるようにします。

[前提条件]

  • シェル スクリプトに関する知識 (Bash または PowerShell)
  • JSON 構成ファイルの基本的な理解
  • Copilot CLI (コパイロット CLI)が使用されているリポジトリへのアクセス
  • jq インストール済み (Bash の例用)

1. 組織ポリシーを定義する

フック スクリプトを記述する前に、自動的に許可するアクションと、人間によるレビューを必要とするアクションを決定します。

明確なポリシーを使用すると、オーバーブロッキングを回避しながら、リスクを軽減できます。

レビューが常に必要なコマンドを特定する

まず、 Copilot CLI (コパイロット CLI)によって自動実行されないようにするパターンを特定します。 たとえば、次のような場合です。

  • 特権エスカレーション: sudosurunas
  • 破壊的なシステム操作: rm -rf /mkfsddformat
  • ダウンロードと実行のパターン: curl ... | bashwget ... | sh、PowerShell iex (irm ...)

これらのコマンドは、意図せずに実行された場合、元に戻せない影響を与える可能性があります。

ログに記録する内容を決定する

フックを使用すると、Copilot CLI (コパイロット CLI) がリポジトリでどのように使用されているかに関する情報をキャプチャできます。これには、ユーザーによって送信されたプロンプトや、Copilot CLI (コパイロット CLI) が実行を試みるツールが含まれます。

少なくとも、ほとんどの組織では次のログが記録されます。

  • タイムスタンプとリポジトリのパス
  • プロンプト テキスト (または編集済みのフォーム)
  • ツール名とツール引数
  • ポリシーの決定 (拒否されたコマンドとその理由など)

シークレットまたは資格情報のログ記録は避けてください。 プロンプトまたはコマンドに機密データが含まれている可能性がある場合は、ログを書き込む前にやり直しを適用します。

このチュートリアルでは、簡単でわかりやすい例として、ローカル .github/hooks/logs ディレクトリを使用します。 これらのログ ファイルは リポジトリにコミットすることを意図したものではなく 、通常は開発者のコンピューター上にのみ存在します。

運用環境では、多くの組織がローカルでログを書き込むのではなく、一元的なログ記録または監視システムにイベントを転送します。 これにより、チームはリポジトリとユーザー間で一貫した編集、アクセス制御、保持ポリシー、監視を適用できます。

利害関係者と連携する

ポリシーを適用する前に、以下を使用してポリシーを確認します。

  • リスクの境界を確認するためのセキュリティチームまたはコンプライアンス チーム
  • より広範なアクセス許可が必要なプラットフォームまたはインフラストラクチャ チーム
  • 開発チームは、ブロックされる内容とその理由を理解します

明確な期待により、ポリシーの適用の導入と維持が容易になります。

2. リポジトリフックファイルを設定する

このチュートリアルでは、**** に格納されている .github/hooks/ を使用します。 これらのフックは、 Copilot CLI (コパイロット CLI) がこのリポジトリ内から実行されるたびに適用されます。

メモ

          Copilot エージェントは、リポジトリ内の `.github/hooks/*.json` からフック構成ファイルを読み込みます。 フックは同期的に実行され、実行をブロックできます。

ディレクトリ構造を作成する

リポジトリ ルートから、フック構成、スクリプト、およびログのディレクトリを作成します。

Bash
mkdir -p .github/hooks/scripts
mkdir -p .github/hooks/logs

ローカル監査ログがコミットされないように、.gitignore に .github/hooks/logs/ を追加します。

Bash
echo ".github/hooks/logs/" >> .gitignore

このチュートリアルでは、次の構造を使用します。

.github/
└── hooks/
    ├── copilot-cli-policy.json
    ├── logs/
    │   └── audit.jsonl
    └── scripts/
        ├── session-banner.sh
        ├── session-banner.ps1
        ├── log-prompt.sh
        ├── log-prompt.ps1
        ├── pre-tool-policy.sh
        └── pre-tool-policy.ps1

フック構成ファイルを作成する

          `.github/hooks/copilot-cli-policy.json` にフック構成ファイルを作成します。

このファイルでは、実行するフック、実行するタイミング、実行するスクリプトを定義します。

JSON
{
  "version": 1,
  "hooks": {
    "sessionStart": [
      {
        "type": "command",
        "bash": "./scripts/session-banner.sh",
        "powershell": "./scripts/session-banner.ps1",
        "cwd": ".github/hooks",
        "timeoutSec": 10
      }
    ],
    "userPromptSubmitted": [
      {
        "type": "command",
        "bash": "./scripts/log-prompt.sh",
        "powershell": "./scripts/log-prompt.ps1",
        "cwd": ".github/hooks",
        "timeoutSec": 10
      }
    ],
    "preToolUse": [
      {
        "type": "command",
        "bash": "./scripts/pre-tool-policy.sh",
        "powershell": "./scripts/pre-tool-policy.ps1",
        "cwd": ".github/hooks",
        "timeoutSec": 15
      }
    ]
  }
}

この構成の内容を理解する

この構成では、次の 3 つのフックが設定されます。

  • sessionStart: 新しいエージェント セッションの開始時または再開時の情報メッセージを表示します。
  • userPromptSubmitted: ユーザーがプロンプトを送信するたびに実行されます。
  • preToolUse: ツールが実行される前に実行され、実行を明示的に許可または拒否できます。

フック構成をコミットして共有する

フック構成をコラボレーターと共有する準備ができたら (たとえば、pull request またはテスト リポジトリで)、フック構成とスクリプトをコミットします。 ローカル監査ログはコミットしないでください。

Bash
git add .github/hooks/copilot-cli-policy.json .github/hooks/scripts
git commit -m "Add Copilot CLI hook configuration"
git push

この時点で、フック スクリプトをまだ作成していない場合でも、 Copilot CLI (コパイロット CLI) はフック構成を検出できます。

3. セッション開始時にポリシー バナーを追加する

          `sessionStart` フックを使用して、新しいCopilot CLI (コパイロット CLI) セッションが開始または再開されるたびにバナーを表示します。 これにより、組織のポリシーがアクティブであることを開発者に明確に示します。

          `sessionStart` フックは、現在の作業ディレクトリや初期プロンプトなどのコンテキスト情報を受け取ります。 このフックからの出力は Copilot CLI (コパイロット CLI)によって無視されるため、情報メッセージに適しています。

セッション バナー スクリプトを作成する (Bash)

          `.github/hooks/scripts/session-banner.sh`を作成します。
Bash
#!/bin/bash
set -euo pipefail

cat << 'EOF'
COPILOT CLI POLICY ACTIVE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Prompts and tool use may be logged for auditing
• High-risk commands may be blocked automatically
• If something is blocked, follow the guidance shown
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF
exit 0

セッション バナー スクリプトを作成する (PowerShell)

          `.github/hooks/scripts/session-banner.ps1`を作成します。
PowerShell
$ErrorActionPreference = "Stop"

Write-Host @"
COPILOT CLI POLICY ACTIVE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Prompts and tool use may be logged for auditing
• High-risk commands may be blocked automatically
• If something is blocked, follow the guidance shown
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
"@
exit 0

セッション バナーをテストする

バナー スクリプトを直接テストできます。

.github/hooks/scripts/session-banner.sh
# or, for PowerShell
.github/hooks/scripts/session-banner.ps1

いずれかのスクリプトを実行すると、ターミナルにポリシー バナーが表示されます。

4. 監査のログ プロンプト

          `userPromptSubmitted` フックを使用して、ユーザーがCopilot CLI (コパイロット CLI)にプロンプトを送信したときに記録します。 このフックは、ツールが呼び出される前に、プロンプトが送信されるたびに実行されます。

フックは、タイムスタンプ、現在の作業ディレクトリ、および完全なプロンプト テキストを含む構造化された JSON 入力を受け取ります。 このフックの出力は無視されます。

重要

プロンプトには機密情報が含まれている場合があります。 このデータをログに記録するときは、編集を適用し、組織のデータ処理と保持ポリシーに従います。

プロンプト ログ スクリプトを作成する (Bash)

          `.github/hooks/scripts/log-prompt.sh`を作成します。
Bash
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"

TIMESTAMP_MS="$(echo "$INPUT" | jq -r '.timestamp // empty')"
CWD="$(echo "$INPUT" | jq -r '.cwd // empty')"

# This example logs only metadata, not the full prompt, to avoid storing
# potentially sensitive data. Adjust to match your organization’s needs.
LOG_DIR=".github/hooks/logs"
mkdir -p "$LOG_DIR"
chmod 700 "$LOG_DIR"

jq -n \
  --arg ts "$TIMESTAMP_MS" \
  --arg cwd "$CWD" \
  '{event:"userPromptSubmitted", timestampMs:$ts, cwd:$cwd}' \
  >> "$LOG_DIR/audit.jsonl"

exit 0

プロンプト ログ スクリプトを作成する (PowerShell)

          `.github/hooks/scripts/log-prompt.ps1`を作成します。
PowerShell
$ErrorActionPreference = "Stop"

$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json

$timestampMs = $inputObj.timestamp
$cwd = $inputObj.cwd
$prompt = $inputObj.prompt

# Optional example redaction. Adjust to match your organization’s needs.
$redactedPrompt = $prompt -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]'

$logDir = ".github/hooks/logs"
if (-not (Test-Path $logDir)) {
  New-Item -ItemType Directory -Path $logDir -Force | Out-Null
}

$logEntry = @{
  event       = "userPromptSubmitted"
  timestampMs = $timestampMs
  cwd         = $cwd
  prompt      = $redactedPrompt
} | ConvertTo-Json -Compress

Add-Content -Path "$logDir/audit.jsonl" -Value $logEntry
exit 0

プロンプト ログ スクリプトをテストする

サンプル入力をパイプ処理することで、スクリプトを直接テストできます。

echo '{"timestamp":1704614500000,"cwd":"/repo","prompt":"List all branches"}' \
  | .github/hooks/scripts/log-prompt.sh
# or, for PowerShell
echo '{"timestamp":1704614500000,"cwd":"/repo","prompt":"List all branches"}' |
  .github/hooks/scripts/log-prompt.ps1

スクリプトを実行した後、.github/hooks/logs/audit.jsonl で新しいログ エントリを確認します。

Bash
cat .github/hooks/logs/audit.jsonl

この時点で、このリポジトリの Copilot CLI (コパイロット CLI) に送信されたプロンプトが監査のために記録されます。

5. 次の方法でポリシーを適用する preToolUse

          `preToolUse` フックを使用して、ツール呼び出しを**実行前に評価します**。 このフックを使用すると、(何もしない) 実行または実行の拒否 (構造化された応答を返すことによって) 実行を許可できます。

          `preToolUse`入力を理解する

          `preToolUse`フック入力には、次のものが含まれます。
  • toolName: Copilot CLI (コパイロット CLI) が実行されようとしているツール (たとえば、 bash)

  • toolArgs: そのツールの引数を含む JSON 文字列

            `toolArgs`は JSON 文字列であるため、スクリプトでは、`command`などのフィールドを読み取る前に解析する必要があります。
    

重要

ツールの引数とコマンドには、API トークン、パスワード、その他の資格情報などの機密情報が含まれている場合があります。 このデータをログに記録する前に編集を適用し、組織のセキュリティ ポリシーに従います。 機密性の高いメタデータ (ツール名、タイムスタンプ、ポリシー決定) のみをログに記録し、適切なaccess制御と保持ポリシーを使用して、セキュリティで保護された一元化されたログ システムに監査イベントを転送することを検討してください。

ポリシー スクリプトを作成する

次に、ポリシー スクリプトを作成します。 この例では次のとおりです。

  • 試行されたすべてのツールの使用状況をログに記録します。
  • 拒否規則を bash コマンドにのみ適用します。
  • 特権エスカレーション、破壊的操作、ダウンロードおよび実行コマンドなどのリスクの高いパターンをブロックします。

拒否フローを安全に検証できるように、スクリプトには無害なテスト コマンドをブロックする一時的なデモ ルールも含まれています。 フックが期待どおりに動作することを確認したら、デモルールを削除し、組織のポリシーを反映するパターンに置き換えます。

スクリプトの例 (Bash)

          `.github/hooks/scripts/pre-tool-policy.sh`を作成します。
Bash
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"

TOOL_NAME="$(echo "$INPUT" | jq -r '.toolName // empty')"
TOOL_ARGS_RAW="$(echo "$INPUT" | jq -r '.toolArgs // empty')"  # JSON string

LOG_DIR=".github/hooks/logs"
mkdir -p "$LOG_DIR"

# Example redaction logic.
# GitHub does not currently provide built-in secret redaction for hooks.
# This example shows one possible approach; many organizations prefer to
# forward events to a centralized logging system that handles redaction.
# Redact sensitive patterns before logging.
# Adjust these patterns to match your organization's needs.
REDACTED_TOOL_ARGS="$(echo "$TOOL_ARGS_RAW" | \
  sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
  sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
  sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
  sed -E 's/ghs_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
  sed -E 's/Bearer [A-Za-z0-9_\-\.]+/Bearer [REDACTED]/g' | \
  sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \
  sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')"

# Log attempted tool use with redacted toolArgs.
jq -n \
  --arg tool "$TOOL_NAME" \
  --arg toolArgs "$REDACTED_TOOL_ARGS" \
  '{event:"preToolUse", toolName:$tool, toolArgs:$toolArgs}' \
  >> "$LOG_DIR/audit.jsonl"

# Only enforce command rules for bash.
if [ "$TOOL_NAME" != "bash" ]; then
  exit 0
fi

# Parse toolArgs JSON string.
# If toolArgs isn't valid JSON for some reason, allow (and rely on logs).
if ! echo "$TOOL_ARGS_RAW" | jq -e . >/dev/null 2>&1; then
  exit 0
fi

COMMAND="$(echo "$TOOL_ARGS_RAW" | jq -r '.command // empty')"

# ---------------------------------------------------------------------------
# Demo-only deny rule for safe testing.
# This blocks a harmless test command so you can validate the deny flow.
# Remove this rule after confirming your hooks work as expected.
# ---------------------------------------------------------------------------
if echo "$COMMAND" | grep -q "COPILOT_HOOKS_DENY_DEMO"; then
  deny "Blocked demo command (test rule). Remove this rule after validating hooks."
fi

deny() {
  local reason="$1"

  # Redact sensitive patterns from command before logging.
  local redacted_cmd="$(echo "$COMMAND" | \
    sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
    sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
    sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
    sed -E 's/ghs_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \
    sed -E 's/Bearer [A-Za-z0-9_\-\.]+/Bearer [REDACTED]/g' | \
    sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \
    sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')"

  # Log the denial decision with redacted command.
  jq -n \
    --arg cmd "$redacted_cmd" \
    --arg r "$reason" \
    '{event:"policyDeny", toolName:"bash", command:$cmd, reason:$r}' \
    >> "$LOG_DIR/audit.jsonl"

  # Return a denial response.
  jq -n \
    --arg r "$reason" \
    '{permissionDecision:"deny", permissionDecisionReason:$r}'

  exit 0
}

# Privilege escalation
if echo "$COMMAND" | grep -qE '\b(sudo|su|runas)\b'; then
  deny "Privilege escalation requires manual approval."
fi

# Destructive filesystem operations targeting root
if echo "$COMMAND" | grep -qE 'rm\s+-rf\s*/($|\s)|rm\s+.*-rf\s*/($|\s)'; then
  deny "Destructive operations targeting the filesystem root require manual approval."
fi

# System-level destructive operations
if echo "$COMMAND" | grep -qE '\b(mkfs|dd|format)\b'; then
  deny "System-level destructive operations are not allowed via automated execution."
fi

# Download-and-execute patterns
if echo "$COMMAND" | grep -qE 'curl.*\|\s*(bash|sh)|wget.*\|\s*(bash|sh)'; then
  deny "Download-and-execute patterns require manual approval."
fi

# Allow by default
exit 0

ポリシー スクリプトを作成する (PowerShell)

          `.github/hooks/scripts/pre-tool-policy.ps1`を作成します。
PowerShell
$ErrorActionPreference = "Stop"

$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json
$toolName = $inputObj.toolName
$toolArgsRaw = $inputObj.toolArgs  # JSON string

$logDir = ".github/hooks/logs"
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }

# Example redaction logic.
# GitHub does not currently provide built-in secret redaction for hooks.
# This example shows one possible approach; many organizations prefer to
# forward events to a centralized logging system that handles redaction.
# Redact sensitive patterns before logging.
# Adjust these patterns to match your organization's needs.
$redactedToolArgs = $toolArgsRaw `
  -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
  -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
  -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
  -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
  -replace 'Bearer [A-Za-z0-9_\-\.]+', 'Bearer [REDACTED]' `
  -replace '--password[= ][^ ]+', '--password=[REDACTED]' `
  -replace '--token[= ][^ ]+', '--token=[REDACTED]'

# Log attempted tool use with redacted toolArgs.
(@{
  event    = "preToolUse"
  toolName = $toolName
  toolArgs = $redactedToolArgs
} | ConvertTo-Json -Compress) | Add-Content -Path "$logDir/audit.jsonl"

if ($toolName -ne "bash") { exit 0 }

# Parse toolArgs JSON string.
$toolArgs = $null
try { $toolArgs = $toolArgsRaw | ConvertFrom-Json } catch { exit 0 }

$command = $toolArgs.command

# ---------------------------------------------------------------------------
# Demo-only deny rule for safe testing.
# This blocks a harmless test command so you can validate the deny flow.
# Remove this rule after confirming your hooks work as expected.
# ---------------------------------------------------------------------------
if ($command -match 'COPILOT_HOOKS_DENY_DEMO') {
  Deny "Blocked demo command (test rule). Remove this rule after validating hooks."
}

function Deny([string]$reason) {
  # Redact sensitive patterns from command before logging.
  $redactedCommand = $command `
    -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
    -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
    -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
    -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' `
    -replace 'Bearer [A-Za-z0-9_\-\.]+', 'Bearer [REDACTED]' `
    -replace '--password[= ][^ ]+', '--password=[REDACTED]' `
    -replace '--token[= ][^ ]+', '--token=[REDACTED]'

  # Log the denial decision with redacted command.
  (@{
    event    = "policyDeny"
    toolName = "bash"
    command  = $redactedCommand
    reason   = $reason
  } | ConvertTo-Json -Compress) | Add-Content -Path "$logDir/audit.jsonl"

  (@{
    permissionDecision = "deny"
    permissionDecisionReason = $reason
  } | ConvertTo-Json -Compress)

  exit 0
}

if ($command -match '\b(sudo|su|runas)\b') { Deny "Privilege escalation requires manual approval." }
if ($command -match 'rm\s+-rf\s*/(\s|$)|rm\s+.*-rf\s*/(\s|$)') { Deny "Destructive operations targeting the filesystem root require manual approval." }
if ($command -match '\b(mkfs|dd|format)\b') { Deny "System-level destructive operations are not allowed via automated execution." }
if ($command -match 'curl.*\|\s*(bash|sh)|wget.*\|\s*(bash|sh)') { Deny "Download-and-execute patterns require manual approval." }

exit 0

ポリシー スクリプトをテストする

サンプルの preToolUse 入力をパイプ処理してスクリプトをテストできます。

許可する例:

echo '{"toolName":"bash","toolArgs":"{\"command\":\"git status\"}"}' \
  | .github/hooks/scripts/pre-tool-policy.sh
# or, for PowerShell
echo '{"toolName":"bash","toolArgs":"{\"command\":\"git status\"}"}' |
  .github/hooks/scripts/pre-tool-policy.ps1

拒否の例:

echo '{"toolName":"bash","toolArgs":"{\"command\":\"sudo rm -rf /\"}"}' \
  | .github/hooks/scripts/pre-tool-policy.sh
# or, for PowerShell
echo '{"toolName":"bash","toolArgs":"{\"command\":\"sudo rm -rf /\"}"}' |
  .github/hooks/scripts/pre-tool-policy.ps1

拒否の例を実行した後、.github/hooks/logs/audit.jsonl で新しい拒否ログ エントリを確認します。

{"permissionDecision":"deny","permissionDecisionReason":"Privilege escalation requires manual approval."}

この時点で、リスクの高い bash コマンドは、このリポジトリでの自動実行からブロックされます。

6. リポジトリでエンド ツー エンドのテストを行う

構成ファイルとスクリプトを作成したら、このリポジトリで Copilot CLI (コパイロット CLI) を使用するときに、フックが期待どおりに実行されることを確認します。

フック構成ファイルを検証する

フック構成ファイルが有効な JSON であることを確認します。

Bash
jq '.' < .github/hooks/copilot-cli-policy.json

スクリプトのアクセス許可を確認する (Unix ベースのシステム)

macOS と Linux では、Bash スクリプトが実行可能であることを確認します。

Bash
chmod +x .github/hooks/scripts/*.sh

基本的なセッションを実行する

リポジトリで新しい Copilot CLI (コパイロット CLI) セッションを開始します。

Bash
copilot -p "Show me the status of this repository"

予想される結果:

  • ( sessionStart から) ポリシー バナーが表示されます。
  • 新しいエントリが (.github/hooks/logs/audit.jsonl から) userPromptSubmittedに追加されます。

トリガー ツールの使用とログ記録の確認

Copilot CLI (コパイロット CLI) でツール (bash など) を使用させるプロンプトを実行します:

Bash
copilot -p "Show me the last 5 git commits"

予想される結果:

  • preToolUse エントリが .github/hooks/logs/audit.jsonl に追加されます。
  • ツール呼び出しが許可されている場合は、通常どおり実行が続行されます。

拒否されたコマンドをテストする

ポリシー スクリプトの例には、文字列 COPILOT_HOOKS_DENY_DEMOを含むコマンドをブロックする一時的なデモ ルールが含まれています。 これにより、破壊的なコマンドを実行せずに、拒否フローを安全に検証できます。

拒否されたコマンドをトリガーするプロンプトを実行します。

Bash
copilot -p "Run a test command: echo COPILOT_HOOKS_DENY_DEMO"

予想される結果:

  • Copilot CLI (コパイロット CLI) はコマンドを実行しません。
  • フックは具体的な理由を伴って拒否応答を返します。
  • policyDeny エントリは、.github/hooks/logs/audit.jsonl に書き込まれます。

拒否フローが正しく動作することを確認したら、スクリプトからデモ ルールを削除し、組織のポリシーを反映する拒否パターンに置き換えます。

監査ログを検査する

最近のエントリを表示するには:

Bash
tail -n 50 .github/hooks/logs/audit.jsonl

拒否された決定のみをフィルター処理するには:

Bash
jq 'select(.event=="policyDeny")' .github/hooks/logs/audit.jsonl

7. チーム間で安全にロールアウトする

1 つのリポジトリでフックを検証した後、開発ワークフローを中断しないように徐々に展開します。

ロールアウト戦略を選択する

一般的なロールアウト方法は次のとおりです。

  • ログ優先ロールアウト (推奨): 実行を拒否せずに、プロンプトとツールの使用状況をログに記録することから始めます。 一定期間ログを確認し、一般的な使用パターンを理解したら拒否ルールを導入します。
  • チームごとのロールアウト: 一度に 1 つのチームまたはリポジトリにフックをデプロイし、フィードバックを収集してから、追加のチームに展開します。
  • リスクベースのロールアウト: 機密性の高いシステムまたは運用インフラストラクチャを処理するリポジトリから始めて、リスクの低いリポジトリに拡張します。

期待を伝える

拒否規則を適用する前に、開発者が以下を理解していることを確認してください。

  • そのフックがリポジトリでアクティブになっている
  • ブロックされる可能性があるコマンドの種類
  • コマンドが拒否された場合の続行方法

明確なコミュニケーションにより、混乱とサポート要求が軽減されます。

ポリシーを保守可能な状態に保つ

使用が進化するにつれて、次のようになります。

  • フックの構成とスクリプトをバージョン 管理に格納します。
  • 監査ログを定期的に確認して、新しいリスク パターンを検出します。
  • 広範な一致を追加するのではなく、拒否ルールを段階的かつ細かく更新します。
  • 各拒否規則が存在する理由 (特に影響の大きい制限の場合) を文書化します。

例外を慎重に処理する

一部のチーム (インフラストラクチャチームやプラットフォーム チームなど) には、より広範なアクセス許可が必要な場合があります。 これを安全に処理するには:

  • 異なるリポジトリに対して個別のフック構成を維持します。
  • 例外を絞り込み、十分に文書化します。
  • 監査可能性を損なうアドホック ローカル バイパスを回避します。

詳細については、次を参照してください。

フックのトラブルシューティングについては、 フックを使用してエージェント ワークフローをカスタマイズする を参照してください。