Update Fleet-maintained apps - #48812
Conversation
Generated automatically with cmd/maintained-apps.
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
Script Diff Resultsee/maintained-apps/outputs/cursor/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/docker-desktop/darwin.json=== Install Script (no changes) ===
=== Uninstall // 4f0d2974 -> 29483ade ===
--- /tmp/old.SaOuUR 2026-07-06 21:11:00.206551807 +0000
+++ /tmp/new.9fu61z 2026-07-06 21:11:00.206551807 +0000
@@ -172,12 +172,12 @@
sudo rm -rf '/Library/PrivilegedHelperTools/com.docker.vmnetd'
sudo rmdir '~/.docker/bin'
sudo rm -rf "$APPDIR/Docker.app"
-sudo rm -rf '/usr/local/bin/docker'
+sudo rm -rf '/usr/local/bin/docker-credential-ecr-login'
sudo rm -rf '/usr/local/bin/docker-credential-osxkeychain'
sudo rm -rf '/usr/local/bin/kubectl.docker'
sudo rm -rf '/usr/local/cli-plugins/docker-compose'
+sudo rm -rf '/usr/local/bin/docker'
sudo rm -rf '/usr/local/bin/docker-credential-desktop'
-sudo rm -rf '/usr/local/bin/docker-credential-ecr-login'
sudo rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data'
sudo rmdir '~/Library/Caches/KSCrashReports'
trash $LOGGED_IN_USER '/usr/local/bin/docker-compose.backup'ee/maintained-apps/outputs/hive-app/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/nova/darwin.json=== Install Script (no changes) ===
=== Uninstall // 24345bcf -> 2d51ce6a ===
--- /tmp/old.N8Kgid 2026-07-06 21:11:00.305552475 +0000
+++ /tmp/new.DIPEku 2026-07-06 21:11:00.306552482 +0000
@@ -52,9 +52,9 @@
fi
}
-sudo rm -rf "$APPDIR/Nova.app"
sudo rm -rf '/Library/LaunchDaemons/com.panic.NovaPrivilegedHelper.plist'
sudo rm -rf '/Library/PrivilegedHelperTools/com.panic.NovaPrivilegedHelper'
+sudo rm -rf "$APPDIR/Nova.app"
trash $LOGGED_IN_USER '~/Library/Application Scripts/com.panic.Nova.NovaQuickLookPreview'
trash $LOGGED_IN_USER '~/Library/Application Scripts/com.panic.Nova.NovaQuickLookThumbnail'
trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.panic.nova.sfl*'ee/maintained-apps/outputs/opencode-desktop/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/postman/windows.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===ee/maintained-apps/outputs/wavebox/darwin.json=== Install Script (no changes) ===
=== Uninstall Script (no changes) === |
WalkthroughThis PR updates maintained app manifest files under ee/maintained-apps/outputs. Six apps (Cursor, Hive, OpenCode Desktop, Postman, Wavebox) receive version bumps with corresponding updates to patched SQL queries, installer URLs, and sha256 checksums. Two apps (Docker Desktop, Nova) receive updated uninstall_script_ref values with replaced uninstall script payloads in their refs mappings. Changes
Sequence Diagram(s)Not applicable; changes are static manifest data updates without executable flow changes. Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ee/maintained-apps/outputs/docker-desktop/darwin.json`:
- Line 19: The quoted home-directory paths in the cleanup script are being
treated as literal strings, so the existing rmdir calls in the Docker Desktop
uninstall flow won’t hit the intended user folders. Update the cleanup logic
around the direct rmdir invocations in this script to expand `~` the same way
`trash()` already does with `LOGGED_IN_USER`, so the home-based cache and bin
directories are removed correctly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 53b7b2b2-12ec-49c7-bff5-c19a145edead
📒 Files selected for processing (7)
ee/maintained-apps/outputs/cursor/darwin.jsonee/maintained-apps/outputs/docker-desktop/darwin.jsonee/maintained-apps/outputs/hive-app/darwin.jsonee/maintained-apps/outputs/nova/darwin.jsonee/maintained-apps/outputs/opencode-desktop/darwin.jsonee/maintained-apps/outputs/postman/windows.jsonee/maintained-apps/outputs/wavebox/darwin.json
| "refs": { | ||
| "2c3a200a": "#!/bin/bash\n\nset -euo pipefail\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\nMOUNT_POINT=\"\"\n\ncleanup() {\n local mp=\"${MOUNT_POINT:-}\"\n if [[ -n \"$mp\" ]]; then\n if mount | grep -q \" on $mp \"; then\n hdiutil detach \"$mp\" >/dev/null 2>&1 || true\n fi\n rmdir \"$mp\" >/dev/null 2>&1 || true\n fi\n}\ntrap cleanup EXIT\n\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name\n var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null || echo \"false\")\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\n return 0\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console 2>/dev/null || echo \"\")\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return 0\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit within ${timeout_duration}s; aborting install.\" >&2\n return 1\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name\n var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\${$var_name:-0}\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console 2>/dev/null || echo \"\")\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Launch the app in the logged-in user's GUI session. Apps launched by root\n # won't register with the user's Dock/GUI, so run 'open' as the console user.\n # Use 'launchctl asuser' to bootstrap into the console user's Mach namespace\n # and GUI session — 'sudo -u' alone doesn't do this, which can cause\n # LSOpenURLsWithRole() failures even when 'open' exits 0.\n local open_status=0\n if [[ $EUID -eq 0 ]]; then\n local console_uid\n console_uid=$(id -u \"$console_user\")\n /bin/launchctl asuser \"$console_uid\" sudo -u \"$console_user\" open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n else\n open -b \"$bundle_id\" >/dev/null 2>&1 || open_status=$?\n fi\n\n if [[ $open_status -eq 0 ]]; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nMOUNT_POINT=$(mktemp -d /tmp/dmg_mount_XXXXXX)\nif ! hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\"; then\n echo \"Failed to mount DMG '$INSTALLER_PATH'.\" >&2\n exit 1\nfi\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\"\nMOUNT_POINT=\"\"\n# copy to the applications folder\nquit_and_track_application 'com.electron.dockerdesktop'\nif [ -d \"$APPDIR/Docker.app\" ]; then\n\tsudo mv \"$APPDIR/Docker.app\" \"$TMPDIR/Docker.app.bkp\"\nfi\n# Docker Desktop's own in-app updater leaves a Docker.app.back bundle alongside\n# Docker.app when it self-updates. osquery's apps table still picks up the\n# stale bundle by its bundle_identifier, which causes Fleet patch policies to\n# report Docker as out of date even after a successful upgrade.\nsudo rm -rf \"$APPDIR/Docker.app.back\"\nsudo cp -R \"$TMPDIR/Docker.app\" \"$APPDIR\"\nrelaunch_application 'com.electron.dockerdesktop'\nmkdir -p /usr/local/cli-plugins\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/cli-plugins/docker-compose\" \"/usr/local/cli-plugins/docker-compose\"\nmkdir -p /usr/local/bin\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/hub-tool\" \"/usr/local/bin/hub-tool\"\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/kubectl\" \"/usr/local/bin/kubectl.docker\"\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/docker\" \"/usr/local/bin/docker\"\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-desktop\" \"/usr/local/bin/docker-credential-desktop\"\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-ecr-login\" \"/usr/local/bin/docker-credential-ecr-login\"\n/bin/ln -h -f -s -- \"$APPDIR/Docker.app/Contents/Resources/bin/docker-credential-osxkeychain\" \"/usr/local/bin/docker-credential-osxkeychain\"\n", | ||
| "4f0d2974": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.docker.helper'\nremove_launchctl_service 'com.docker.socket'\nremove_launchctl_service 'com.docker.vmnetd'\nquit_application 'com.docker.docker'\nquit_application 'com.electron.dockerdesktop'\nquit_application 'com.electron.dockerdesktop'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.socket'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.vmnetd'\nsudo rmdir '~/.docker/bin'\nsudo rm -rf \"$APPDIR/Docker.app\"\nsudo rm -rf '/usr/local/bin/docker'\nsudo rm -rf '/usr/local/bin/docker-credential-osxkeychain'\nsudo rm -rf '/usr/local/bin/kubectl.docker'\nsudo rm -rf '/usr/local/cli-plugins/docker-compose'\nsudo rm -rf '/usr/local/bin/docker-credential-desktop'\nsudo rm -rf '/usr/local/bin/docker-credential-ecr-login'\nsudo rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data'\nsudo rmdir '~/Library/Caches/KSCrashReports'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker-compose.backup'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker.backup'\ntrash $LOGGED_IN_USER '~/.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/KSCrashReports/Docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Logs/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.docker.docker.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.docker-frontend.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.dockerdesktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.docker-frontend.savedState'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.dockerdesktop.savedState'\n" | ||
| "29483ade": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n # A wildcard label can't be used with launchctl or as a plist name, so expand\n # it to the labels of currently loaded services that match the pattern.\n local services=(\"$service\")\n if [[ \"$service\" == *\"*\"* ]]; then\n local regex\n # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so\n # it matches a full label rather than a substring.\n regex=$(printf '%s' \"$service\" | sed -e 's/[][(){}.^$+?|\\\\]/\\\\&/g' -e 's/\\*/.*/g')\n regex=\"^${regex}$\"\n services=()\n local id\n # Match every loaded job by label regardless of PID; launchctl list reports\n # loaded-but-not-running jobs with a \"-\" in the PID column.\n while read -r _ _ id; do\n [[ \"$id\" =~ $regex ]] && services+=(\"$id\")\n done < <(launchctl list 2>/dev/null | tail -n +2)\n if [[ ${#services[@]} -eq 0 ]]; then\n echo \"No loaded launchctl service matches ${service}\"\n return\n fi\n fi\n\n local service_label\n for service_label in \"${services[@]}\"; do\n for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service_label}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service_label}\"\n else\n launchctl remove \"${service_label}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service_label}.plist\"\n \"/Library/LaunchDaemons/${service_label}.plist\"\n )\n\n # if not using sudo, prepend the home directory to the paths\n if [[ $should_sudo == \"false\" ]]; then\n for i in \"${!paths[@]}\"; do\n paths[i]=\"${HOME}${paths[i]}\"\n done\n fi\n\n for path in \"${paths[@]}\"; do\n if [[ -e \"$path\" ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo rm -f -- \"$path\"\n else\n rm -f -- \"$path\"\n fi\n fi\n done\n done\n done\n}\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n\n # If the target contains glob characters, expand it and move each match.\n if [[ \"$target_file\" == *[*?[]* ]]; then\n local file file_name\n local matched=false\n local i=0\n # compgen -G expands the (quoted) pattern itself, so paths containing\n # spaces glob correctly; reading line by line keeps each match intact.\n while IFS= read -r file; do\n [[ -n \"$file\" ]] || continue\n [[ -e \"$file\" || -L \"$file\" ]] || continue\n matched=true\n i=$((i + 1))\n file_name=\"$(basename \"$file\")\"\n echo \"removing $file.\"\n # The per-match counter keeps matches that share a basename from\n # overwriting each other in the trash.\n mv -f \"$file\" \"$trash/${file_name}_${timestamp}_${rand}_${i}\"\n done < <(compgen -G \"$target_file\" 2>/dev/null)\n if [[ \"$matched\" == false ]]; then\n echo \"$target_file doesn't exist.\"\n fi\n return\n fi\n\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nremove_launchctl_service 'com.docker.helper'\nremove_launchctl_service 'com.docker.socket'\nremove_launchctl_service 'com.docker.vmnetd'\nquit_application 'com.docker.docker'\nquit_application 'com.electron.dockerdesktop'\nquit_application 'com.electron.dockerdesktop'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.socket'\nsudo rm -rf '/Library/PrivilegedHelperTools/com.docker.vmnetd'\nsudo rmdir '~/.docker/bin'\nsudo rm -rf \"$APPDIR/Docker.app\"\nsudo rm -rf '/usr/local/bin/docker-credential-ecr-login'\nsudo rm -rf '/usr/local/bin/docker-credential-osxkeychain'\nsudo rm -rf '/usr/local/bin/kubectl.docker'\nsudo rm -rf '/usr/local/cli-plugins/docker-compose'\nsudo rm -rf '/usr/local/bin/docker'\nsudo rm -rf '/usr/local/bin/docker-credential-desktop'\nsudo rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data'\nsudo rmdir '~/Library/Caches/KSCrashReports'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker-compose.backup'\ntrash $LOGGED_IN_USER '/usr/local/bin/docker.backup'\ntrash $LOGGED_IN_USER '~/.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.docker.helper.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.electron.dockerdesktop.sfl*'\ntrash $LOGGED_IN_USER '~/Library/Application Support/com.bugsnag.Bugsnag/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Caches/KSCrashReports/Docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.docker.helper'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/group.com.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.docker.docker.binarycookies'\ntrash $LOGGED_IN_USER '~/Library/Logs/Docker Desktop'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.docker.docker.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.docker-frontend.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.electron.dockerdesktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.docker-frontend.savedState'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.electron.dockerdesktop.savedState'\n", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== File context =="
nl -ba ee/maintained-apps/outputs/docker-desktop/darwin.json | sed -n '1,80p'
echo
echo "== Shell behavior probe =="
tmpdir="$(mktemp -d)"
cd "$tmpdir"
mkdir -p "$HOME/.docker/bin" "$HOME/Library/Caches/com.plausiblelabs.crashreporter.data" "$HOME/Library/Caches/KSCrashReports"
printf 'quoted : '; printf '%s\n' '~/.docker/bin'
printf 'unquoted: '; printf '%s\n' ~/.docker/bin
printf '\nTrying rmdir with quoted tilde paths:\n'
rmdir '~/.docker/bin' 2>&1 || true
rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data' 2>&1 || true
rmdir '~/Library/Caches/KSCrashReports' 2>&1 || true
printf '\nStill exists?\n'
for p in "$HOME/.docker/bin" "$HOME/Library/Caches/com.plausiblelabs.crashreporter.data" "$HOME/Library/Caches/KSCrashReports"; do
[[ -d "$p" ]] && echo "yes: $p" || echo "no : $p"
done
printf '\nLiteral-path leftovers in CWD?\n'
find . -maxdepth 3 -type d | sed 's#^\./##'Repository: fleetdm/fleet
Length of output: 210
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== File context =="
cat -n ee/maintained-apps/outputs/docker-desktop/darwin.json | sed -n '1,80p'
echo
echo "== Shell behavior probe =="
tmpdir="$(mktemp -d)"
home="$tmpdir/home"
mkdir -p "$home/.docker/bin" \
"$home/Library/Caches/com.plausiblelabs.crashreporter.data" \
"$home/Library/Caches/KSCrashReports"
(
cd "$tmpdir"
HOME="$home"
echo "quoted expansion: $(printf '%s\n' '~/.docker/bin')"
echo "unquoted expansion: $(printf '%s\n' ~/.docker/bin)"
set +e
rmdir '~/.docker/bin' 2>&1
echo "rmdir status: $?"
for p in \
"$home/.docker/bin" \
"$home/Library/Caches/com.plausiblelabs.crashreporter.data" \
"$home/Library/Caches/KSCrashReports"; do
[[ -d "$p" ]] && echo "still exists: $p"
done
)Repository: fleetdm/fleet
Length of output: 14918
Quoted ~ paths break these rmdir calls
sudo rmdir '~/.docker/bin', sudo rmdir '~/Library/Caches/com.plausiblelabs.crashreporter.data', and sudo rmdir '~/Library/Caches/KSCrashReports' pass a literal ~, so they won’t remove the intended directories and will leave those leftovers behind. Use the same home expansion approach as trash instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ee/maintained-apps/outputs/docker-desktop/darwin.json` at line 19, The quoted
home-directory paths in the cleanup script are being treated as literal strings,
so the existing rmdir calls in the Docker Desktop uninstall flow won’t hit the
intended user folders. Update the cleanup logic around the direct rmdir
invocations in this script to expand `~` the same way `trash()` already does
with `LOGGED_IN_USER`, so the home-based cache and bin directories are removed
correctly.
Automated ingestion of latest Fleet-maintained app data.
Summary by CodeRabbit