Skip to main content

예측 가능한 정책 준수를 위해 Copilot CLI와 연결고리 사용

후크를 사용하여 사용자 프롬프트를 기록하고 부조종사 CLI가 리포지토리에서 실행할 수 있는 도구를 제어하므로 팀은 조직의 보안 및 규정 준수 요구 사항 내에서 안전하게 자동화할 수 있습니다.

이 자습서는 부조종사 CLI를 사용하여 개발자를 지원하는 DevOps 엔지니어, 플랫폼 팀 및 엔지니어링 리더를 위한 것입니다.

후크는 부조종사 CLI 세션 중 특정 지점에서 실행되는 사용자 지정 스크립트입니다. 프롬프트 및 도구 호출, 감사에 대한 로그 정보 및 특정 명령의 실행을 차단할 수도 있습니다.

다음과 같은 리포지토리 범위 후크를 구성합니다.

  • 프롬프트 및 도구 사용에 대한 가시성을 제공합니다.
  • 실행 전에 위험 수준이 높은 명령 패턴을 차단합니다.
  • 개발자가 명확한 메시징을 사용하여 조직 정책을 이해할 수 있도록 지원합니다.

필수 조건

  • 셸 스크립팅에 대한 숙지(Bash 또는 PowerShell)
  • JSON 구성 파일에 대한 기본 이해
  • 부조종사 CLI가 사용되는 저장소에 액세스
  •         `jq` 설치됨(Bash 예제의 경우)
    

1. 조직 정책 정의

후크 스크립트를 작성하기 전에 자동으로 허용되는 작업과 사용자 검토가 필요한 작업을 결정합니다.

명확한 정책을 사용하면 위험을 줄이면서 과잉 차단을 방지할 수 있습니다.

항상 검토가 필요한 명령 식별

먼저 부조종사 CLI에서 자동 실행해서는 안 되는 패턴을 식별합니다. 일반적인 예는 다음과 같습니다.

  •         **권한 에스컬레이션**: `sudo`, `su``runas`
    
  •         **파괴적인 시스템 작업**: `rm -rf /`, `mkfs`, `dd``format`
    
  •         **다운로드 및 실행 패턴**: `curl ... | bash`, `wget ... | sh`, PowerShell `iex (irm ...)`
    

이러한 명령은 의도치 않게 실행되는 경우 되돌릴 수 없는 영향을 미칠 수 있습니다.

로깅할 내용 결정

후크를 사용하면 사용자가 제출한 프롬프트와 부조종사 CLI이 리포지토리에서 시도하는 실행 도구 등, 부조종사 CLI의 사용 방식에 대한 정보를 포착할 수 있습니다.

최소한 대부분의 조직에서는 다음을 기록합니다.

  • 타임스탬프 및 리포지토리 경로
  • 프롬프트 텍스트(또는 수정된 양식)
  • 도구 이름 및 도구 인수
  • 모든 정책 결정(예: 거부된 명령 및 그 이유)

비밀 또는 자격 증명을 로깅하지 않습니다. 프롬프트 또는 명령에 중요한 데이터가 포함될 수 있는 경우 로그를 작성하기 전에 수정을 적용합니다.

이 자습서에서는 간단한 설명 예제로 로컬 .github/hooks/logs 디렉터리를 사용합니다. 이러한 로그 파일은 리포지토리에 커밋되지 않으며 일반적으로 개발자의 컴퓨터에만 저장됩니다.

프로덕션 환경에서는 많은 조직에서 로컬로 로그를 작성하는 대신 중앙 집중식 로깅 또는 관찰 시스템에 후크 이벤트를 전달합니다. 이를 통해 팀은 리포지토리 및 사용자 간에 일관된 편집, 액세스 제어, 보존 정책 및 모니터링을 적용할 수 있습니다.

관련자와 일치

정책을 적용하기 전에 다음을 사용하여 검토합니다.

  • 보안 또는 규정 준수 팀, 위험 경계 확인
  • 더 광범위한 권한이 필요할 수 있는 플랫폼 또는 인프라 팀
  • 개발 팀은 차단되는 내용과 이유를 이해합니다.

명확한 기대치를 통해 정책 적용을 더 쉽게 채택하고 유지 관리할 수 있습니다.

2. 리포지토리 후크 파일 설정

이 자습서 전체에서는 리포지토리에 저장된 리포지토리 범위 후크를 사용합니다. 이 후크는 이 리포지토리 내에서 부조종사 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
      }
    ]
  }
}

이 구성이 수행하는 작업 이해

