#!/bin/bash set -euo pipefail # Brainy Gate Preflight # Refuses to let a test/build gate run on a machine that isn't clean enough # to trust the numbers it produces. See scripts/gate/README.md for why (the # 2026-08-13 lost-day ledger). # # Checks: 1-minute load average, any non-allowlisted process pinning a core, # the cpu0 scaling governor, and free space on / and /tmp. # # Exit 0 and print one OK line per passing check when the machine is clean. # Exit 1 and print one FATAL line per violation, naming the offender, when # it is not. # # Known trap: a helper function whose last executed statement is a `while` # (or any command whose own exit status happens to be nonzero) hands that # status back as the function's return value. Called as a plain statement, # that silently kills this script under `set -e`. Every helper below ends # on an explicit `return 0` as its own statement, never on a loop or test. # # The same failure mode hides in plainer-looking lines too: `var=$(cmd)` is # a bare assignment, so `set -e` DOES treat a nonzero `cmd` (or, under # `pipefail`, a nonzero stage anywhere in `cmd`'s pipeline) as a failure of # that statement and kills the script right there — even mid-loop, even # when the "failure" is routine (a process that exited before a second # lookup, a path that doesn't exist). Every such assignment below is paired # with an explicit `|| var=""` fallback so a routine miss degrades to an # empty value instead of an exit. VIOLATIONS=0 ANCESTOR_PIDS="" fatal() { echo "FATAL: $1" VIOLATIONS=$((VIOLATIONS + 1)) } ok() { echo "OK: $1" } # Walks this process's parent chain up to pid 1, then takes one snapshot of # its direct children (the ps/read pipeline in check_processes), and # records both in ANCESTOR_PIDS — so the process-scan below can recognize # its own tree (the shell/terminal/session that launched it, plus its own # helper commands) instead of flagging it. Children are captured once, up # front, rather than re-queried per row later, so a helper command that has # already exited by the time it's looked up can't be mistaken for a miss. build_ancestor_pids() { local pid="$$" local ppid child ANCESTOR_PIDS=" $pid " while [ "$pid" != "1" ]; do ppid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ') || ppid="" if [ -z "$ppid" ]; then break fi ANCESTOR_PIDS="${ANCESTOR_PIDS}${ppid} " pid="$ppid" done while IFS= read -r child; do [ -z "$child" ] && continue ANCESTOR_PIDS="${ANCESTOR_PIDS}${child} " done < <(ps --ppid "$$" -o pid= 2>/dev/null || true) return 0 } # (a) 1-minute load average vs. threshold (default: nproc / 2). check_load() { local max_load="${GATE_MAX_LOAD:-}" if [ -z "$max_load" ]; then max_load=$(( $(nproc) / 2 )) if [ "$max_load" -lt 1 ]; then max_load=1 fi fi local load_1m load_1m=$(cut -d' ' -f1 /proc/loadavg) if awk -v l="$load_1m" -v m="$max_load" 'BEGIN { exit !(l > m) }'; then fatal "1-minute load average ${load_1m} exceeds threshold ${max_load} (GATE_MAX_LOAD=${max_load})" else ok "1-minute load average ${load_1m} is within threshold ${max_load}" fi return 0 } # (b) any process outside the allowlist pinning more than half a core. # Parsed with `read` into named fields, not an awk/cut chain — a fixed-column # awk/cut split on `ps` output duplicated fields the first time this was # tried, because process args vary in word count. `read` with a fixed list # of variables dumps everything left over into the last one (args), which # handles that correctly. check_processes() { local max_pcpu=50 local extra_regex="${GATE_ALLOW_REGEX:-}" local violation_found=0 local line pcpu pid args pcpu_int while IFS= read -r line; do [ -z "$line" ] && continue read -r pcpu pid args <<< "$line" # Kernel threads report their comm in brackets, e.g. "[kworker/0:1]". case "$args" in \[*\]) continue ;; esac # This script's own tree: its ancestors (shell, terminal, session) and # its direct children, both captured once by build_ancestor_pids. case " $ANCESTOR_PIDS " in *" $pid "*) continue ;; esac case "$args" in *sshd*|*systemd*) continue ;; esac if [ -n "$extra_regex" ] && [[ "$args" =~ $extra_regex ]]; then continue fi pcpu_int="${pcpu%.*}" if [ -z "$pcpu_int" ]; then pcpu_int=0 fi if [ "$pcpu_int" -gt "$max_pcpu" ]; then fatal "pid ${pid} ('${args}') is using ${pcpu}% of one core" violation_found=1 fi done < <(ps -eo pcpu,pid,args --sort=-pcpu | tail -n +2) if [ "$violation_found" -eq 0 ]; then ok "no process outside the allowlist exceeds ${max_pcpu}% of one core" fi return 0 } # (c) cpu0 scaling governor must be "performance". Skipped with a warning # (not a violation) when the sysfs path doesn't exist on this machine. check_governor() { local gov_path="/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" if [ ! -r "$gov_path" ]; then echo "WARNING: ${gov_path} not present; skipping governor check" return 0 fi local governor governor=$(cat "$gov_path" 2>/dev/null) || governor="" if [ "$governor" != "performance" ]; then fatal "cpu0 governor is '${governor}', not 'performance'" else ok "cpu0 governor is 'performance'" fi return 0 } # (d) free-space floors on / and /tmp (default 10G each). Skip entirely via # GATE_SKIP_DISK_CHECK=1. check_disk() { if [ "${GATE_SKIP_DISK_CHECK:-0}" = "1" ]; then echo "WARNING: disk free-space check skipped (GATE_SKIP_DISK_CHECK=1)" return 0 fi local floor_gb=10 local floor_bytes=$((floor_gb * 1024 * 1024 * 1024)) local path avail_bytes avail_gb for path in / /tmp; do avail_bytes=$(df --output=avail -B1 "$path" 2>/dev/null | tail -n 1 | tr -d ' ') || avail_bytes="" if [ -z "$avail_bytes" ]; then echo "WARNING: could not determine free space on ${path}; skipping" continue fi if [ "$avail_bytes" -lt "$floor_bytes" ]; then avail_gb=$((avail_bytes / 1024 / 1024 / 1024)) fatal "${path} has only ${avail_gb}G free, below the ${floor_gb}G floor" else ok "${path} has enough free space (floor ${floor_gb}G)" fi done return 0 } echo "Brainy gate preflight" echo "----------------------" build_ancestor_pids check_load check_processes check_governor check_disk echo "----------------------" if [ "$VIOLATIONS" -gt 0 ]; then echo "FATAL: gate preflight failed with ${VIOLATIONS} violation(s) — machine is not gate-clean" exit 1 fi echo "gate preflight passed — machine is gate-clean" exit 0