53 lines
4.4 KiB
Bash
Executable file
53 lines
4.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# The self-matching process-pattern class (6 October 2026). Three times in one day a script matched its own shell:
|
|
# the shipper's recovery at 16:1xZ, the fleet's wave script at 16:25Z (`pgrep -f igneumd-0313 || start the node` matched
|
|
# the launching shell's command line, which carried the file name, so no wave pod ever started its node and 38 cards
|
|
# hashed against nothing for an hour), and the fleet's Devnet 2 kill step at 17:18Z (`pkill -f '^bash in/box-dn2.sh'`
|
|
# inside a file the same script called killed the caller). Rule: a `pgrep -f`, `pkill -f` or `ps ... | grep` whose
|
|
# pattern is a literal word matches every process whose command line carries that word, including the shell that
|
|
# runs the pattern and any ssh command that carries the script's text; the pattern must therefore exclude itself:
|
|
# anchored to the executable's path (`'^/opt/igneum/pkg/bin/igneumd'`), the bracket form (`'[i]gneumd'`), or
|
|
# `pgrep -x <name>` / `pkill -x <name>` on the binary name (15 characters at most). This check fails CI when a script
|
|
# under tools/, relay/playbooks/, infra/ or packaging/ runs pgrep -f / pkill -f with a bare literal pattern (no `^`,
|
|
# no bracket, no `$`), or pipes `ps` into `grep <word>` without a bracket or a `grep -v grep`.
|
|
# With file arguments it checks those files only; --self-test runs the two fixtures.
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/../.."
|
|
fail=0
|
|
bad_pattern() { # the pattern text between the quotes after -f; prints 1 when it is a bare literal
|
|
local p="$1"
|
|
[[ "$p" == ^* || "$p" == *'['* || "$p" == *'$' || "$p" == '$'* ]] && return 1
|
|
return 0
|
|
}
|
|
check_file() {
|
|
local f="$1" n=0
|
|
while IFS= read -r line; do
|
|
n=$((n + 1))
|
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
# pgrep -f / pkill -f with a quoted or bare pattern
|
|
while read -r pat; do
|
|
[ -z "$pat" ] && continue
|
|
if bad_pattern "$pat"; then echo "pgrep-self-match: $f:$n: p(grep|kill) -f with the bare pattern '$pat' matches the shell that runs it; anchor it (^/path), bracket it ([x]rest) or use -x"; fail=1; fi
|
|
done < <(printf '%s\n' "$line" | grep -oE "p(grep|kill)( -[0-9A-Za-z]+)* -f(a|c|l)? +(\"[^\"]*\"|'[^']*'|[^ |;)]+)" | sed -E "s/^p(grep|kill)( -[0-9A-Za-z]+)* -f[acl]* +//; s/^[\"']//; s/[\"']$//")
|
|
# ps | grep word
|
|
if printf '%s\n' "$line" | grep -qE 'ps [^|]*\| *grep ' && ! printf '%s\n' "$line" | grep -qE "grep +(-[a-zA-Z]+ +)*['\"]?\[" && ! printf '%s\n' "$line" | grep -q 'grep -v grep'; then
|
|
echo "pgrep-self-match: $f:$n: ps | grep without a bracket pattern or 'grep -v grep' matches the grep itself"; fail=1
|
|
fi
|
|
done < "$f"
|
|
}
|
|
if [ "${1:-}" = "--self-test" ]; then
|
|
t="$(mktemp -d)"
|
|
printf 'pgrep -f igneumd-0313 >/dev/null || start\npkill -f "bash in/box-x.sh"\nps aux | grep igneumd\n' > "$t/bad.sh"
|
|
printf "pgrep -f '^/opt/igneum/pkg/bin/igneumd' || start\npkill -x igneum-miner\npkill -f '[i]gneumd-0313'\nps aux | grep '[i]gneumd'\nps -eo cmd | grep igneumd | grep -v grep\n" > "$t/good.sh"
|
|
fail=0; check_file "$t/bad.sh"; [ "$fail" = 1 ] || { echo "pgrep-self-match: self-test FAILED: the bad fixture passed"; exit 1; }
|
|
fail=0; check_file "$t/good.sh"; [ "$fail" = 0 ] || { echo "pgrep-self-match: self-test FAILED: the good fixture was flagged"; exit 1; }
|
|
echo "pgrep-self-match: self-test ok (the bad fixture fails, the good one passes)"; exit 0
|
|
fi
|
|
# Owed, not exempt: the PC 2 playbooks of 5 and 6 October use `pkill -f sp1-gpu-server` (the prover-socket check's own
|
|
# required line) inside a WSL `bash -c` whose command line carries the word, so the pkill kills that shell too when it
|
|
# runs first; they are finished measurements and get `pkill -x sp1-gpu-server` when next touched (tools/ci/README.md).
|
|
ALLOW='^(tools/prover-floor/pc2-.*\.ps1|tools/proving-v1/pc2-.*\.ps1|tools/repo/fresh-repo\.sh|tools/observer/autosync\.sh|infra/devnet/restart\-hand\-nodes\.sh|infra/seed\-nodes/addpeer\-from\-mac\.sh|relay/playbooks/shard\-test\.ps1|tools/ci/fixtures/bash\-body\-ok\.ps1|tools/ci/pgrep\-self\-match\-check\.sh|tools/ci/prover\-socket\-check\.sh|tools/exec\-attacks/net\.sh)$'
|
|
list_files() { if [ $# -gt 0 ]; then printf '%s\n' "$@"; else git ls-files 'tools/**' 'relay/playbooks/**' 'infra/**' 'packaging/**' | grep -E '\.(sh|bash|ps1|mjs|py)$'; fi; }
|
|
while IFS= read -r f; do [ -f "$f" ] || continue; [[ "$f" =~ $ALLOW ]] && continue; check_file "$f"; done < <(list_files "$@")
|
|
[ "$fail" = 0 ] && echo "pgrep-self-match: no script matches its own shell"
|
|
exit $fail
|