Files
claudetools/.claude/hooks/block-tmp-path.sh
Mike Swanson 2937b00ebf sync: auto-sync from GURU-5070 at 2026-07-01 15:49:56
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-07-01 15:49:56
2026-07-01 15:50:54 -07:00

56 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# PreToolUse(Bash) hook: block bash commands that WRITE files under /tmp on
# Windows (Git Bash / MSYS).
#
# Why: MSYS bash and the harness's other tools (Write, Python via py launcher)
# resolve /tmp to DIFFERENT real directories on Windows, so a file curl/tee
# writes to /tmp cannot be read back by the next tool call — the single most
# repeated tmp-path friction in errorlog.md (ref=feedback_tmp_path_windows,
# 6+ hits; also breaks run_in_background shells where TMPDIR is unset).
#
# Windows-only: exits 0 immediately on macOS/Linux where /tmp is one real dir.
# Only WRITE patterns are blocked (redirects, tee, -o/--output, cp/mv/mktemp
# targets). Reads (ls/cat/rm /tmp/...) pass.
#
# Dual-driver like block-backslash-winpath.sh: handles Claude (tool_input) and
# Grok (toolInput) event shapes; emits Grok decision JSON when denying there.
case "$(uname -s 2>/dev/null)" in
MINGW*|MSYS*|CYGWIN*) ;; # Windows Git-bash: the mismatch exists — check
*) exit 0 ;; # real /tmp elsewhere: nothing to protect
esac
input=$(cat)
cmd=$(echo "$input" | jq -r '(.toolInput // .tool_input // {}) | .command // ""' 2>/dev/null || python -c "
import sys, json
try:
d = json.load(sys.stdin)
ti = d.get('toolInput') or d.get('tool_input') or {}
print(ti.get('command', ''))
except:
print('')
" 2>/dev/null || echo '')
is_grok=$(echo "$input" | jq -r 'if has("hookEventName") or has("toolInput") then "1" else "0" end' 2>/dev/null || echo '0')
# Strip quoted substrings so a /tmp mention inside a string (commit message,
# grep pattern) does not false-trigger; real write targets sit outside quotes.
bare=$(printf '%s' "$cmd" | sed -E "s/'[^']*'//g; s/\"[^\"]*\"//g")
if printf '%s' "$bare" | grep -qE '(>>?[[:space:]]*/tmp/|[[:space:]]tee[[:space:]]+(-a[[:space:]]+)?/tmp/|(^|[[:space:]])-o[[:space:]]*/tmp/|--output(=|[[:space:]]+)/tmp/|(^|[[:space:]]|;|\|)(cp|mv)[[:space:]][^|;&>]*[[:space:]]/tmp/|mktemp[[:space:]]+(-d[[:space:]]+)?/tmp/)'; then
reason="Blocked write to /tmp in bash on Windows: MSYS /tmp and the Write/Python tools' /tmp are DIFFERENT directories — the file cannot be read back by the next tool call."
echo "BLOCKED: do not write files under /tmp on Windows (Git Bash)."
echo ""
echo "MSYS bash and the harness's other tools resolve /tmp to different real"
echo "directories, so the next tool call cannot read what you just wrote"
echo "(ref: feedback_tmp_path_windows). Use one of these instead:"
echo " - repo-relative scratch: curl -o ./.x.json ... (gitignored .tmp-* also works)"
echo " - the session scratchpad dir (absolute path, shared by all tools)"
echo " - pipe directly: curl ... | jq ... (no intermediate file)"
if [ "$is_grok" = "1" ]; then
printf '{"decision":"deny","reason":"%s"}\n' "$reason"
fi
exit 2
fi
exit 0