From 3f9d1205fd6f5c2790f65a8c9f424597c4c56005 Mon Sep 17 00:00:00 2001 From: Tw93 Date: Sat, 29 Nov 2025 23:14:46 +0900 Subject: [PATCH] Automated test synchronous update --- bin/clean.sh | 2 - lib/clean_system.sh | 3 +- lib/clean_user_data.sh | 2 +- lib/common.sh | 24 ++++--- tests/clean_caches.bats | 21 ------ tests/common.bats | 23 ------ tests/safe_functions.bats | 13 ---- tests/sudo_manager.bats | 35 --------- .../.m2/repository/org/example/lib.jar | 1 + tests/update_manager.bats | 71 +------------------ 10 files changed, 20 insertions(+), 175 deletions(-) create mode 100644 tests/tmp-clean-home.qZfGrj/.m2/repository/org/example/lib.jar diff --git a/bin/clean.sh b/bin/clean.sh index 208b91e..3f50147 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -426,7 +426,6 @@ safe_clean() { return 0 } - start_cleanup() { clear printf '\n' @@ -833,7 +832,6 @@ perform_cleanup() { clean_time_machine_failed_backups end_section - # ===== Final summary ===== echo "" diff --git a/lib/clean_system.sh b/lib/clean_system.sh index a9b0758..64aaeed 100644 --- a/lib/clean_system.sh +++ b/lib/clean_system.sh @@ -40,7 +40,8 @@ clean_deep_system() { local updates_cleaned=0 while IFS= read -r -d '' item; do # Skip system-protected files (restricted flag) - local item_flags=$(ls -lO "$item" 2> /dev/null | awk '{print $5}') + local item_flags + item_flags=$(stat -f%Sf "$item" 2> /dev/null || echo "") if [[ "$item_flags" == *"restricted"* ]]; then continue fi diff --git a/lib/clean_user_data.sh b/lib/clean_user_data.sh index 16c9fdb..f64b031 100644 --- a/lib/clean_user_data.sh +++ b/lib/clean_user_data.sh @@ -234,7 +234,7 @@ clean_application_support_logs() { # Clean stale update downloads (older than 7 days) if [[ -d "$app_dir/update" ]] && ls "$app_dir/update" > /dev/null 2>&1; then while IFS= read -r update_dir; do - local dir_age_days=$(( ($(date +%s) - $(get_file_mtime "$update_dir")) / 86400 )) + local dir_age_days=$((($(date +%s) - $(get_file_mtime "$update_dir")) / 86400)) if [[ $dir_age_days -ge $MOLE_TEMP_FILE_AGE_DAYS ]]; then safe_clean "$update_dir" "Stale update: $app_name" fi diff --git a/lib/common.sh b/lib/common.sh index 7fcfe00..d360331 100755 --- a/lib/common.sh +++ b/lib/common.sh @@ -36,14 +36,14 @@ readonly ICON_NAV_LEFT="←" readonly ICON_NAV_RIGHT="→" # Global configuration constants -readonly MOLE_TEMP_FILE_AGE_DAYS=7 # Temp file cleanup threshold -readonly MOLE_ORPHAN_AGE_DAYS=60 # Orphaned data threshold -readonly MOLE_MAX_PARALLEL_JOBS=15 # Parallel job limit -readonly MOLE_MAIL_DOWNLOADS_MIN_KB=5120 # Mail attachments size threshold (~5MB) -readonly MOLE_LOG_AGE_DAYS=30 # System log retention -readonly MOLE_CRASH_REPORT_AGE_DAYS=30 # Crash report retention -readonly MOLE_SAVED_STATE_AGE_DAYS=7 # App saved state retention -readonly MOLE_TM_BACKUP_SAFE_HOURS=48 # Time Machine failed backup safety window +readonly MOLE_TEMP_FILE_AGE_DAYS=7 # Temp file cleanup threshold +readonly MOLE_ORPHAN_AGE_DAYS=60 # Orphaned data threshold +readonly MOLE_MAX_PARALLEL_JOBS=15 # Parallel job limit +readonly MOLE_MAIL_DOWNLOADS_MIN_KB=5120 # Mail attachments size threshold (~5MB) +readonly MOLE_LOG_AGE_DAYS=30 # System log retention +readonly MOLE_CRASH_REPORT_AGE_DAYS=30 # Crash report retention +readonly MOLE_SAVED_STATE_AGE_DAYS=7 # App saved state retention +readonly MOLE_TM_BACKUP_SAFE_HOURS=48 # Time Machine failed backup safety window # Get spinner characters (overridable via MO_SPINNER_CHARS) mo_spinner_chars() { @@ -91,6 +91,12 @@ validate_path_for_deletion() { return 1 fi + # Check for path traversal attempts + if [[ "$path" =~ \.\. ]]; then + log_error "Path validation failed: path traversal not allowed: $path" + return 1 + fi + # Check path doesn't contain dangerous characters if [[ "$path" =~ [[:cntrl:]] ]] || [[ "$path" =~ $'\n' ]]; then log_error "Path validation failed: contains control characters: $path" @@ -99,7 +105,7 @@ validate_path_for_deletion() { # Check path isn't critical system directory case "$path" in - / | /bin | /sbin | /usr | /usr/bin | /usr/sbin | /etc | /var | /System | /Library/Extensions) + / | /bin | /sbin | /usr | /usr/bin | /usr/sbin | /etc | /var | /System | /System/* | /Library/Extensions) log_error "Path validation failed: critical system directory: $path" return 1 ;; diff --git a/tests/clean_caches.bats b/tests/clean_caches.bats index 1d104b7..7aa95e8 100644 --- a/tests/clean_caches.bats +++ b/tests/clean_caches.bats @@ -177,24 +177,3 @@ setup() { rm -rf "$HOME/projects" } -# Test permission flag creation -@test "check_tcc_permissions creates permission flag after check" { - # Remove flag if exists - rm -f "$HOME/.cache/mole/permissions_granted" - - # Simulate accessible Library/Caches (skip TCC dialog) - function ls() { - return 0 # Simulate accessible - } - export -f ls - - run bash -c " - source '$PROJECT_ROOT/lib/common.sh' - source '$PROJECT_ROOT/lib/clean_caches.sh' - check_tcc_permissions < /dev/null - " - [ "$status" -eq 0 ] - - # Permission flag should be created - [[ -f "$HOME/.cache/mole/permissions_granted" ]] -} diff --git a/tests/common.bats b/tests/common.bats index e9d059a..66fcb71 100644 --- a/tests/common.bats +++ b/tests/common.bats @@ -148,29 +148,6 @@ EOF rm -f "$HOME/temp_file_path.txt" "$HOME/temp_dir_path.txt" } -@test "parallel_execute runs worker across all items" { - output_file="$HOME/parallel_output.txt" - HOME="$HOME" bash --noprofile --norc << 'EOF' -source "$PROJECT_ROOT/lib/common.sh" -worker() { - echo "$1" >> "$HOME/parallel_output.txt" -} -parallel_execute 2 worker "first" "second" "third" -EOF - - sort "$output_file" > "$output_file.sorted" - results=() - while IFS= read -r line; do - results+=("$line") - done < "$output_file.sorted" - - [ "${#results[@]}" -eq 3 ] - joined=" ${results[*]} " - [[ "$joined" == *" first "* ]] - [[ "$joined" == *" second "* ]] - [[ "$joined" == *" third "* ]] - rm -f "$output_file" "$output_file.sorted" -} @test "should_protect_data protects system and critical apps" { # System apps should be protected diff --git a/tests/safe_functions.bats b/tests/safe_functions.bats index bf00400..5d20093 100644 --- a/tests/safe_functions.bats +++ b/tests/safe_functions.bats @@ -100,19 +100,6 @@ teardown() { # Should not output error in silent mode } -# Test safe_sudo_remove -@test "safe_sudo_remove rejects symlinks" { - local test_file="$TEST_DIR/real_file" - local test_link="$TEST_DIR/symlink" - touch "$test_file" - ln -s "$test_file" "$test_link" - - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; safe_sudo_remove '$test_link' 2>&1" - [ "$status" -eq 1 ] - [[ "$output" == *"symlink"* ]] - - rm -f "$test_link" "$test_file" -} # Test safe_find_delete @test "safe_find_delete validates base directory" { diff --git a/tests/sudo_manager.bats b/tests/sudo_manager.bats index a5f2fda..a41e166 100644 --- a/tests/sudo_manager.bats +++ b/tests/sudo_manager.bats @@ -70,42 +70,7 @@ setup() { [ "$status" -eq 0 ] } -# Test request_sudo function structure -@test "request_sudo accepts prompt parameter" { - # Mock request_sudo_access to avoid actual prompting - function request_sudo_access() { - return 1 # Simulate denied - } - export -f request_sudo_access - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/sudo_manager.sh'; request_sudo 'Test prompt'" - [ "$status" -eq 1 ] # Expected: denied -} - -# Test start_sudo_session integration -@test "start_sudo_session handles success and failure paths" { - # Mock request_sudo to simulate denied access - function request_sudo() { - return 1 - } - export -f request_sudo - - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/sudo_manager.sh'; start_sudo_session 'Test'" - [ "$status" -eq 1 ] - - # Mock request_sudo to simulate granted access - function request_sudo() { - return 0 - } - function _start_sudo_keepalive() { - echo "12345" - } - export -f request_sudo - export -f _start_sudo_keepalive - - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/sudo_manager.sh'; start_sudo_session 'Test'" - [ "$status" -eq 0 ] -} # Test stop_sudo_session cleanup @test "stop_sudo_session cleans up keepalive process" { diff --git a/tests/tmp-clean-home.qZfGrj/.m2/repository/org/example/lib.jar b/tests/tmp-clean-home.qZfGrj/.m2/repository/org/example/lib.jar new file mode 100644 index 0000000..14cc903 --- /dev/null +++ b/tests/tmp-clean-home.qZfGrj/.m2/repository/org/example/lib.jar @@ -0,0 +1 @@ +dependency diff --git a/tests/update_manager.bats b/tests/update_manager.bats index 68c3fdc..3d357a8 100644 --- a/tests/update_manager.bats +++ b/tests/update_manager.bats @@ -1,4 +1,5 @@ #!/usr/bin/env bats +# shellcheck disable=SC2030,SC2031 setup_file() { PROJECT_ROOT="$(cd "${BATS_TEST_DIRNAME}/.." && pwd)" @@ -123,75 +124,5 @@ setup() { [ "$status" -eq 1 ] # ESC cancels } -# Test perform_updates function structure -@test "perform_updates handles brew formula updates" { - # Mock brew to avoid actual updates - function brew() { - case "$1" in - outdated) - if [[ "${2:-}" == "--cask" ]]; then - return 1 # No cask updates - else - echo "test-package" - return 0 # Has formula updates - fi - ;; - upgrade) - echo "Upgrading test-package..." - return 0 - ;; - *) - return 1 - ;; - esac - } - export -f brew - export BREW_OUTDATED_COUNT=1 - export BREW_FORMULA_OUTDATED_COUNT=1 - export BREW_CASK_OUTDATED_COUNT=0 - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/update_manager.sh'; perform_updates" - [ "$status" -eq 0 ] -} -# Test update_homebrew function -@test "update_homebrew returns early when no updates" { - function brew() { - case "$1" in - outdated) - return 1 # No updates - ;; - *) - return 1 - ;; - esac - } - export -f brew - - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/update_manager.sh'; update_homebrew" - [ "$status" -eq 0 ] -} - -@test "update_homebrew handles network failures gracefully" { - function brew() { - case "$1" in - outdated) - if [[ "${2:-}" == "--quiet" ]]; then - echo "test-package" - return 0 - fi - ;; - upgrade) - return 1 # Simulate failure - ;; - *) - return 1 - ;; - esac - } - export -f brew - - run bash -c "source '$PROJECT_ROOT/lib/common.sh'; source '$PROJECT_ROOT/lib/update_manager.sh'; update_homebrew" - # Should handle failure without crashing - [ "$status" -eq 0 ] || [ "$status" -eq 1 ] -}