두 가지 결과 구분하기
명시적 Deny와 Hook 자체 실행 실패를 구분하세요 — 도구 호출에 반대 결과를 가져옵니다.
Hook을 이벤트상의 프로그래밍 가능한 체크포인트로 생각하세요. PreToolUse는 명시적 거부를 반환할 수 있으며, 프로세스 충돌, 타임아웃, 파싱 불가 출력은 모두 fail-open으로 처리되어 도구 호출이 계속됩니다.
명시적 Deny와 Hook 자체 실행 실패를 구분하세요 — 도구 호출에 반대 결과를 가져옵니다.
matcher의 정확한 이름, 정규식 패턴, Bash 호환 별칭을 파악합니다.
사용자 가이드의 JSON 구조에 따라 명령 Hook을 구성하고 네 가지 장애 경로 테스트를 설계합니다.
SessionStart, SessionEnd, Stop, StopFailure, PreToolUse, PostToolUse, PostToolUseFailure, PermissionDenied. 이 중 PreToolUse만 is_blocking()이 true를 반환합니다.
UserPromptSubmit, Notification, SubagentStart, SubagentStop, 호환 별칭 SubagentEnd, PreCompact, PostCompact.
이벤트 열거형은 트리거 포인트를 정의하고, is_blocking()은 차단 능력을 별도로 선언합니다. 이벤트 목록을 읽을 때 결과가 호출자에게 어떻게 반환되는지도 함께 추적해야 합니다.
deny2allow, 종료 코드 2보안 함의: Hook은 정책 알림, 감사, 복구 가능한 사전 검사에 적합합니다. 강제 보장이 필요한 경우 권한 레이어와 샌드박스도 사용해야 합니다. 소스 코드 주석은 Hook 실패가 도구 가용성을 손상시켜서는 안 된다고 명시합니다.
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
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를 매칭할 수 있습니다. 매처는 정규식으로 컴파일되며, 사용자 가이드 예시는 도구명을 사용합니다.
{
"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의 제어를 받습니다. 예약된 환경 변수는 필터링되고, 확인되지 않은 변수는 시작 전 오류를 발생시킵니다.
제출물
구성, 스크립트, 테스트 로그
Bash를 매칭하는 PreToolUse 명령 Hook을 구성합니다.rm -rf에 대해 JSON deny를 반환하고 도구가 차단되는 결과를 기록합니다.Hook의 안전성을 판단하려면 두 가지를 먼저 물어보세요: 명시적 거부를 표현할 수 있는가, 그리고 Hook 자체가 실패할 때 메인 플로우는 어떻게 처리하는가? Grok Build의 답은 명확합니다 — 명시적 deny는 차단하고, Hook 실패는 fail-open입니다.
소스 스냅샷 설명: 이 페이지는 로컬 grok-build-main 스냅샷의 hooks crate, 사용자 가이드, 예시 구성을 기반으로 작성되었습니다. 코드 발췌는 교육 목적으로 로그 필드와 오류 래퍼가 생략되었습니다. 이벤트명, JSON 계층, 종료 코드, 결정 시맨틱은 소스 코드와 일치합니다.