mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-20 20:00:45 +02:00
Merge origin/main (v1.60.1.0) into garrytan/gstack-fix-wave
Semantic reconciliation with the parallel time-attack wave (#2264):
- careful: adopt main's anchored full-command whitelist (stricter — also
catches comment-hiding), re-apply this wave's two hardenings on top
(capital -[rR] in the flag cluster; exclude `(` and backtick from safe
targets so $()/backtick substitution cannot ride the whitelist). Union
of both waves' test batteries passes (main's test.each incl. comment
case + this wave's substitution/capital-R/FP-pin cases).
- one-way-doors: main landed the singular noun unification (a2a447a1);
keep this wave's superset (plural s? + --summary-stdin runtime wiring).
- gbrain-local-status: union of states — main's engine-locked (#2194,
exit 124 PGLite lock) + this wave's thin-client (#2051). --is-ok keeps
main's intent (engine-locked = STOP) and this wave's (thin-client =
usable). Test harness unions both fake behaviors.
- sync-gbrain/setup-gbrain tmpls: both Step 1.5 branches kept; generated
SKILL.md resolved via bun run gen:skill-docs (never hand-edited).
- VERSION/package.json -> 1.61.0.0 per bin/gstack-next-version (main took
1.60.1.0; PR #2470 claims 1.60.2.0). CHANGELOG: wave entry renumbered
1.61.0.0 on top of main's 1.60.1.0; careful/#2024 bullets updated to
describe the delta vs current main. TODOS: union.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,42 +25,21 @@ fi
|
||||
# Normalize: lowercase for case-insensitive SQL matching
|
||||
CMD_LOWER=$(printf '%s' "$CMD" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# --- Check for safe exceptions (rm -rf of build artifacts) ---
|
||||
# Only whitelist when the command is a SINGLE rm invocation. The target
|
||||
# extraction below greedily matches the LAST `rm ` in the string, so a chained
|
||||
# command like `rm -rf /; rm -rf node_modules` would be judged solely by its
|
||||
# final (safe) targets and wave through the destructive earlier `rm -rf /`.
|
||||
# When any shell separator is present, skip the shortcut and fall through to the
|
||||
# destructive-pattern check, which warns on any recursive rm.
|
||||
HAS_SEPARATOR=false
|
||||
case "$CMD" in
|
||||
# Real separators, plus JSON-escaped newlines (\n / \r) which survive the
|
||||
# grep extraction path as literal two-char sequences and still mark a chain.
|
||||
# Command/backtick substitution counts as chaining too: a token like
|
||||
# `$(./wipe-all)/node_modules` ends in a whitelisted suffix while running
|
||||
# anything inside the substitution. Plain $VAR expansion stays allowed —
|
||||
# only `$(` triggers.
|
||||
*';'*|*'|'*|*'&'*|*'$('*|*'`'*|*$'\n'*|*$'\r'*|*'\n'*|*'\r'*) HAS_SEPARATOR=true ;;
|
||||
esac
|
||||
if [ "$HAS_SEPARATOR" = false ] && printf '%s' "$CMD" | grep -qE 'rm\s+(-[a-zA-Z]*[rR][a-zA-Z]*\s+|--recursive\s+)' 2>/dev/null; then
|
||||
SAFE_ONLY=true
|
||||
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//;s/--recursive[[:space:]]*//')
|
||||
for target in $RM_ARGS; do
|
||||
case "$target" in
|
||||
*/node_modules|node_modules|*/\.next|\.next|*/dist|dist|*/__pycache__|__pycache__|*/\.cache|\.cache|*/build|build|*/\.turbo|\.turbo|*/coverage|coverage)
|
||||
;; # safe target
|
||||
-*)
|
||||
;; # flag, skip
|
||||
*)
|
||||
SAFE_ONLY=false
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "$SAFE_ONLY" = true ]; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
# --- Check for safe exceptions (one standalone rm of build artifacts) ---
|
||||
# Match the complete command. Parsing only the last rm is unsafe because shell
|
||||
# syntax or comments can hide an earlier destructive command, for example:
|
||||
# rm -rf / # rm -rf node_modules
|
||||
# Unknown syntax fails closed and falls through to the destructive checks.
|
||||
# Two hardenings on top of the anchored shape (#2039 wave):
|
||||
# - flag cluster accepts capital -R (BSD/macOS recursive), so a single
|
||||
# `rm -Rf node_modules` stays allowed instead of prompting;
|
||||
# - target tokens exclude `(` and backtick, so command substitution that
|
||||
# ENDS in a whitelisted suffix (`rm -rf $(./wipe-all)/node_modules`)
|
||||
# cannot ride the whitelist. Plain $VAR expansion (no parenthesis) is
|
||||
# still allowed.
|
||||
if printf '%s' "$CMD" | grep -qE '^[[:space:]]*rm[[:space:]]+(-[a-zA-Z]*[rR][a-zA-Z]*[[:space:]]+|--recursive[[:space:]]+)(([^[:space:];&|#(`]*/)?(node_modules|\.next|dist|__pycache__|\.cache|build|\.turbo|coverage)[[:space:]]*)+$' 2>/dev/null; then
|
||||
echo '{}'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Destructive pattern checks ---
|
||||
|
||||
Reference in New Issue
Block a user