From ee1f2bd3726e871f809486b0b27a4e605bf368b3 Mon Sep 17 00:00:00 2001 From: Luke Bullimore <112502129+injuxtice@users.noreply.github.com> Date: Wed, 25 Feb 2026 02:22:56 +0000 Subject: [PATCH 1/2] Fix --dry-run hiding system cleanup preview (#493) The dry-run mode hardcoded SYSTEM_CLEAN=false, which meant the entire system section was silently skipped during preview. Users had no way to see what /Library/Caches, /private/var/log, diagnostics, or other sudo-required paths would be cleaned. Now dry-run checks for a cached sudo session (sudo -n) and includes the system preview when available. When sudo isn't cached, a hint tells the user how to get the full preview without running the whole script as root. --- bin/clean.sh | 12 +++++++++++- tests/clean_core.bats | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/bin/clean.sh b/bin/clean.sh index c0e7d01..b5f16ea 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -717,7 +717,6 @@ start_cleanup() { if [[ "$DRY_RUN" == "true" ]]; then echo -e "${YELLOW}Dry Run Mode${NC}, Preview only, no deletions" echo "" - SYSTEM_CLEAN=false ensure_user_file "$EXPORT_LIST_FILE" cat > "$EXPORT_LIST_FILE" << EOF @@ -732,6 +731,17 @@ start_cleanup() { # EOF + + # Preview system section when sudo is already cached (no password prompt). + if sudo -n true 2> /dev/null; then + SYSTEM_CLEAN=true + echo -e "${GREEN}${ICON_SUCCESS}${NC} Admin access available, system preview included" + echo "" + else + SYSTEM_CLEAN=false + echo -e "${GRAY}${ICON_WARNING} System caches need sudo, run ${NC}sudo -v && mo clean --dry-run${GRAY} for full preview${NC}" + echo "" + fi return fi diff --git a/tests/clean_core.bats b/tests/clean_core.bats index 3994c64..0b78f6a 100644 --- a/tests/clean_core.bats +++ b/tests/clean_core.bats @@ -34,6 +34,42 @@ setup() { [[ "$output" != *"Deep system-level cleanup"* ]] } +@test "mo clean --dry-run includes system preview when sudo is cached" { + local mock_bin="$HOME/bin" + mkdir -p "$mock_bin" + cat > "$mock_bin/sudo" << 'MOCK' +#!/bin/bash +# Shim: sudo -n true succeeds, all other sudo calls are no-ops. +if [[ "$1" == "-n" && "$2" == "true" ]]; then exit 0; fi +if [[ "$1" == "test" ]]; then exit 1; fi +if [[ "$1" == "find" ]]; then exit 0; fi +exit 0 +MOCK + chmod +x "$mock_bin/sudo" + + run env HOME="$HOME" MOLE_TEST_MODE=1 PATH="$mock_bin:$PATH" \ + "$PROJECT_ROOT/mole" clean --dry-run + [ "$status" -eq 0 ] + [[ "$output" == *"system preview included"* ]] +} + +@test "mo clean --dry-run shows hint when sudo is not cached" { + local mock_bin="$HOME/bin" + mkdir -p "$mock_bin" + cat > "$mock_bin/sudo" << 'MOCK' +#!/bin/bash +# Shim: sudo -n always fails (no cached credentials). +exit 1 +MOCK + chmod +x "$mock_bin/sudo" + + run env HOME="$HOME" MOLE_TEST_MODE=1 PATH="$mock_bin:$PATH" \ + "$PROJECT_ROOT/mole" clean --dry-run + [ "$status" -eq 0 ] + [[ "$output" == *"sudo -v"* ]] + [[ "$output" == *"full preview"* ]] +} + @test "mo clean --dry-run reports user cache without deleting it" { mkdir -p "$HOME/Library/Caches/TestApp" echo "cache data" > "$HOME/Library/Caches/TestApp/cache.tmp" From 5241b59ea9f09af8557673a423126456e5cdce0c Mon Sep 17 00:00:00 2001 From: tw93 Date: Wed, 25 Feb 2026 10:32:12 +0800 Subject: [PATCH 2/2] refactor: reuse sudo cache checks in clean dry-run tests --- bin/clean.sh | 11 ++++++-- tests/clean_core.bats | 66 +++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/bin/clean.sh b/bin/clean.sh index b5f16ea..914cb09 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -137,6 +137,11 @@ note_activity() { fi } +# shellcheck disable=SC2329 +has_cached_sudo() { + sudo -n true 2> /dev/null +} + CLEANUP_DONE=false # shellcheck disable=SC2329 cleanup() { @@ -733,7 +738,7 @@ start_cleanup() { EOF # Preview system section when sudo is already cached (no password prompt). - if sudo -n true 2> /dev/null; then + if has_cached_sudo; then SYSTEM_CLEAN=true echo -e "${GREEN}${ICON_SUCCESS}${NC} Admin access available, system preview included" echo "" @@ -746,7 +751,7 @@ EOF fi if [[ -t 0 ]]; then - if sudo -n true 2> /dev/null; then + if has_cached_sudo; then SYSTEM_CLEAN=true echo -e "${GREEN}${ICON_SUCCESS}${NC} Admin access already available" echo "" @@ -786,7 +791,7 @@ EOF else echo "" echo "Running in non-interactive mode" - if sudo -n true 2> /dev/null; then + if has_cached_sudo; then SYSTEM_CLEAN=true echo " ${ICON_LIST} System-level cleanup enabled, sudo session active" else diff --git a/tests/clean_core.bats b/tests/clean_core.bats index 0b78f6a..8da50b2 100644 --- a/tests/clean_core.bats +++ b/tests/clean_core.bats @@ -25,19 +25,13 @@ setup() { rm -rf "${HOME:?}"/* rm -rf "$HOME/Library" "$HOME/.config" mkdir -p "$HOME/Library/Caches" "$HOME/.config/mole" + unset TEST_MOCK_BIN } -@test "mo clean --dry-run skips system cleanup in non-interactive mode" { - run env HOME="$HOME" MOLE_TEST_MODE=1 "$PROJECT_ROOT/mole" clean --dry-run - [ "$status" -eq 0 ] - [[ "$output" == *"Dry Run Mode"* ]] - [[ "$output" != *"Deep system-level cleanup"* ]] -} - -@test "mo clean --dry-run includes system preview when sudo is cached" { - local mock_bin="$HOME/bin" - mkdir -p "$mock_bin" - cat > "$mock_bin/sudo" << 'MOCK' +set_mock_sudo_cached() { + TEST_MOCK_BIN="$HOME/bin" + mkdir -p "$TEST_MOCK_BIN" + cat > "$TEST_MOCK_BIN/sudo" << 'MOCK' #!/bin/bash # Shim: sudo -n true succeeds, all other sudo calls are no-ops. if [[ "$1" == "-n" && "$2" == "true" ]]; then exit 0; fi @@ -45,26 +39,49 @@ if [[ "$1" == "test" ]]; then exit 1; fi if [[ "$1" == "find" ]]; then exit 0; fi exit 0 MOCK - chmod +x "$mock_bin/sudo" + chmod +x "$TEST_MOCK_BIN/sudo" +} - run env HOME="$HOME" MOLE_TEST_MODE=1 PATH="$mock_bin:$PATH" \ +set_mock_sudo_uncached() { + TEST_MOCK_BIN="$HOME/bin" + mkdir -p "$TEST_MOCK_BIN" + cat > "$TEST_MOCK_BIN/sudo" << 'MOCK' +#!/bin/bash +# Shim: sudo -n always fails (no cached credentials). +exit 1 +MOCK + chmod +x "$TEST_MOCK_BIN/sudo" +} + +run_clean_dry_run() { + local test_path="$PATH" + if [[ -n "${TEST_MOCK_BIN:-}" ]]; then + test_path="$TEST_MOCK_BIN:$PATH" + fi + + run env HOME="$HOME" MOLE_TEST_MODE=1 PATH="$test_path" \ "$PROJECT_ROOT/mole" clean --dry-run +} + +@test "mo clean --dry-run skips system cleanup in non-interactive mode" { + set_mock_sudo_uncached + run_clean_dry_run + [ "$status" -eq 0 ] + [[ "$output" == *"Dry Run Mode"* ]] + [[ "$output" == *"sudo -v && mo clean --dry-run"* ]] + [[ "$output" != *"system preview included"* ]] +} + +@test "mo clean --dry-run includes system preview when sudo is cached" { + set_mock_sudo_cached + run_clean_dry_run [ "$status" -eq 0 ] [[ "$output" == *"system preview included"* ]] } @test "mo clean --dry-run shows hint when sudo is not cached" { - local mock_bin="$HOME/bin" - mkdir -p "$mock_bin" - cat > "$mock_bin/sudo" << 'MOCK' -#!/bin/bash -# Shim: sudo -n always fails (no cached credentials). -exit 1 -MOCK - chmod +x "$mock_bin/sudo" - - run env HOME="$HOME" MOLE_TEST_MODE=1 PATH="$mock_bin:$PATH" \ - "$PROJECT_ROOT/mole" clean --dry-run + set_mock_sudo_uncached + run_clean_dry_run [ "$status" -eq 0 ] [[ "$output" == *"sudo -v"* ]] [[ "$output" == *"full preview"* ]] @@ -300,4 +317,3 @@ EOF [[ "$output" == *"Time Machine backup in progress, skipping cleanup"* ]] } -