mirror of
https://github.com/garrytan/gstack.git
synced 2026-07-19 22:17:57 +02:00
fix(careful): fail closed for compound recursive deletes
This commit is contained in:
@@ -25,26 +25,14 @@ fi
|
|||||||
# Normalize: lowercase for case-insensitive SQL matching
|
# Normalize: lowercase for case-insensitive SQL matching
|
||||||
CMD_LOWER=$(printf '%s' "$CMD" | tr '[:upper:]' '[:lower:]')
|
CMD_LOWER=$(printf '%s' "$CMD" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
# --- Check for safe exceptions (rm -rf of build artifacts) ---
|
# --- Check for safe exceptions (one standalone rm of build artifacts) ---
|
||||||
if printf '%s' "$CMD" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|--recursive\s+)' 2>/dev/null; then
|
# Match the complete command. Parsing only the last rm is unsafe because shell
|
||||||
SAFE_ONLY=true
|
# syntax or comments can hide an earlier destructive command, for example:
|
||||||
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//;s/--recursive[[:space:]]*//')
|
# rm -rf / # rm -rf node_modules
|
||||||
for target in $RM_ARGS; do
|
# Unknown syntax fails closed and falls through to the destructive checks.
|
||||||
case "$target" in
|
if printf '%s' "$CMD" | grep -qE '^[[:space:]]*rm[[:space:]]+(-[a-zA-Z]*r[a-zA-Z]*[[:space:]]+|--recursive[[:space:]]+)(([^[:space:];&|#]*/)?(node_modules|\.next|dist|__pycache__|\.cache|build|\.turbo|coverage)[[:space:]]*)+$' 2>/dev/null; then
|
||||||
*/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 '{}'
|
echo '{}'
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Destructive pattern checks ---
|
# --- Destructive pattern checks ---
|
||||||
|
|||||||
@@ -96,6 +96,21 @@ describe('check-careful.sh', () => {
|
|||||||
expect(output.permissionDecision).toBe('ask');
|
expect(output.permissionDecision).toBe('ask');
|
||||||
expect(output.message).toContain('recursive delete');
|
expect(output.message).toContain('recursive delete');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test.each([
|
||||||
|
'rm -rf /; rm -rf node_modules',
|
||||||
|
'rm -rf / && rm -rf node_modules',
|
||||||
|
'rm -rf / # rm -rf node_modules',
|
||||||
|
'rm -rf node_modules; rm -rf /',
|
||||||
|
'rm -rf node_modules || rm -rf /',
|
||||||
|
'echo ok && rm -rf /',
|
||||||
|
'rm -rf node_modules\nrm -rf /',
|
||||||
|
])('never lets a safe-looking target hide a destructive command: %s', (command) => {
|
||||||
|
const { exitCode, output } = runHook(CAREFUL_SCRIPT, carefulInput(command));
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
expect(output.permissionDecision).toBe('ask');
|
||||||
|
expect(output.message).toContain('recursive delete');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- SQL destructive commands ---
|
// --- SQL destructive commands ---
|
||||||
|
|||||||
Reference in New Issue
Block a user