Grok Build Source Course · 12 / 19

Hooks: 명시적 deny만 차단합니다

Hook을 이벤트상의 프로그래밍 가능한 체크포인트로 생각하세요. PreToolUse는 명시적 거부를 반환할 수 있으며, 프로세스 충돌, 타임아웃, 파싱 불가 출력은 모두 fail-open으로 처리되어 도구 호출이 계속됩니다.

15개 이벤트명PreToolUse 차단 가능JSON 구성프로세스 stdin / stdout
01 / OBJECTIVES

학습 목표

두 가지 결과 구분하기

명시적 Deny와 Hook 자체 실행 실패를 구분하세요 — 도구 호출에 반대 결과를 가져옵니다.

이벤트 매칭 이해하기

matcher의 정확한 이름, 정규식 패턴, Bash 호환 별칭을 파악합니다.

테스트 가능한 구성 작성하기

사용자 가이드의 JSON 구조에 따라 명령 Hook을 구성하고 네 가지 장애 경로 테스트를 설계합니다.

02 / CORE VISUAL

PreToolUse 단일 결정 경로

03 / EVENTS

소스 코드의 이벤트 표면

세션 및 도구

8개 메인 플로우 체크포인트

SessionStart, SessionEnd, Stop, StopFailure, PreToolUse, PostToolUse, PostToolUseFailure, PermissionDenied. 이 중 PreToolUseis_blocking()이 true를 반환합니다.

사용자, 에이전트 및 압축

7개 확장 체크포인트

UserPromptSubmit, Notification, SubagentStart, SubagentStop, 호환 별칭 SubagentEnd, PreCompact, PostCompact.

핵심 경계

"이벤트 트리거" ≠ "메인 플로우 제어"

이벤트 열거형은 트리거 포인트를 정의하고, is_blocking()은 차단 능력을 별도로 선언합니다. 이벤트 목록을 읽을 때 결과가 호출자에게 어떻게 반환되는지도 함께 추적해야 합니다.

crates/codegen/xai-grok-hooks/src/event.rs
04 / SEMANTICS

차단 vs. fail-open 매트릭스

Hook 결과
dispatcher 해석
도구 호출
JSON decision = deny
명시적 거부
차단
유효한 JSON 없음, 종료 코드 2
폴백 거부
차단
유효한 JSON allow, 종료 코드 2
JSON 우선
허용, 충돌 경고 기록
종료 코드 0도 2도 아님
HookRunResult::Failed
허용, 경고 기록
타임아웃 또는 프로세스 충돌
HookRunResult::Failed
허용, 경고 기록
stdout 무효 또는 decision 알 수 없음
폴백 종료 코드 또는 Failed
출력 자체는 차단하지 않음; 폴백 종료 코드 2는 여전히 거부

보안 함의: Hook은 정책 알림, 감사, 복구 가능한 사전 검사에 적합합니다. 강제 보장이 필요한 경우 권한 레이어와 샌드박스도 사용해야 합니다. 소스 코드 주석은 Hook 실패가 도구 가용성을 손상시켜서는 안 된다고 명시합니다.

05 / SOURCE

실제 소스 코드 증거

dispatcher.rs

실패 시 기본적으로 허용

match result {
    HookRunnerResult::Decision(
        HookDecision::Deny { reason, .. }
    ) => {
        return PreToolUseResult {
            decision: HookDecision::Deny { ... },
            results: run_results,
        };
    }
    HookRunnerResult::Failed(err) => {
        tracing::warn!(
            error = %err,
            "hook failed; ignoring (fail-open)"
        );
    }
    _ => {}
}
crates/codegen/xai-grok-hooks/src/dispatcher.rs
matcher.rs + command.rs

매칭과 종료 코드

pub const DENY_EXIT_CODE: i32 = 2;

pub fn matches(&self, tool_name: &str) -> bool {
    self.regex.is_match(tool_name)
        || self.matches_compat_alias(tool_name)
}

호환 매핑을 통해 구성의 Bash가 내부 도구명 run_terminal_command를 매칭할 수 있습니다. 매처는 정규식으로 컴파일되며, 사용자 가이드 예시는 도구명을 사용합니다.

crates/codegen/xai-grok-hooks/src/matcher.rs · runner/command.rs
06 / CONFIG

실제 JSON 구조로 구성 작성하기

~/.grok/hooks/*.json · project/.grok/hooks/*.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bin/safe-shell-guard.sh",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

구성 계층은 "이벤트 → matcher 그룹 → 핸들러 목록"입니다. 명령은 stdin을 통해 이벤트 봉투를 수신합니다. 유효한 JSON 결정이 우선하며, 유효한 JSON이 없으면 종료 코드로 해석하고 종료 코드 2는 거부를 의미합니다. 전역 Hook은 ~/.grok/hooks/에, 프로젝트 Hook은 .grok/hooks/에 위치하며 folder trust의 제어를 받습니다. 예약된 환경 변수는 필터링되고, 확인되지 않은 변수는 시작 전 오류를 발생시킵니다.

crates/codegen/xai-grok-hooks/examples/hooks/safe-shell.json · xai-grok-pager/docs/user-guide/10-hooks.md
07 / LAB

실습: 네 가지 경로 검증하기

25 MIN

제출물
구성, 스크립트, 테스트 로그

  1. Bash를 매칭하는 PreToolUse 명령 Hook을 구성합니다.
  2. 스크립트가 rm -rf에 대해 JSON deny를 반환하고 도구가 차단되는 결과를 기록합니다.
  3. 종료 코드 1, 타임아웃, 무효 stdout을 순서대로 발생시켜 세 경우 모두 허용되고 경고가 생성되는지 검증합니다.
  4. 종료 코드를 2로 변경하고, 무효 stdout 상황에서도 명시적 거부 경로를 통과할 수 있는지 검증합니다.
  5. 경계 설명 한 문장 작성: 어떤 정책은 권한 레이어 또는 샌드박스로 이동해야 하는지.
핵심 정리

Hook의 안전성을 판단하려면 두 가지를 먼저 물어보세요: 명시적 거부를 표현할 수 있는가, 그리고 Hook 자체가 실패할 때 메인 플로우는 어떻게 처리하는가? Grok Build의 답은 명확합니다 — 명시적 deny는 차단하고, Hook 실패는 fail-open입니다.

소스 스냅샷 설명: 이 페이지는 로컬 grok-build-main 스냅샷의 hooks crate, 사용자 가이드, 예시 구성을 기반으로 작성되었습니다. 코드 발췌는 교육 목적으로 로그 필드와 오류 래퍼가 생략되었습니다. 이벤트명, JSON 계층, 종료 코드, 결정 시맨틱은 소스 코드와 일치합니다.