claude-print/scripts/test_exact_claude_print_scenario.sh
jedarden ea162c09a3 fix(bf-2f5): correct timeout exit code from 3 to 124
The watchdog mechanism was complete but had an inconsistency:
main.rs used exit code 3 for timeout errors while ClaudePrintError::Timeout.exit_code()
returned 124 (GNU timeout convention). Now uses the proper exit code from the error type.

This ensures timeout errors exit with the standard code 124, matching GNU timeout
behavior and making error handling consistent for callers (marathon loop/NEEDLE).
2026-06-25 08:33:00 -04:00

132 lines
3.5 KiB
Bash
Executable file

#!/bin/bash
# Exact simulation of claude-print's scenario
# Creates temp dir with settings.json (Stop hook only), hook.sh, and FIFO
# Then runs child claude with --dangerously-skip-permissions and --settings=<temp>
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" >&2
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >&2
}
CLAUDE_BIN=$(which claude)
log_info "Using claude binary: $CLAUDE_BIN"
# Create temp dir exactly like claude-print does
TEMP_DIR=$(mktemp -d)
SETTINGS_FILE="$TEMP_DIR/settings.json"
HOOK_FILE="$TEMP_DIR/hook.sh"
FIFO_FILE="$TEMP_DIR/stop.fifo"
log_info "Created temp dir: $TEMP_DIR"
# Create hook.sh that writes to FIFO (exactly like claude-print)
cat > "$HOOK_FILE" << EOF
#!/bin/sh
cat > '$FIFO_FILE' 2>/dev/null || true
EOF
chmod +x "$HOOK_FILE"
# Create settings.json with Stop hook only (exactly like claude-print)
cat > "$SETTINGS_FILE" << EOF
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$HOOK_FILE",
"timeout": 10
}
]
}
]
}
}
EOF
# Create FIFO
mkfifo "$FIFO_FILE" 2>/dev/null || true
log_info "Created artifacts:"
log_info " - settings.json: $SETTINGS_FILE"
log_info " - hook.sh: $HOOK_FILE"
log_info " - stop.fifo: $FIFO_FILE"
cleanup() {
log_info "Cleaning up temp dir: $TEMP_DIR"
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
# Test in untrusted directory
cd /tmp
log_info "Test 1: WITH --settings (should hang based on original evidence)"
log_info "Running: $CLAUDE_BIN --dangerously-skip-permissions --settings=$SETTINGS_FILE -p 'test'"
# Run with timeout and capture ALL output
timeout 10s "$CLAUDE_BIN" --dangerously-skip-permissions --settings="$SETTINGS_FILE" -p "test" 2>&1 | tee /tmp/test1_output.txt || {
EXIT_CODE=$?
log_error "Test 1 exited with code: $EXIT_CODE"
if [ $EXIT_CODE -eq 124 ]; then
log_error "TIMEOUT - child produced no output within 10s"
fi
}
# Check if we got any output
if [ -s /tmp/test1_output.txt ]; then
log_info "Test 1 produced output:"
head -3 /tmp/test1_output.txt
else
log_error "Test 1 produced NO output (this is the bug!)"
fi
echo ""
log_info "Test 2: WITH --settings AND --setting-sources= (should work)"
log_info "Running: $CLAUDE_BIN --dangerously-skip-permissions --settings=$SETTINGS_FILE --setting-sources= -p 'test'"
timeout 10s "$CLAUDE_BIN" --dangerously-skip-permissions --settings="$SETTINGS_FILE" --setting-sources= -p "test" 2>&1 | tee /tmp/test2_output.txt || {
EXIT_CODE=$?
log_error "Test 2 exited with code: $EXIT_CODE"
if [ $EXIT_CODE -eq 124 ]; then
log_error "TIMEOUT - even with --setting-sources= it hung"
fi
}
# Check if we got any output
if [ -s /tmp/test2_output.txt ]; then
log_info "Test 2 produced output:"
head -3 /tmp/test2_output.txt
else
log_error "Test 2 produced NO output"
fi
# Summary
echo ""
log_info "=== SUMMARY ==="
if [ -s /tmp/test1_output.txt ]; then
log_info "Test 1 (with --settings): WORKED (produced output)"
else
log_error "Test 1 (with --settings): FAILED (no output - child hung)"
fi
if [ -s /tmp/test2_output.txt ]; then
log_info "Test 2 (with --settings --setting-sources=): WORKED (produced output)"
else
log_error "Test 2 (with --settings --setting-sources=): FAILED (no output)"
fi
log_info "Test complete"