#!/usr/bin/env bash set -uo pipefail # CASAN H6/H7 — Kill-switch (Incident response · C7 / V23). # # A scoped emergency stop: engage a switch for a project / model / provider and # any gate that honors it refuses to run further work in that scope. Engaging is # recorded; clearing requires an explicit reason (production: reviewer approval). # # Usage: # kill-switch.sh engage [reason] # turn the switch ON # kill-switch.sh clear [reason] # turn it OFF (audited) # kill-switch.sh check # exit 2 if engaged, 0 if clear # kill-switch.sh status # list engaged switches # scope ∈ {project, model, provider, global}. A `global` switch stops everything. # Env: CASAN_KILLSWITCH_DIR (default .specify/logs/level5/kill-switch) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" KS_DIR="${CASAN_KILLSWITCH_DIR:-$PROJECT_ROOT/.specify/logs/level5/kill-switch}" mkdir -p "$KS_DIR" CMD="${1:-}"; SCOPE="${2:-}"; ID="${3:-}"; REASON="${4:-unspecified}" ts() { date -u +"%Y-%m-%dT%H:%M:%SZ"; } safe() { printf '%s' "$1" | tr '/ :' '___'; } case "$CMD" in engage) [[ -n "$SCOPE" && -n "$ID" ]] || { echo "usage: kill-switch.sh engage [reason]" >&2; exit 64; } f="$KS_DIR/$(safe "$SCOPE")-$(safe "$ID").on" printf '{"scope":"%s","id":"%s","reason":"%s","engaged_at":"%s","actor":"%s"}\n' \ "$SCOPE" "$ID" "$REASON" "$(ts)" "${CASAN_ACTOR:-system}" > "$f" echo "KILL_SWITCH_ENGAGED scope=$SCOPE id=$ID reason=$REASON" ;; clear) [[ -n "$SCOPE" && -n "$ID" ]] || { echo "usage: kill-switch.sh clear [reason]" >&2; exit 64; } f="$KS_DIR/$(safe "$SCOPE")-$(safe "$ID").on" if [[ -f "$f" ]]; then printf '%s cleared_by=%s reason=%s at=%s\n' "$(cat "$f")" "${CASAN_ACTOR:-system}" "$REASON" "$(ts)" \ >> "$KS_DIR/kill-switch-history.log" rm -f "$f" echo "KILL_SWITCH_CLEARED scope=$SCOPE id=$ID" else echo "KILL_SWITCH_NOT_ENGAGED scope=$SCOPE id=$ID" fi ;; check) [[ -n "$SCOPE" && -n "$ID" ]] || { echo "usage: kill-switch.sh check " >&2; exit 64; } # A global switch, or a switch for this exact scope/id, blocks. if [[ -f "$KS_DIR/global-all.on" ]]; then echo "KILL_SWITCH_ACTIVE scope=global" >&2; exit 2 fi if [[ -f "$KS_DIR/$(safe "$SCOPE")-$(safe "$ID").on" ]]; then echo "KILL_SWITCH_ACTIVE scope=$SCOPE id=$ID" >&2; exit 2 fi echo "KILL_SWITCH_CLEAR scope=$SCOPE id=$ID"; exit 0 ;; status) n=0 for f in "$KS_DIR"/*.on; do [[ -e "$f" ]] || continue; cat "$f"; n=$((n+1)); done echo "KILL_SWITCH_STATUS engaged=$n" ;; *) echo "Usage: kill-switch.sh {engage|clear|check|status} [reason]" >&2 exit 64 ;; esac