Files
actual/scripts/agent-hooks/github-comment-style.sh
T
Matiss Janis AboltinsandClaude Fable 5 da8eb79539 [AI] Fail agent hooks with an actionable error when jq is missing (#8651)
* [AI] Fail agent hooks with an actionable error when jq is missing

The shared agent-hook scripts all parse their payload with jq but never
checked it exists. A missing jq made git-guard.sh block every Bash call
with a misleading 'could not parse the hook payload' message, while other
hooks silently failed open and skipped their checks (issue #8629).

Add require_jq to common.sh — called by every hook before its first jq
use — so a missing jq fails closed with a clear install message, distinct
from a malformed-payload error. The script name in the message is derived
from $0 rather than passed by each caller. The Cursor adapters emit a
static JSON deny (their deny() helper itself needs jq to build JSON) or
an advisory where blocking isn't possible, and AGENTS.md now documents
the prerequisite.

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Address review: advisory wording for PostToolUse hooks, hook tests

PostToolUse hooks (format-edited-file, prefer-one-component) run after the
edit already happened, so a missing jq now reports 'Agent hook skipped'
instead of claiming a block. Exit 2 stays: it is the only exit code that
feeds stderr back to the agent. Add scripts/agent-hooks/test-hooks.sh, a
standalone runnable check covering the missing-jq path for every hook plus
malformed-JSON, missing-field, and guard-behavior cases, and soften the
release-note verb.

Co-Authored-By: Claude Fable 5 <[email protected]>

* [AI] Remove standalone hook test script

Not wired into CI, so it only served as a manual check; the hook behavior
was verified by hand and the script isn't worth maintaining.

Co-Authored-By: Claude Fable 5 <[email protected]>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-08-06 06:52:52 +00:00

57 lines
2.5 KiB
Bash
Executable File

#!/bin/sh
# Shared agent guard for GitHub comments / reviews / issues, wired for Claude
# (PreToolUse), Codex (PreToolUse) and Cursor (beforeMCPExecution via adapter).
#
# Every comment, review or issue an agent posts to GitHub must be prefixed with
# the robot emoji 🤖, so agent-authored content is always visibly marked. Reads
# the text from `.tool_input.body` (and `.tool_input.title` for issues) on
# stdin; each non-empty field must start with 🤖 (after any leading whitespace),
# otherwise the call is blocked (exit 2 + stderr) so the agent fixes it.
#
# This only ever runs on the agent's own outgoing comments — bots like CodeRabbit
# post under their own identity and never pass through this hook.
block() {
echo "$1" >&2
exit 2
}
# A missing jq gets its own actionable block, distinct from the
# malformed-payload block below.
. "$(dirname "$0")/common.sh"
require_jq
input=$(cat)
# 🤖 = U+1F916, UTF-8 F0 9F A4 96. Build it from raw bytes so the prefix check is
# locale- and file-encoding-independent.
robot=$(printf '\360\237\244\226')
# Fail closed on a malformed payload — invalid JSON, or a missing/non-object
# `.tool_input` — matching git-guard.sh / guard-shell.sh, so a payload we can't
# read can't silently bypass the prefix check. A genuinely absent body/title
# within a valid `.tool_input` is fine (nothing to mark).
fields=$(printf '%s' "$input" | jq -e '.tool_input | objects' 2>/dev/null) ||
block "Blocked: could not read the hook payload (.tool_input). (scripts/agent-hooks/github-comment-style.sh)"
body=$(printf '%s' "$fields" | jq -r '.body // empty')
title=$(printf '%s' "$fields" | jq -r '.title // empty')
# A field passes if it's empty/whitespace-only (nothing to mark) or, after
# stripping leading whitespace, begins with the robot emoji.
starts_with_robot() {
# ${1%%[![:space:]]*} is the leading whitespace; strip it off the front. A
# whitespace-only (or empty) field strips down to "" and passes too.
trimmed=${1#"${1%%[![:space:]]*}"}
case "$trimmed" in
"" | "$robot"*) return 0 ;;
*) return 1 ;;
esac
}
starts_with_robot "$title" ||
block "Blocked: GitHub issue titles must start with the robot emoji 🤖 to mark them as agent-authored. Prefix the title with 🤖 and try again. (scripts/agent-hooks/github-comment-style.sh)"
starts_with_robot "$body" ||
block "Blocked: GitHub comments, reviews and issues must start with the robot emoji 🤖 to mark them as agent-authored. Prefix the body with 🤖 and try again. (scripts/agent-hooks/github-comment-style.sh)"
exit 0