Dieses Lernprogramm richtet sich an DevOps-Ingenieure, Plattformteams und technische Führungskräfte, die Entwickler mit Copilot-CLI unterstützen.
Hooks sind benutzerdefinierte Skripte, die während einer Copilot-CLI Sitzung an bestimmten Stellen ausgeführt werden. Sie können Eingabeaufforderungen und Toolaufrufe prüfen, Informationen zur Überwachung protokollieren und sogar die Ausführung bestimmter Befehle blockieren.
Sie konfigurieren Repository-spezifische Hooks, die:
- Bieten Sie Einblicke in Eingabeaufforderungen und die Verwendung von Tools.
- Blockieren Von Befehlsmustern mit hohem Risiko vor der Ausführung.
- Helfen Sie Entwicklern, Organisationsrichtlinien mit klaren Nachrichten zu verstehen.
Voraussetzungen
- Vertrautheit mit Shellskripting (Bash oder PowerShell)
- Grundlegendes Verständnis von JSON-Konfigurationsdateien
- Zugriff auf ein Repository, in dem Copilot-CLI verwendet wird
-
`jq` installiert (für die Bash-Beispiele)
1. Definieren einer Organisationsrichtlinie
Bevor Sie Hook-Skripts schreiben, entscheiden Sie, welche Aktionen automatisch zugelassen werden sollen und welche eine menschliche Überprüfung erfordern sollten.
Eine klare Richtlinie hilft Ihnen, die Übersperrung zu vermeiden und gleichzeitig das Risiko zu verringern.
Identifizieren von Befehlen, für die immer eine Überprüfung erforderlich ist
Beginnen Sie mit der Identifizierung von Mustern, die niemals von {data variables.copilot.copilot_cli_short} automatisch ausgeführt werden sollen. Häufige Beispiele sind:
-
**Berechtigungseskalation**: `sudo`, `su``runas` -
**Destruktive Systemvorgänge**: `rm -rf /`, `mkfs`, `dd``format` -
**Download- und Ausführungsmuster**: `curl ... | bash`, `wget ... | sh`, PowerShell `iex (irm ...)`
Diese Befehle können unwiderrufliche Auswirkungen haben, wenn sie unbeabsichtigt ausgeführt werden.
Entscheiden, was protokolliert werden soll
Wenn Sie Hooks verwenden, können Sie Informationen darüber erfassen, wie Copilot-CLI in einem Repository verwendet wird, einschließlich Aufforderungen, die von Benutzern und Tools übermittelt werden, die Copilot-CLI versucht auszuführen.
Mindestens protokollieren die meisten Organisationen:
- Der Zeitstempel und der Repository-Pfad
- Der Text der Eingabeaufforderung (oder in redigierter Form)
- Der Toolname und die Toolargumente
- Jede Richtlinienentscheidung (z. B. ein verweigerter Befehl und sein Grund)
Vermeiden Sie die Protokollierung geheimer Schlüssel oder Anmeldeinformationen. Wenn Eingabeaufforderungen oder Befehle möglicherweise vertrauliche Daten enthalten, entfernen Sie diese Informationen, bevor Sie Protokolle schreiben.
In diesem Lernprogramm wird ein lokales .github/hooks/logs Verzeichnis als einfaches, illustratives Beispiel verwendet. Diese Protokolldateien sind nicht für das Repository vorgesehen und befinden sich in der Regel nur auf dem Computer eines Entwicklers.
In Produktionsumgebungen leiten viele Organisationen Hook-Ereignisse an ein zentralisiertes Protokollierungs- oder Observability-System weiter, anstatt Protokolle lokal zu schreiben. Auf diese Weise können Teams konsistente Redaction, Zugriffssteuerungen, Aufbewahrungsrichtlinien und Überwachungen für Repositorys und Benutzer anwenden.
Abstimmung mit Interessengruppen
Bevor Sie Richtlinien erzwingen, überprüfen Sie sie mit:
- Sicherheits- oder Complianceteams, um Risikogrenzen zu bestätigen
- Plattform- oder Infrastrukturteams, die möglicherweise umfassendere Berechtigungen benötigen
- Entwicklungsteams, damit sie verstehen, was blockiert wird und warum
Klare Erwartungen machen die Durchsetzung von Richtlinien einfacher zu übernehmen und aufrechtzuerhalten.
2. Einrichten von Repository-Hookdateien
In diesem Lernprogramm verwenden Sie Repository-bezogene Hooks, die im Repository unter .github/hooks/ gespeichert sind. Diese Hooks gelten immer, wenn Copilot-CLI innerhalb dieses Repositories ausgeführt wird.
Hinweis
Copilot Agents laden Hook-Konfigurationsdateien aus dem .github/hooks/*.json Repository. Hooks werden synchron ausgeführt und können die Ausführung blockieren.
Erstellen der Verzeichnisstruktur
Erstellen Sie im Repositorystamm Verzeichnisse für Ihre Hook-Konfiguration, Skripts und Protokolle:
mkdir -p .github/hooks/scripts mkdir -p .github/hooks/logs
mkdir -p .github/hooks/scripts
mkdir -p .github/hooks/logs
Fügen Sie .github/hooks/logs/ zu gitignore hinzu, damit lokale Überwachungsprotokolle nicht zugesichert werden:
echo ".github/hooks/logs/" >> .gitignore
echo ".github/hooks/logs/" >> .gitignore
In diesem Lernprogramm wird die folgende Struktur verwendet:
.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
Erstellen einer Hook-Konfigurationsdatei
Erstellen Sie eine Hook-Konfigurationsdatei unter .github/hooks/copilot-cli-policy.json.
Diese Datei definiert, welche Hooks ausgeführt werden, wann sie ausgeführt werden und welche Skripts ausgeführt werden.
{
"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
}
]
}
}
{
"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
}
]
}
}
Grundlegendes zur Funktionsweise dieser Konfiguration
Diese Konfiguration richtet drei Hooks ein:
-
`sessionStart`: Zeigt eine Informationsmeldung an, wenn eine neue Agentsitzung gestartet oder fortgesetzt wird. -
`userPromptSubmitted`: Wird ausgeführt, wenn ein Benutzer eine Eingabeaufforderung sendet. -
`preToolUse`: Wird ausgeführt, bevor ein Tool ausgeführt wird und die Ausführung explizit zulassen oder verweigern kann.
Commit und Freigeben der Hook-Konfiguration
Wenn Sie bereit sind, die Hook-Konfiguration für Mitarbeiter freizugeben (z. B. über eine Pullanforderung oder in einem Test-Repository), übernehmen Sie die Hook-Konfiguration und Skripts. Übergeben Sie keine lokalen Audit-Logs.
git add .github/hooks/copilot-cli-policy.json .github/hooks/scripts git commit -m "Add Copilot CLI hook configuration" git push
git add .github/hooks/copilot-cli-policy.json .github/hooks/scripts
git commit -m "Add Copilot CLI hook configuration"
git push
Zu diesem Zeitpunkt können Copilot-CLI Ihre Hookkonfiguration ermitteln, obwohl Sie die Hook-Skripts noch nicht erstellt haben.
3. Hinzufügen eines Richtlinienbanners beim Start der Sitzung
Verwenden Sie einen sessionStart Hook, um ein Banner anzuzeigen, wann immer eine neue Copilot-CLI Sitzung gestartet oder fortgesetzt wird. Dadurch wird Entwicklern klar, dass Organisationsrichtlinien aktiv sind.
Der sessionStart Hook empfängt kontextbezogene Informationen wie das aktuelle Arbeitsverzeichnis und die erste Eingabeaufforderung. Jede Ausgabe dieses Hooks wird von Copilot-CLI ignoriert, wodurch sie für Informationsnachrichten geeignet ist.
Erstellen des Sitzungsbannerskripts (Bash)
Erstellen:.github/hooks/scripts/session-banner.sh
#!/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
#!/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
Erstellen des Sitzungsbannerskripts (PowerShell)
Erstellen:.github/hooks/scripts/session-banner.ps1
$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
$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
Testen des Sitzungsbanners
Sie können die Bannerskripts direkt testen:
.github/hooks/scripts/session-banner.sh
# or, for PowerShell
.github/hooks/scripts/session-banner.ps1
Wenn Sie eines der Skripts ausführen, sollte das Richtlinienbanner in Ihrem Terminal angezeigt werden.
4. Protokollieren von Aufforderungen zur Prüfung
Verwenden Sie den userPromptSubmitted Hook, um aufzuzeichnen, wenn Benutzer Aufforderungen an Copilot-CLI senden. Dieser Hook wird immer ausgeführt, wenn eine Eingabeaufforderung gesendet wird, bevor tools aufgerufen werden.
Der Hook empfängt strukturierte JSON-Eingaben, die den Zeitstempel, das aktuelle Arbeitsverzeichnis und den vollständigen Eingabeaufforderungstext enthalten. Die Ausgabe dieses Hooks wird ignoriert.
Wichtig
Eingabeaufforderungen können vertrauliche Informationen enthalten. Wenden Sie Redaction an, und befolgen Sie die Datenverarbeitungs- und Aufbewahrungsrichtlinien Ihrer Organisation beim Protokollieren dieser Daten.
Skript zur Prompt-Protokollierung erstellen (Bash)
Erstellen:.github/hooks/scripts/log-prompt.sh
#!/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
#!/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
Erstellen Sie das Skript zur Protokollierung der Eingabeaufforderung (PowerShell)
Erstellen:.github/hooks/scripts/log-prompt.ps1
$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
$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
Das Skript zur Protokollierung von Prompts testen
Sie können die Skripte direkt testen, indem Sie Beispiel-Eingaben über eine Pipeline verwenden.
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
Überprüfen Sie .github/hooks/logs/audit.jsonl nach dem Ausführen des Skripts nach einem neuen Protokolleintrag.
cat .github/hooks/logs/audit.jsonl
cat .github/hooks/logs/audit.jsonl
An dieser Stelle werden Aufforderungen, die an Copilot-CLI in diesem Repository übermittelt werden, zur Überwachung aufgezeichnet.
5. Richtlinien erzwingen mit preToolUse
Verwenden Sie den preToolUse Hook, um einen Toolaufruf auszuwerten, bevor er ausgeführt wird. Dieser Hook kann die Ausführung erlauben (indem nichts unternommen wird) oder die Ausführung verweigern (durch Zurückgeben einer strukturierten Antwort).
Verstehen Sie die preToolUse Eingabe
Die preToolUse Hookeingabe umfasst:
-
`toolName`: Das Tool, das Copilot-CLI ausführt (z. B `bash`. ) -
`toolArgs`: Eine **JSON-Zeichenfolge** , die die Argumente dieses Tools enthält
Da toolArgs eine JSON-Zeichenfolge ist, muss Ihr Skript sie parsen, bevor es Felder wie command liest.
Wichtig
Toolargumente und -befehle können vertrauliche Informationen wie API-Token, Kennwörter oder andere Anmeldeinformationen enthalten. Wenden Sie Schwärzung an, bevor Sie diese Daten protokollieren, und befolgen Sie die Sicherheitsrichtlinien Ihrer Organisation. Erwägen Sie die Protokollierung nur nicht vertraulicher Metadaten (Toolname, Zeitstempel, Richtlinienentscheidung) und das Weiterleiten von Überwachungsereignissen an ein gesichertes, zentralisiertes Protokollierungssystem mit entsprechenden Zugriffssteuerungen und Aufbewahrungsrichtlinien.
Erstellen des Richtlinienskripts
Erstellen Sie als Nächstes ein Richtlinienskript. Dieses Beispiel:
- Protokolliert alle versuchten Toolverwendungen.
- Wendet Verweigerungsregeln nur auf Bash-Befehle an.
- Blockiert Hochrisikomuster wie Berechtigungseskalation, destruktive Vorgänge und Download- und Ausführungsbefehle.
Damit Sie den Verweigerungsfluss sicher überprüfen können, enthält das Skript auch eine temporäre Demoregel, die einen harmlosen Testbefehl blockiert. Nachdem Sie bestätigt haben, dass Hooks wie erwartet funktionieren, entfernen Sie die Demoregel, und ersetzen Sie sie durch Muster, die die Richtlinien Ihrer Organisation widerspiegeln.
Beispielskript (Bash)
Erstellen:.github/hooks/scripts/pre-tool-policy.sh
#!/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
#!/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
Erstellen des Richtlinienskripts (PowerShell)
Erstellen: .github/hooks/scripts/pre-tool-policy.ps1
$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
$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
Testen des Richtlinienskripts
Sie können die Skripts testen, indem Sie Beispiel-Eingaben über eine Pipe preToolUse eingeben.
Beispiel zulassen:
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
Beispiel für Ablehnung:
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
Überprüfen Sie .github/hooks/logs/audit.jsonl nach dem Ausführen des Ablehnungsbeispiels auf einen neuen Denialprotokolleintrag.
{"permissionDecision":"deny","permissionDecisionReason":"Privilege escalation requires manual approval."}
An diesem Punkt werden Hochrisikobefehle bash von der automatischen Ausführung in diesem Repository blockiert.
6. Durchführung eines End-to-End-Tests im gesamten Repository
Nachdem Sie die Konfigurationsdatei und Skripts erstellt haben, überprüfen Sie, ob Hooks wie erwartet ausgeführt werden, wenn Sie Copilot-CLI in diesem Repository verwenden.
Überprüfen der Hook-Konfigurationsdatei
Überprüfen Sie, ob die Hook-Konfigurationsdatei eine gültige JSON-Datei ist:
jq '.' < .github/hooks/copilot-cli-policy.json
jq '.' < .github/hooks/copilot-cli-policy.json
Überprüfen von Skriptberechtigungen (Unix-basierte Systeme)
Vergewissern Sie sich unter macOS und Linux, dass Ihre Bash-Skripts ausführbar sind:
chmod +x .github/hooks/scripts/*.sh
chmod +x .github/hooks/scripts/*.sh
Ausführen einer einfachen Sitzung
Starten Sie eine neue Copilot-CLI-Sitzung im Repository:
copilot -p "Show me the status of this repository"
copilot -p "Show me the status of this repository"
Erwartete Ergebnisse:
- Sie sehen das Richtlinienbanner (von
sessionStart). - Ein neuer Eintrag wird zu
.github/hooks/logs/audit.jsonl(vonuserPromptSubmitted) hinzugefügt.
Trigger-Tool verwenden und Protokollierung überprüfen
Führen Sie einen Prompt aus, der bewirkt, dass Copilot-CLI ein Tool verwendet (z. B. bash):
copilot -p "Show me the last 5 git commits"
copilot -p "Show me the last 5 git commits"
Erwartete Ergebnisse:
- Ein
preToolUseEintrag wird zu.github/hooks/logs/audit.jsonlhinzugefügt. - Wenn der Toolaufruf zulässig ist, wird die Ausführung normal fortgesetzt.
Testen eines verweigerten Befehls
Das Beispielrichtlinienskript enthält eine temporäre Demoregel, die Befehle blockiert, die die Zeichenfolge COPILOT_HOOKS_DENY_DEMOenthalten. Auf diese Weise können Sie den Verweigerungsfluss sicher überprüfen, ohne destruktive Befehle auszuführen.
Führen Sie eine Eingabeaufforderung aus, die einen verweigerten Befehl auslöst:
copilot -p "Run a test command: echo COPILOT_HOOKS_DENY_DEMO"
copilot -p "Run a test command: echo COPILOT_HOOKS_DENY_DEMO"
Erwartete Ergebnisse:
- Copilot-CLI führt den Befehl nicht aus.
- Ihr Hook liefert eine Ablehnungsantwort mit einer klaren Begründung zurück.
- Ein
policyDenyEintrag wird geschrieben in.github/hooks/logs/audit.jsonl.
Nachdem Sie bestätigt haben, dass der Verweigerungsfluss ordnungsgemäß funktioniert, entfernen Sie die Demoregel aus Ihrem Skript, und ersetzen Sie sie durch Verweigerungsmuster, die die Richtlinien Ihrer Organisation widerspiegeln.
Überprüfen Sie Ihre Prüfprotokolle
Um neueste Einträge anzusehen:
tail -n 50 .github/hooks/logs/audit.jsonl
tail -n 50 .github/hooks/logs/audit.jsonl
So filtern Sie nur verweigerte Entscheidungen:
jq 'select(.event=="policyDeny")' .github/hooks/logs/audit.jsonl
jq 'select(.event=="policyDeny")' .github/hooks/logs/audit.jsonl
7. Sicheres Rollout über die Teams hinweg
Nachdem Sie Ihre Hooks in einem einzigen Repository überprüft haben, führen Sie sie schrittweise aus, um Unterbrechungen von Entwicklungsworkflows zu vermeiden.
Auswählen einer Rolloutstrategie
Zu den gängigen Rolloutansätzen gehören:
-
**Protokollierungsorientiertes Rollout (empfohlen)**: Beginnen Sie mit der Protokollierung von Prompts und der Nutzung von Tools, ohne die Ausführung zu unterbrechen. Überprüfen Sie Protokolle für einen bestimmten Zeitraum, und führen Sie dann Verweigerungsregeln ein, sobald Sie allgemeine Verwendungsmuster verstehen. -
**Team-nach-Team-Rollout**: Stellen Sie Hooks an ein Team oder Repository nacheinander bereit, sammeln Sie Feedback, und erweitern Sie dann auf weitere Teams. -
**Risikobasiertes Rollout**: Beginnen Sie mit Repositorys, die sensible Systeme oder Produktionsinfrastruktur behandeln, und erweitern Sie dann auf Repositorys mit geringerem Risiko.
Kommunizieren von Erwartungen
Bevor Sie Verweigerungsregeln erzwingen, sollten Sie sicherstellen, dass Entwickler Folgendes verstehen:
- Diese Hooks sind im Repository aktiv
- Welche Arten von Befehlen blockiert werden können
- Vorgehensweise, wenn ein Befehl verweigert wird
Klare Kommunikation reduziert Verwirrung und Supportanfragen.
Richtlinien wartbar halten
Während sich die Nutzung weiterentwickelt:
- Store-Hook-Konfiguration und Skripts in der Versionssteuerung.
- Überprüfen Sie Überwachungsprotokolle regelmäßig, um neue Risikomuster zu erkennen.
- Aktualisieren Sie Ablehnungsregeln inkrementell, anstatt breite Übereinstimmungen hinzuzufügen.
- Dokumentieren Sie, warum jede Verweigerungsregel vorhanden ist, insbesondere für Einschränkungen mit hohem Einfluss.
Ausnahmen sorgfältig behandeln
Einige Teams (z. B. Infrastruktur- oder Plattformteams) erfordern möglicherweise umfassendere Berechtigungen. So behandeln Sie dies sicher:
- Verwalten Sie separate Hook-Konfigurationen für verschiedene Repositorys.
- Halten Sie Ausnahmen eng und gut dokumentiert.
- Vermeiden Sie ad-hoc lokale Umgehungen, die die Auditierbarkeit untergraben.
Weiterführende Lektüre
Zur Problembehandlung bei Hooks siehe Verwenden von Hooks mit GitHub Copilot-Agenten.