Skip to main content

将挂钩与 Copilot CLI 配合使用,实现可预测且符合策略的执行

使用 hooks 来记录用户提示,并控制 Copilot 命令行界面(CLI) 在仓库中可以运行哪些工具,从而让团队在符合组织安全与合规要求的前提下安全地实现自动化。

本教程适用于支持开发人员使用 Copilot 命令行界面(CLI) 的 DevOps 工程师、平台团队以及工程负责人。

Hooks 是在 Copilot 命令行界面(CLI) 会话期间特定时间点运行的自定义脚本。 他们可以检查提示和工具调用、记录审核信息,甚至阻止执行某些命令。

你将配置一些作用于存储库范围的钩子:

  • 提供对提示和工具使用情况的可见性。
  • 在执行前阻止高风险命令模式。
  • 帮助开发人员了解具有明确消息传送的组织策略。

先决条件

  • 熟悉 shell 脚本(Bash 或 PowerShell)
  • 基本了解 JSON 配置文件
  • 可访问正在使用 Copilot 命令行界面(CLI) 的仓库
  •         `jq` 已安装 (对于 Bash 示例)
    

1. 定义组织策略

在编写任何挂钩脚本之前,请确定哪些操作应自动允许,哪些操作需要人工审核。

明确的策略有助于避免过度阻塞,同时仍降低风险。

确定始终需要审阅的命令

首先识别那些绝不应由 Copilot 命令行界面(CLI) 自动执行的模式。 常见示例包括:

  •         **权限提升**: `sudo`, , `su``runas`
    
  •         **破坏性系统操作**:`rm -rf /`、`mkfs`、`dd`、`format`
    
  •         **下载和执行模式**:`curl ... | bash`、PowerShell `wget ... | sh``iex (irm ...)`
    

这些命令在无意中执行时可能会产生不可逆的影响。

确定要记录的内容

使用 hooks 时,你可以捕获 Copilot 命令行界面(CLI) 在仓库中的使用情况信息,包括用户提交的提示以及 Copilot 命令行界面(CLI) 尝试运行的工具。

大多数组织至少记录:

  • 时间戳和存储库路径
  • 提示文本(或经过编辑的形式)
  • 工具名称和工具参数
  • 任何策略决策(例如,被拒绝的命令及其原因)

请勿在日志中记录机密信息或凭证。 如果提示或命令可能包含敏感数据,请在编写日志之前应用修订。

本教程使用本地 .github/hooks/logs 目录作为一个简单的演示示例。 这些日志文件 不打算提交到存储库 ,通常仅存在于开发人员的计算机上。

在生产环境中,许多组织将事件转发到集中式日志记录或可观测性系统,而不是在本地编写日志。 这样,团队就可以在存储库和用户之间应用一致的编辑、访问控制、保留策略和监控。

与利益干系人保持一致

在强制实施策略之前,与以下人员一同审核它们:

  • 安全或合规性团队,以确认风险边界
  • 平台或基础结构团队,他们可能需要更广泛的权限
  • 开发团队,因此他们了解将被阻止的内容以及原因

明确的预期使政策强制实施更容易采用和维护。

2.设置存储库挂钩文件

在整个教程中,你将使用存储在仓库中 .github/hooks/ 下的仓库级 hooks。 每当 数据变量.copilot.copilot_cli_short %} 从该存储库内运行时,这些钩子适用。

注意

