#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" HOOK_UNDER_TEST="$REPO_ROOT/hooks/session-start-codex" EXAMPLE_UNDER_TEST="$REPO_ROOT/hooks/hooks-codex.json.example" FAILURES=0 pass() { echo " [PASS] $1" } fail() { echo " [FAIL] $1" FAILURES=$((FAILURES + 1)) } # run_hook — echoes hook stdout; fails the calling test on # non-zero exit. env -i mirrors the codex hook executor's clean environment. run_hook() { printf '%s' "$1" | env -i PATH="${PATH:-}" bash "$HOOK_UNDER_TEST" } echo "Codex SessionStart hook tests" startup_payload='{"session_id":"s","hook_event_name":"SessionStart","model":"gpt-5.6-terra","source":"startup"}' if output="$(run_hook "$startup_payload")" && [ -z "$output" ]; then pass "source=startup emits nothing and exits 0" else fail "source=startup emits nothing and exits 0" printf '%s\n' "$output" | head -3 | sed 's/^/ /' fi compact_payload='{"session_id":"s","hook_event_name":"SessionStart","model":"gpt-5.6-terra","source":"compact"}' if output="$(run_hook "$compact_payload")"; then ok=1 for needle in \ "" \ "You have superpowers." \ "name: using-superpowers" \ "" \ "subagent-driven-development/SKILL.md" \ "references/codex-tools.md"; do if [[ "$output" != *"$needle"* ]]; then ok=0 echo " missing: $needle" fi done if [ "$ok" -eq 1 ]; then pass "source=compact emits bootstrap plus re-read addendum" else fail "source=compact emits bootstrap plus re-read addendum" fi else fail "source=compact emits bootstrap plus re-read addendum (hook exited non-zero)" fi # Whitespace-tolerant source matching (serializers vary). spaced_payload='{"hook_event_name":"SessionStart", "source" : "compact"}' if output="$(run_hook "$spaced_payload")" && [[ "$output" == *""* ]]; then pass "whitespace around the source key still triggers injection" else fail "whitespace around the source key still triggers injection" fi if output="$(printf '' | env -i PATH="${PATH:-}" bash "$HOOK_UNDER_TEST")" && [ -z "$output" ]; then pass "empty stdin fails open to no output, exit 0" else fail "empty stdin fails open to no output, exit 0" fi if output="$(run_hook 'not json at all {{{')" && [ -z "$output" ]; then pass "garbage stdin fails open to no output, exit 0" else fail "garbage stdin fails open to no output, exit 0" fi # A compact mention inside some other field must not trigger injection. decoy_payload='{"hook_event_name":"SessionStart","source":"startup","cwd":"/tmp/compact"}' if output="$(run_hook "$decoy_payload")" && [ -z "$output" ]; then pass "compact appearing outside the source field does not trigger" else fail "compact appearing outside the source field does not trigger" fi if node -e ' const example = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")); const entry = example.hooks.SessionStart[0].hooks[0]; if (entry.type !== "command") { console.error(`example hook type is ${JSON.stringify(entry.type)}, expected "command"`); process.exit(1); } if (!/session-start-codex"$/.test(entry.command)) { console.error(`unexpected example command shape: ${entry.command}`); process.exit(1); } ' "$EXAMPLE_UNDER_TEST"; then pass "hooks-codex.json.example parses and invokes session-start-codex" else fail "hooks-codex.json.example parses and invokes session-start-codex" fi if [[ "$FAILURES" -gt 0 ]]; then echo "STATUS: FAILED ($FAILURES failure(s))" exit 1 fi echo "STATUS: PASSED"