46 lines
3.7 KiB
Bash
Executable file
46 lines
3.7 KiB
Bash
Executable file
#!/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() { # <file...>: 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"
|