Copilot 代理从存储库中的 .github/hooks/*.json 中加载挂钩配置文件。 钩子同步运行,可以阻止程序的执行。

创建目录结构

在存储库根目录中,为挂钩配置、脚本和日志创建目录:

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

.github/hooks/logs/ 添加到 .gitignore 中,以避免本地审计日志被提交:

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
      }
    ]
  }
}

了解此配置的作用

此配置设置三个挂钩:

  •         `sessionStart`:显示新代理会话启动或恢复时的信息性消息。
    
  •         `userPromptSubmitted`:每当用户提交提示时运行。
    
  •         `preToolUse`:在工具执行之前运行,并且可以显式允许或拒绝执行。
    

提交并共享挂钩配置

当您准备好与协作者共享钩子配置时(例如,通过拉取请求或在测试存储库中),请提交钩子配置和脚本。 不要提交任何本地审核日志。

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

此时,即使你尚未创建 hook 脚本,Copilot 命令行界面(CLI) 也已经能够发现你的 hook 配置。

3. 在会话开始时添加策略横幅

使用一个 sessionStart hook,在每次新的 Copilot 命令行界面(CLI) 会话开始或恢复时显示横幅信息。 这向开发人员明确表示组织策略处于活动状态。

挂钩函数 sessionStart 接收上下文相关信息,例如当前工作目录和初始提示。 该 hook 的任何输出都会被 Copilot 命令行界面(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) 提交提示。 每次发送提示时,都会先运行此钩子,然后再调用任何工具。

挂钩接收结构化 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) 的提示都会被记录下来以供审计。

5.使用 preToolUse 强制执行策略

使用preToolUse挂钩来在工具调用运行之前进行评估。 此挂钩可以允许执行(不采取任何行动)或拒绝执行(通过返回结构化响应)。

了解 preToolUse 的输入

          `preToolUse` hook 的输入包括:

* toolNameCopilot 命令行界面(CLI) 即将运行的工具(例如 bash) * toolArgs:包含该工具参数的 JSON 字符串

因为 toolArgs 是 JSON 字符串,所以脚本在读取类似 command字段之前必须对其进行分析。

重要

工具参数和命令可能包含敏感信息,例如 API 令牌、密码或其他凭据。 在记录此数据之前应用修订,并遵循组织的安全策略。 请考虑仅记录非敏感元数据(工具名称、时间戳、策略决策),并将审核事件定向到具有适当access控制和保留策略的安全集中日志记录系统。

创建策略脚本

接下来,创建策略脚本。 本示例:

  • 记录所有尝试的工具使用情况。
  • 仅对 bash 命令应用拒绝规则。
  • 阻止高风险模式,例如特权升级、破坏性操作和下载并执行命令。

为了安全地验证拒绝流,该脚本还包括一个临时演示规则,用于阻止无害的测试命令。 在确认 hooks 按预期工作后,移除演示规则,并将其替换为符合你组织策略的模式。

示例脚本 (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) 时 hooks 是否按预期运行。

验证挂钩配置文件

检查挂钩配置文件是否为有效的 JSON:

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

验证脚本权限(基于 Unix 的系统)

在 macOS 和 Linux 上,确认 Bash 脚本是可执行的:

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

运行基本会话

在仓库中启动一个新的 Copilot 命令行界面(CLI) 会话:

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

预期结果:

  • 你将看到策略横幅(来自 sessionStart)。
  • 将新条目添加到 .github/hooks/logs/audit.jsonl(从 userPromptSubmitted)。

触发工具的使用与日志记录验证

运行提示以使 数据变量.copilot.copilot_cli_short %} 使用工具(例如 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) 不会执行该命令。
  • 钩子函数返回一个拒绝响应,并附有明确的原因。
  •         `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. 跨团队安全部署

在单个存储库中验证钩子后,逐步推出以避免中断开发工作流。

选择推出策略

常见的推出方法包括:

  •         **日志记录优先推出(建议)**:首先记录提示和工具使用情况,而无需拒绝执行。 查看一段时间的日志,然后在了解常见使用模式后引入拒绝规则。
    
  •         **团队部署**:一次将挂钩部署到一个团队或存储库,收集反馈,然后扩展到其他团队。
    
  •         **基于风险的推出**:从处理敏感系统或生产基础结构的存储库开始,然后扩展到风险较低的存储库。
    

传达期望

在强制实施拒绝规则之前,请确保开发人员了解:

  • 这表明 hooks 已在仓库中处于活动状态
  • 可以阻止哪些类型的命令
  • 如果执行命令被拒绝,应如何继续操作

清晰的沟通从而减少混淆和支持请求。

使策略保持可维护

随着使用情况的发展:

  • 将挂钩配置和脚本存储在版本控制中。
  • 定期查看审核日志,以检测新的风险模式。
  • 请逐步更新拒绝规则,而不要一次性添加范围过大的匹配规则。
  • 记录每个拒绝规则存在的原因,尤其是对于高影响限制。

小心处理异常

某些团队(例如基础结构或平台团队)可能需要更广泛的权限。 若要安全地处理此问题,

  • 维护不同存储库的单独挂钩配置。
  • 确保例外范围较窄且记录完善。
  • 避免临时性的本地绕过,这会削弱审计透明度。

延伸阅读

有关 hooks 的故障排查,请参阅 将钩子与 GitHub Copilot 代理配合使用