#!/usr/bin/env bash # No inline deletion inside a `bash -c` or `sh -c` string (main, 7 October 2026 21:33 BST: the desktop app asked the founder to # approve lanes' shell commands that carried `rm` inside an inline bash -c '...' string, "runs rm and could not be checked"). # Rule: never an inline `rm`, `rm -rf`, `find ... -delete` or a redirect-truncate (`: > file`, `> file` on its own) inside a # `bash -c` / `sh -c` string in a tracked script; put the script in a file under tools/ (or the lane's scratch directory) and run it # by path; on the boxes, deletions go through the lease or job tooling, which the checker reads as a plain command. # This check greps every tracked shell, PowerShell and JS/MJS script for a bash -c / sh -c string that carries one of those. Known # failures named with file and line. --self-test first: four banned shapes fail, four allowed shapes pass. set -uo pipefail cd "$(git rev-parse --show-toplevel)" # a line that opens an inline shell string (bash -c, sh -c, "bash", "-c" in a PowerShell or JS argument list) and, on the same # line, a deletion word inside it BANNED='((bash|sh|pwsh|powershell)(\.exe)? +-l?c +["'"'"'][^"'"'"']*|"-c", *["'"'"'][^"'"'"']*)(\brm +|\brm$|find [^"'"'"']*-delete|(^|[ ;&|]): *> *[^ ]|[ ;&|]> *([A-Za-z._$]|/[a-ce-z]|/d[a-df-z])[^ ]* *([;&|]|$))' scan() { # : prints "file:line: text" for each hit grep -n -H -E "$BANNED" "$@" 2>/dev/null | grep -v -E '^[^:]*:[0-9]+:\s*#' || true } if [ "${1:-}" = --self-test ]; then t=$(mktemp -d); trap 'rm -rf "$t"' EXIT; fail=0 printf '%s\n' 'ssh box "bash -c '"'"'cd /tmp && rm -rf /tmp/x'"'"'"' > "$t/b1.sh" printf '%s\n' 'sh -c "find /srv/x -name y -delete"' > "$t/b2.sh" printf '%s\n' 'bash -c '"'"': > /srv/builds/_locks/quiet'"'"'' > "$t/b3.sh" printf '%s\n' 'Start-Process bash -ArgumentList "-c", "rm /tmp/old.log; echo ok"' > "$t/b4.ps1" printf '%s\n' 'bash tools/ci/clean-scratch.sh /tmp/x' > "$t/a1.sh" printf '%s\n' 'rm -rf "$t" # a plain command, the checker reads it' > "$t/a2.sh" printf '%s\n' 'ssh box "bash -c '"'"'ls /srv/x && echo done'"'"'"' > "$t/a3.sh" printf '%s\n' '# bash -c "rm -rf x" is banned (a comment names the rule)' > "$t/a4.sh" for f in b1.sh b2.sh b3.sh b4.ps1; do [ -n "$(scan "$t/$f")" ] || { echo "inline-rm self-test: FAIL: banned shape $f passed"; fail=1; }; done for f in a1.sh a2.sh a3.sh a4.sh; do [ -z "$(scan "$t/$f")" ] || { echo "inline-rm self-test: FAIL: allowed shape $f was flagged: $(scan "$t/$f")"; fail=1; }; done [ "$fail" = 0 ] && echo "inline-rm self-test: 4 banned shapes fail (rm, find -delete, truncate, PowerShell -c list), 4 allowed shapes pass (script by path, plain rm, no deletion, a comment)" [ "$fail" = 0 ] || exit 1 fi # allowed for now, named: the proving lane's WSL socket clean-up (tools/proving-v1, three lines of `bash -c 'pkill ...; rm -f /tmp/sp1-cuda-*.sock'` # run inside WSL on a PC by a job, not from a Mac shell); the lane moves it into a file under tools/proving-v1 and the lines leave this list ALLOW='^tools/proving-v1/(pc2-agg-cost(-restore)?|pc2-segments)\.ps1:' hits="" while IFS= read -r f; do [ -n "$f" ] || continue h=$(scan "$f" | grep -v -E "$ALLOW" || true) [ -n "$h" ] && hits="${hits}${h}"$'\n' done < <(git ls-files -- '*.sh' '*.bash' '*.ps1' '*.mjs' '*.js' '*.yml' '*.yaml' | grep -v -E '^tools/ci/inline-rm-check\.sh$') hits=$(printf '%s' "$hits" | sed '/^$/d') if [ -n "$hits" ]; then echo "inline-rm: a deletion inside an inline bash -c / sh -c string (put the script in a file and run it by path; on a box use the lease or job tooling):" echo "$hits" | cut -c1-200 | sed 's/^/ /'; exit 1 fi echo "inline-rm: no tracked script carries rm, find -delete or a truncate inside an inline bash -c / sh -c string"