이 구성은 세 가지 후크를 설정합니다.

  •         `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

이 시점에서 부조종사 CLI은(는) 후크 스크립트를 아직 만들지 않았더라도 후크 구성을 검색할 수 있습니다.

3. 세션 시작 시 정책 배너 추가

          `sessionStart` 후크를 사용하여 새 부조종사 CLI 세션이 시작되거나 다시 시작될 때마다 배너를 표시합니다. 이렇게 하면 개발자에게 조직 정책이 활성 상태임을 분명히 할 수 있습니다.

          `sessionStart` 후크는 현재 작업 디렉터리 및 초기 프롬프트와 같은 컨텍스트 정보를 받습니다. 이 후크의 모든 출력은 부조종사 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. 감사에 대한 로그 프롬프트

사용자들이 부조종사 CLI에 프롬프트를 제출할 때, userPromptSubmitted 후크를 사용하여 기록합니다. 이 후크는 도구를 호출하기 전에 프롬프트가 전송될 때마다 실행됩니다.

후크는 타임스탬프, 현재 작업 디렉터리 및 전체 프롬프트 텍스트를 포함하는 구조화된 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

현재 이 리포지토리에서 감사용으로 기록되기 위해 제출된 프롬프트가 부조종사 CLI에 저장됩니다.

5. 다음을 사용하여 정책 적용 preToolUse

          `preToolUse` 후크를 사용하여 **실행하기 전에** 도구 호출을 평가합니다. 이 후크는 아무 작업도 수행하지 않고 실행을 허용하거나 구조적 응답을 반환하여 실행을 거부할 수 있습니다.

          `preToolUse` 입력 이해

후크 입력에는 다음이 preToolUse 포함됩니다.

  •         `toolName`: 부조종사 CLI이(가) 실행하려고 하는 도구(예: `bash`)입니다.
    
  •         `toolArgs`: 해당 도구의 인수를 포함하는 **JSON 문자열**
    
            `toolArgs` JSON 문자열이므로 스크립트는 다음과 같은 `command`필드를 읽기 전에 구문 분석해야 합니다.
    

중요

도구 인수 및 명령에는 API 토큰, 암호 또는 기타 자격 증명과 같은 중요한 정보가 포함될 수 있습니다. 이 데이터를 로깅하기 전에 수정을 적용하고 조직의 보안 정책을 따릅니다. 중요하지 않은 메타데이터(도구 이름, 타임스탬프, 정책 결정)만 로깅하고 적절한 액세스 제어 및 보존 정책을 사용하여 감사 이벤트를 중앙 집중식으로 보호된 로깅 시스템으로 전송하는 것이 좋습니다.

정책 스크립트 만들기

다음으로, 정책 스크립트를 만듭니다. 이 예제:

  • 시도된 모든 도구 사용을 기록합니다.
  • 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. 리포지토리에서 엔드투엔드 테스트

구성 파일 및 스크립트를 만든 후에는 이 리포지토리에서 부조종사 CLI를 사용할 때 후크가 예상대로 실행되는지 확인합니다.

후크 구성 파일의 유효성 검사

후크 구성 파일이 유효한 JSON인지 확인합니다.

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

스크립트 권한 확인(Unix 기반 시스템)

macOS 및 Linux에서 Bash 스크립트가 실행 가능한지 확인합니다.

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

기본 세션 실행

리포지토리에서 부조종사 CLI 새 세션을 시작합니다.

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

예상 결과:

  • 정책 배너(원본 sessionStart)가 표시됩니다.
  •         `.github/hooks/logs/audit.jsonl`에서 새로운 항목이 `userPromptSubmitted`에 추가됩니다.
    

트리거 도구 사용 및 로깅 확인

부조종사 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"

예상 결과:

  • 부조종사 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. 팀 전체에 안전하게 배포

단일 리포지토리에서 후크의 유효성을 검사한 후 개발 워크플로를 방해하지 않도록 점진적으로 배포합니다.

출시 전략 선택

일반적인 출시 방법은 다음과 같습니다.

  •         **로깅 우선 롤아웃(권장)**: 실행을 거부하지 않고 프롬프트 및 도구 사용을 로깅하여 시작합니다. 일정 기간 동안 로그를 검토한 다음 일반적인 사용 패턴을 이해하면 거부 규칙을 도입합니다.
    
  •         **팀별 롤아웃**: 한 번에 한 팀 또는 리포지토리에 후크를 배포하고, 피드백을 수집한 다음, 추가 팀으로 확장합니다.
    
  •         **위험 기반 롤아웃**: 중요한 시스템 또는 프로덕션 인프라를 처리하는 리포지토리로 시작한 다음, 위험 수준이 낮은 리포지토리로 확장합니다.
    

기대치 전달

거부 규칙을 적용하기 전에 개발자가 다음을 이해해야 합니다.

  • 해당 후크는 리포지토리에서 활성화됩니다.
  • 차단할 수 있는 명령 유형
  • 명령이 거부된 경우 진행하는 방법

명확한 통신은 혼동을 줄이고 요청을 지원합니다.

정책을 유지 관리할 수 있도록 유지

사용량이 발전함에 따라 다음을 수행합니다.

  • 버전 제어에 후크 구성 및 스크립트를 저장합니다.
  • 감사 로그를 주기적으로 검토하여 새 위험 패턴을 검색합니다.
  • 광범위한 일치 항목을 추가하는 대신 거부 규칙을 증분 방식으로 업데이트합니다.
  • 특히 영향이 큰 제한에 대해 각 거부 규칙이 존재하는 이유를 문서화합니다.

예외를 신중하게 처리

일부 팀(예: 인프라 또는 플랫폼 팀)에는 더 광범위한 권한이 필요할 수 있습니다. 이 작업을 안전하게 처리하려면 다음을 수행합니다.

  • 다른 리포지토리에 대해 별도의 후크 구성을 유지 관리합니다.
  • 예외를 좁고 잘 문서화된 상태로 유지합니다.
  • 감사 가능성을 저해하는 임시 로컬 바이패스를 방지합니다.

추가 읽기

후크 문제를 해결하려면 GitHub Copilot 에이전트와 훅 사용을 참조하세요.