Skip to content

Update Fleet-maintained apps - #49797

Closed
fleet-release wants to merge 1 commit into
mainfrom
fma-2607230019
Closed

Update Fleet-maintained apps#49797
fleet-release wants to merge 1 commit into
mainfrom
fma-2607230019

Conversation

@fleet-release

@fleet-release fleet-release commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Automated ingestion of latest Fleet-maintained app data.

Summary by CodeRabbit

  • New Features
    • Updated managed app packages to their latest releases across macOS and Windows, including Advanced Installer, Akiflow, AWS CLI, Brave, Dataflare, Firefox, Granola, Loom, Microsoft Teams, Mozilla VPN, OBS, Pritunl, and others.
    • Refreshed download links and integrity checks for the updated installers.
  • Bug Fixes
    • Updated installation and upgrade detection to correctly recognize the latest app versions.
    • Refined uninstall behavior for select applications, including Rider, Setapp, and PowerShell.

Generated automatically with cmd/maintained-apps.
@github-actions

Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/advanced-installer/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/akiflow/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/amie/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/aws-cli/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/beyond-compare/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/brave-browser/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/cleanmymac/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/clop/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/comet/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/cursor/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/dataflare/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/dataflare/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/datagrip/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/datagrip/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/firefox@developer-edition/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/firefox@nightly/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/google-ads-editor/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/granola/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/granola/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/hwmonitor/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/lookaway/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/loom/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/loom/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/macwhisper/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/marsedit/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/megasync/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/microsoft-teams/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/microsoft-teams/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/mozilla-vpn/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/mozilla-vpn/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/naps2/darwin.json

=== Install // 54ba1114 -> 27c40399 ===

--- /tmp/old.ZK0DEB	2026-07-23 00:24:29.087650727 +0000
+++ /tmp/new.vmz3MG	2026-07-23 00:24:29.087650727 +0000
@@ -96,5 +96,5 @@
 
 # install pkg files
 quit_and_track_application 'com.naps2.desktop'
-sudo installer -pkg "$TMPDIR/naps2-8.3.1-mac-arm64.pkg" -target /
+sudo installer -pkg "$TMPDIR/naps2-8.3.2-mac-arm64.pkg" -target /
 relaunch_application 'com.naps2.desktop'

=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/nosql-workbench/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/nosql-workbench/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/obs/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/only-switch/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/onlyoffice/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/popclip/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/powerphotos/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/powershell/windows.json

=== Install Script (no changes) ===
=== Uninstall // 0995d374 -> 06cf76b8 ===

--- /tmp/old.cH8tLM	2026-07-23 00:24:29.493656256 +0000
+++ /tmp/new.6SKCv7	2026-07-23 00:24:29.493656256 +0000
@@ -1,4 +1,4 @@
-$product_code = '{7B031DCF-BDCE-47D6-89B9-4C558D76E773}'
+$product_code = '{92D9A5DC-8C64-40D5-B1BC-98DB9C7FDB7F}'
 $timeoutSeconds = 300  # 5 minute timeout
 
 # Fleet uninstalls app using product code that's extracted on upload

ee/maintained-apps/outputs/prisma-browser/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/pritunl/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/pritunl/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/rider/darwin.json

=== Install Script (no changes) ===
=== Uninstall // c52dae57 -> 22db20ac ===

--- /tmp/old.4S1VEC	2026-07-23 00:24:29.658658502 +0000
+++ /tmp/new.MUBOPa	2026-07-23 00:24:29.658658502 +0000
@@ -54,9 +54,9 @@
 
 sudo rm -rf "$APPDIR/Rider.app"
 sudo rm -rf 'rider'
-trash $LOGGED_IN_USER '~/Library/Application Support/Rider2026.1'
-trash $LOGGED_IN_USER '~/Library/Caches/Rider2026.1'
-trash $LOGGED_IN_USER '~/Library/Logs/Rider2026.1'
+trash $LOGGED_IN_USER '~/Library/Application Support/Rider2026.2'
+trash $LOGGED_IN_USER '~/Library/Caches/Rider2026.2'
+trash $LOGGED_IN_USER '~/Library/Logs/Rider2026.2'
 trash $LOGGED_IN_USER '~/Library/Preferences/jetbrains.rider.71e559ef.plist'
-trash $LOGGED_IN_USER '~/Library/Preferences/Rider2026.1'
+trash $LOGGED_IN_USER '~/Library/Preferences/Rider2026.2'
 trash $LOGGED_IN_USER '~/Library/Saved Application State/com.jetbrains.rider.savedState'

ee/maintained-apps/outputs/rustrover/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/setapp/darwin.json

=== Install Script (no changes) ===
=== Uninstall // e23bd29d -> 9ef05eb6 ===

--- /tmp/old.noguOT	2026-07-23 00:24:29.750659755 +0000
+++ /tmp/new.ebC5Gw	2026-07-23 00:24:29.751659769 +0000
@@ -5,6 +5,76 @@
 LOGGED_IN_USER=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')
 # functions
 
+remove_launchctl_service() {
+  local service="$1"
+  local booleans=("true" "false")
+  local plist_status
+  local paths
+  local should_sudo
+
+  echo "Removing launchctl service ${service}"
+
+  # A wildcard label can't be used with launchctl or as a plist name, so expand
+  # it to the labels of currently loaded services that match the pattern.
+  local services=("$service")
+  if [[ "$service" == *"*"* ]]; then
+    local regex
+    # Escape regex metacharacters, turn '*' into '.*', and anchor the pattern so
+    # it matches a full label rather than a substring.
+    regex=$(printf '%s' "$service" | sed -e 's/[][(){}.^$+?|\\]/\\&/g' -e 's/\*/.*/g')
+    regex="^${regex}$"
+    services=()
+    local id
+    # Match every loaded job by label regardless of PID; launchctl list reports
+    # loaded-but-not-running jobs with a "-" in the PID column.
+    while read -r _ _ id; do
+      [[ "$id" =~ $regex ]] && services+=("$id")
+    done < <(launchctl list 2>/dev/null | tail -n +2)
+    if [[ ${#services[@]} -eq 0 ]]; then
+      echo "No loaded launchctl service matches ${service}"
+      return
+    fi
+  fi
+
+  local service_label
+  for service_label in "${services[@]}"; do
+    for should_sudo in "${booleans[@]}"; do
+      plist_status=$(launchctl list "${service_label}" 2>/dev/null)
+
+      if [[ $plist_status == \{* ]]; then
+        if [[ $should_sudo == "true" ]]; then
+          sudo launchctl remove "${service_label}"
+        else
+          launchctl remove "${service_label}"
+        fi
+        sleep 1
+      fi
+
+      paths=(
+        "/Library/LaunchAgents/${service_label}.plist"
+        "/Library/LaunchDaemons/${service_label}.plist"
+      )
+
+      # if not using sudo, prepend the home directory to the paths
+      if [[ $should_sudo == "false" ]]; then
+        for i in "${!paths[@]}"; do
+          paths[i]="${HOME}${paths[i]}"
+        done
+      fi
+
+      for path in "${paths[@]}"; do
+        if [[ -e "$path" ]]; then
+          if [[ $should_sudo == "true" ]]; then
+            sudo rm -f -- "$path"
+          else
+            rm -f -- "$path"
+          fi
+        fi
+      done
+    done
+  done
+}
+
 trash() {
   local logged_in_user="$1"
   local target_file="$2"
@@ -52,10 +122,19 @@
   fi
 }
 
+remove_launchctl_service 'com.setapp.DesktopClient.SetappAgent'
+remove_launchctl_service 'com.setapp.DesktopClient.SetappAssistant'
+remove_launchctl_service 'com.setapp.DesktopClient.SetappLauncher'
+remove_launchctl_service 'com.setapp.DesktopClient.SetappUpdater'
 sudo rm -rf "$APPDIR/Setapp.app"
 trash $LOGGED_IN_USER '~/Library/Application Scripts/com.setapp.DesktopClient.SetappAgent.FinderSyncExt'
+trash $LOGGED_IN_USER '~/Library/Application Support/Setapp*'
 trash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient'
 trash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient.SetappAgent'
+trash $LOGGED_IN_USER '~/Library/Containers/com.setapp.DesktopClient.SetappAgent.FinderSyncExt'
+trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.setapp.DesktopClient*'
+trash $LOGGED_IN_USER '~/Library/LaunchAgents/com.setapp.DesktopClient.*plist'
 trash $LOGGED_IN_USER '~/Library/Logs/Setapp'
+trash $LOGGED_IN_USER '~/Library/Preferences/com.setapp.DesktopClient.plist'
 trash $LOGGED_IN_USER '~/Library/Preferences/com.setapp.DesktopClient.SetappAgent.plist'
 trash $LOGGED_IN_USER '~/Library/Saved Application State/com.setapp.DesktopClient.savedState'

ee/maintained-apps/outputs/snagit/darwin.json

=== Install Script (no changes) ===
=== Uninstall // b52ff2b2 -> 59bfdeae ===

--- /tmp/old.OuwHwF	2026-07-23 00:24:29.797660395 +0000
+++ /tmp/new.lqlGzG	2026-07-23 00:24:29.797660395 +0000
@@ -5,6 +5,46 @@
 LOGGED_IN_USER=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')
 # functions
 
+quit_application() {
+  local bundle_id="$1"
+  local timeout_duration=10
+
+  # check if the application is running
+  local app_running
+  app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null)
+  if [[ "$app_running" != "true" ]]; then
+    return
+  fi
+
+  local console_user
+  console_user=$(stat -f "%Su" /dev/console)
+  if [[ -z "$console_user" || "$console_user" == "root" || "$console_user" == "loginwindow" ]]; then
+    echo "Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'."
+    return
+  fi
+
+  echo "Quitting application '$bundle_id'..."
+
+  # try to quit the application within the timeout period
+  local quit_success=false
+  SECONDS=0
+  while (( SECONDS < timeout_duration )); do
+    if osascript -e "tell application id \"$bundle_id\" to quit" >/dev/null 2>&1; then
+      if ! pgrep -f "$bundle_id" >/dev/null 2>&1; then
+        echo "Application '$bundle_id' quit successfully."
+        quit_success=true
+        break
+      fi
+    fi
+    sleep 1
+  done
+
+  if [[ "$quit_success" = false ]]; then
+    echo "Application '$bundle_id' did not quit."
+  fi
+}
+
+
 trash() {
   local logged_in_user="$1"
   local target_file="$2"
@@ -52,9 +92,14 @@
   fi
 }
 
+quit_application 'com.TechSmith.Snagit'
 sudo rm -rf "$APPDIR/Snagit.app"
+trash $LOGGED_IN_USER '~/Library/Application Scripts/7TQL462TU8.com.techsmith.snagit'
+trash $LOGGED_IN_USER '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.techsmith.snagit.sfl*'
+trash $LOGGED_IN_USER '~/Library/Application Support/Snagit'
 trash $LOGGED_IN_USER '~/Library/Caches/com.TechSmith.Snagit*'
 trash $LOGGED_IN_USER '~/Library/Group Containers/*.com.techsmith.snagit'
+trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.TechSmith.Snagit*'
 trash $LOGGED_IN_USER '~/Library/Preferences/com.TechSmith.Snagit*.plist'
 trash $LOGGED_IN_USER '~/Library/Preferences/com.techsmith.snagit.capturehelper*.plist'
 trash $LOGGED_IN_USER '~/Library/Saved Application State/com.TechSmith.Snagit*.savedState'

ee/maintained-apps/outputs/sourcetree/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/superwhisper/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/tabby/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/trezor-suite/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/typora/windows.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/visual-studio-code/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/vivaldi/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/wechat/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/whatsapp/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

ee/maintained-apps/outputs/workflowy/darwin.json

=== Install Script (no changes) ===
=== Uninstall Script (no changes) ===

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Updated maintained-app output manifests for numerous Windows and macOS applications. Changes include newer version values, patched-query version thresholds, installer URLs, and SHA-256 checksums. Selected entries also update install or uninstall script references and embedded script behavior for NAPS2, PowerShell, Rider, Setapp, and Snagit.

Possibly related PRs

  • fleetdm/fleet#49796 — Updates overlapping maintained-app entries using the same version, query, URL, and checksum fields.
  • fleetdm/fleet#49793 — Applies the same maintained-app metadata refresh pattern to overlapping entries.
  • fleetdm/fleet#49759 — Updates overlapping maintained-app JSON records with matching release metadata changes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is far too brief and omits the required issue, checklist, testing, and migration sections from the template. Expand the PR description to follow the template, including related issue, checklist items, testing notes, and any applicable migration details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title matches the main change by indicating Fleet-maintained app updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fma-2607230019

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
ee/maintained-apps/outputs/advanced-installer/windows.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

ee/maintained-apps/outputs/akiflow/darwin.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

ee/maintained-apps/outputs/amie/darwin.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

  • 53 others

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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/naps2/darwin.json`:
- Line 19: Capture and propagate the exit status of the sudo installer command
in the installation flow before calling relaunch_application. Ensure the script
exits nonzero when package installation fails, while preserving the existing
relaunch behavior only for successful installations.

In `@ee/maintained-apps/outputs/onlyoffice/darwin.json`:
- Around line 9-10: Update the darwin ONLYOFFICE v9.4.0 installer configuration
to reference an actual macOS release asset; use its exact filename in
installer_url and update install_script_ref so extraction matches the asset
format, using hdiutil for a .dmg or the appropriate archive command otherwise.

In `@ee/maintained-apps/outputs/rider/darwin.json`:
- Line 19: Remove the sudo rm -rf command targeting the relative “rider” path,
or replace it with a validated absolute path confined to the intended Rider data
or extraction directory; preserve the existing absolute APPDIR cleanup.

In `@ee/maintained-apps/outputs/setapp/darwin.json`:
- Line 20: Update remove_launchctl_service so non-sudo cleanup targets the
logged-in user’s domain rather than the installer’s root environment: build
LaunchAgents paths under /Users/$LOGGED_IN_USER and invoke launchctl removal
through that user’s GUI bootstrap/domain. Keep privileged daemon cleanup and
existing wildcard/service matching behavior unchanged.

In `@ee/maintained-apps/outputs/snagit/darwin.json`:
- Line 11: Update the uninstall_script_ref entry in the Snagit configuration to
reference the actual uninstall/removal script instead of the install script,
using b52ff2b2 if it remains valid. Ensure the referenced script removes Snagit
rather than mounting the DMG, copying the application, or relaunching it.
🪄 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: 91430328-f088-406d-8e62-5da03059f085

📥 Commits

Reviewing files that changed from the base of the PR and between 42c0e4f and 6b3bd29.

📒 Files selected for processing (56)
  • ee/maintained-apps/outputs/advanced-installer/windows.json
  • ee/maintained-apps/outputs/akiflow/darwin.json
  • ee/maintained-apps/outputs/amie/darwin.json
  • ee/maintained-apps/outputs/aws-cli/windows.json
  • ee/maintained-apps/outputs/beyond-compare/darwin.json
  • ee/maintained-apps/outputs/brave-browser/darwin.json
  • ee/maintained-apps/outputs/cleanmymac/darwin.json
  • ee/maintained-apps/outputs/clop/darwin.json
  • ee/maintained-apps/outputs/comet/windows.json
  • ee/maintained-apps/outputs/cursor/darwin.json
  • ee/maintained-apps/outputs/dataflare/darwin.json
  • ee/maintained-apps/outputs/dataflare/windows.json
  • ee/maintained-apps/outputs/datagrip/darwin.json
  • ee/maintained-apps/outputs/datagrip/windows.json
  • ee/maintained-apps/outputs/firefox@developer-edition/darwin.json
  • ee/maintained-apps/outputs/firefox@nightly/darwin.json
  • ee/maintained-apps/outputs/google-ads-editor/windows.json
  • ee/maintained-apps/outputs/granola/darwin.json
  • ee/maintained-apps/outputs/granola/windows.json
  • ee/maintained-apps/outputs/hwmonitor/windows.json
  • ee/maintained-apps/outputs/lookaway/darwin.json
  • ee/maintained-apps/outputs/loom/darwin.json
  • ee/maintained-apps/outputs/loom/windows.json
  • ee/maintained-apps/outputs/macwhisper/darwin.json
  • ee/maintained-apps/outputs/marsedit/darwin.json
  • ee/maintained-apps/outputs/megasync/windows.json
  • ee/maintained-apps/outputs/microsoft-teams/darwin.json
  • ee/maintained-apps/outputs/microsoft-teams/windows.json
  • ee/maintained-apps/outputs/mozilla-vpn/darwin.json
  • ee/maintained-apps/outputs/mozilla-vpn/windows.json
  • ee/maintained-apps/outputs/naps2/darwin.json
  • ee/maintained-apps/outputs/nosql-workbench/darwin.json
  • ee/maintained-apps/outputs/nosql-workbench/windows.json
  • ee/maintained-apps/outputs/obs/darwin.json
  • ee/maintained-apps/outputs/only-switch/darwin.json
  • ee/maintained-apps/outputs/onlyoffice/darwin.json
  • ee/maintained-apps/outputs/popclip/darwin.json
  • ee/maintained-apps/outputs/powerphotos/darwin.json
  • ee/maintained-apps/outputs/powershell/windows.json
  • ee/maintained-apps/outputs/prisma-browser/windows.json
  • ee/maintained-apps/outputs/pritunl/darwin.json
  • ee/maintained-apps/outputs/pritunl/windows.json
  • ee/maintained-apps/outputs/rider/darwin.json
  • ee/maintained-apps/outputs/rustrover/windows.json
  • ee/maintained-apps/outputs/setapp/darwin.json
  • ee/maintained-apps/outputs/snagit/darwin.json
  • ee/maintained-apps/outputs/sourcetree/darwin.json
  • ee/maintained-apps/outputs/superwhisper/darwin.json
  • ee/maintained-apps/outputs/tabby/darwin.json
  • ee/maintained-apps/outputs/trezor-suite/darwin.json
  • ee/maintained-apps/outputs/typora/windows.json
  • ee/maintained-apps/outputs/visual-studio-code/darwin.json
  • ee/maintained-apps/outputs/vivaldi/darwin.json
  • ee/maintained-apps/outputs/wechat/darwin.json
  • ee/maintained-apps/outputs/whatsapp/darwin.json
  • ee/maintained-apps/outputs/workflowy/darwin.json

],
"refs": {
"54ba1114": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local 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)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\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 eval \"export $var_name=0\"\n return\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.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local 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\"\n if [[ \"$was_running\" != \"1\" ]]; 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 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# install pkg files\nquit_and_track_application 'com.naps2.desktop'\nsudo installer -pkg \"$TMPDIR/naps2-8.3.1-mac-arm64.pkg\" -target /\nrelaunch_application 'com.naps2.desktop'\n",
"27c40399": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local 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)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\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 eval \"export $var_name=0\"\n return\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.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local 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\"\n if [[ \"$was_running\" != \"1\" ]]; 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 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# install pkg files\nquit_and_track_application 'com.naps2.desktop'\nsudo installer -pkg \"$TMPDIR/naps2-8.3.2-mac-arm64.pkg\" -target /\nrelaunch_application 'com.naps2.desktop'\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Propagate package-installation failures.

Line 19 ignores the exit status from sudo installer; the later relaunch_application call can make the script exit successfully even when NAPS2 was not installed.

Proposed fix
-sudo installer -pkg "$TMPDIR/naps2-8.3.2-mac-arm64.pkg" -target /
+sudo installer -pkg "$TMPDIR/naps2-8.3.2-mac-arm64.pkg" -target / || exit $?
 relaunch_application 'com.naps2.desktop'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"27c40399": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local 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)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\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 eval \"export $var_name=0\"\n return\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.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local 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\"\n if [[ \"$was_running\" != \"1\" ]]; 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 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# install pkg files\nquit_and_track_application 'com.naps2.desktop'\nsudo installer -pkg \"$TMPDIR/naps2-8.3.2-mac-arm64.pkg\" -target /\nrelaunch_application 'com.naps2.desktop'\n",
# install pkg files
quit_and_track_application 'com.naps2.desktop'
sudo installer -pkg "$TMPDIR/naps2-8.3.2-mac-arm64.pkg" -target / || exit $?
relaunch_application 'com.naps2.desktop'
🤖 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/naps2/darwin.json` at line 19, Capture and
propagate the exit status of the sudo installer command in the installation flow
before calling relaunch_application. Ensure the script exits nonzero when
package installation fails, while preserving the existing relaunch behavior only
for successful installations.

Comment on lines +9 to 10
"installer_url": "https://github.com/ONLYOFFICE/DesktopEditors/releases/download/v9.4.0/ONLYOFFICE-arm.dmg",
"install_script_ref": "5beeff19",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | rg '(^|/)ee/maintained-apps/outputs/onlyoffice/darwin\.json$' || true

echo "== file excerpt =="
if [ -f ee/maintained-apps/outputs/onlyoffice/darwin.json ]; then
  cat -n ee/maintained-apps/outputs/onlyoffice/darwin.json | sed -n '1,80p'
fi

echo "== references to install_script_ref / onlyoffice in repo =="
rg -n '"install_script_ref"|"ONLYOFFICE"|onlyoffice|ONLYOFFICE-dmg|ONLYOFFICE-arm\.dmg' ee maintained-apps .github package.json 2>/dev/null | head -200 || true

echo "== check github asset metadata for cited release =="
python3 - <<'PY'
import json, urllib.request
url='https://api.github.com/repos/ONLYOFFICE/desktop-apps/releases/tags/v9.4.0'
try:
    with urllib.request.urlopen(url, timeout=30) as r:
        data=json.load(r)
    print("release_url", data.get('html_url'))
    print("tag_name", data.get('tag_name'))
    print("assets")
    names=[]
    for a in data.get('assets', []):
        names.append(a.get('name'))
        if a.get('name') in ('ONLYOFFICE-arm.dmg','ONLYOFFICE-x64.dmg','ONLYOFFICE.dmg'):
            print(json.dumps({'name': a.get('name'), 'browser_download_url': a.get('browser_download_url'), 'content_type': a.get('content_type')}, indent=2))
    print("all asset names", names)
except Exception as e:
    print(type(e).__name__, e)
PY

Repository: fleetdm/fleet

Length of output: 25921


🌐 Web query:

ONLYOFFICE DesktopEditors v9.4.0 GitHub release ONLYOFFICE-arm.dmg

💡 Result:

The ONLYOFFICE DesktopEditors v9.4.0 release, published on GitHub on May 19, 2026, does not include an "ONLYOFFICE-arm.dmg" file in its list of official assets [1]. While previous versions of ONLYOFFICE DesktopEditors, such as v9.3.1 [2], v9.2.1 [3], v9.0.3 [4], v8.1.1 [5], and v7.0.0 [6], explicitly included an "ONLYOFFICE-arm.dmg" file, this asset was absent from the v9.4.0 release [1]. Instead, the v9.4.0 release provides alternative formats for ARM-based systems, including "DesktopEditors_arm64.exe", "DesktopEditors_arm64.msi", "DesktopEditors_arm64.zip", and "onlyoffice-desktopeditors_arm64.deb" [1].

Citations:


Point to a real macOS installer and make the install script match it.

ONLYOFFICE-arm.dmg is not available in the v9.4.0 release, so this URL is broken for darwin. If there is a v9.4.0 .dmg, update the installer script to mount it with hdiutil instead of unzip; otherwise use the available macOS archive asset and keep the extraction command compatible with it.

🤖 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/onlyoffice/darwin.json` around lines 9 - 10,
Update the darwin ONLYOFFICE v9.4.0 installer configuration to reference an
actual macOS release asset; use its exact filename in installer_url and update
install_script_ref so extraction matches the asset format, using hdiutil for a
.dmg or the appropriate archive command otherwise.

Source: MCP tools

"refs": {
"b5794400": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local 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)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\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 eval \"export $var_name=0\"\n return\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.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local 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\"\n if [[ \"$was_running\" != \"1\" ]]; 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 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)\nyes | hdiutil attach -plist -nobrowse -readonly -mountpoint \"$MOUNT_POINT\" \"$INSTALLER_PATH\" || exit 1\nsudo cp -R \"$MOUNT_POINT\"/* \"$TMPDIR\"\nhdiutil detach \"$MOUNT_POINT\" || true\n# copy to the applications folder\nquit_and_track_application 'com.jetbrains.rider'\nif [ -d \"$APPDIR/Rider.app\" ]; then\n\tsudo mv \"$APPDIR/Rider.app\" \"$TMPDIR/Rider.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Rider.app\" \"$APPDIR\"\nrelaunch_application 'com.jetbrains.rider'\n",
"c52dae57": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\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\nsudo rm -rf \"$APPDIR/Rider.app\"\nsudo rm -rf 'rider'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Rider2026.1'\ntrash $LOGGED_IN_USER '~/Library/Caches/Rider2026.1'\ntrash $LOGGED_IN_USER '~/Library/Logs/Rider2026.1'\ntrash $LOGGED_IN_USER '~/Library/Preferences/jetbrains.rider.71e559ef.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/Rider2026.1'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.jetbrains.rider.savedState'\n"
"22db20ac": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\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\nsudo rm -rf \"$APPDIR/Rider.app\"\nsudo rm -rf 'rider'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Rider2026.2'\ntrash $LOGGED_IN_USER '~/Library/Caches/Rider2026.2'\ntrash $LOGGED_IN_USER '~/Library/Logs/Rider2026.2'\ntrash $LOGGED_IN_USER '~/Library/Preferences/jetbrains.rider.71e559ef.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/Rider2026.2'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.jetbrains.rider.savedState'\n",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not recursively delete a relative path as root.

Line 19 resolves rider against the script’s current working directory, so an unrelated directory with that name could be deleted. Remove this command or derive a validated absolute path under the intended Rider data/extraction directory.

🤖 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/rider/darwin.json` at line 19, Remove the sudo rm
-rf command targeting the relative “rider” path, or replace it with a validated
absolute path confined to the intended Rider data or extraction directory;
preserve the existing absolute APPDIR cleanup.

"refs": {
"1ba0fd31": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local 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)\n if [[ \"$app_running\" != \"true\" ]]; then\n eval \"export $var_name=0\"\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 eval \"export $var_name=0\"\n return\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.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local 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\"\n if [[ \"$was_running\" != \"1\" ]]; 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 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\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.setapp.DesktopClient.SetappAgent'\nif [ -d \"$APPDIR/Setapp.app\" ]; then\n\tsudo mv \"$APPDIR/Setapp.app\" \"$TMPDIR/Setapp.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Setapp.app\" \"$APPDIR\"\nrelaunch_application 'com.setapp.DesktopClient.SetappAgent'\n",
"e23bd29d": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\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\nsudo rm -rf \"$APPDIR/Setapp.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.setapp.DesktopClient.SetappAgent.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient.SetappAgent'\ntrash $LOGGED_IN_USER '~/Library/Logs/Setapp'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.setapp.DesktopClient.SetappAgent.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.setapp.DesktopClient.savedState'\n"
"9ef05eb6": "#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\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.setapp.DesktopClient.SetappAgent'\nremove_launchctl_service 'com.setapp.DesktopClient.SetappAssistant'\nremove_launchctl_service 'com.setapp.DesktopClient.SetappLauncher'\nremove_launchctl_service 'com.setapp.DesktopClient.SetappUpdater'\nsudo rm -rf \"$APPDIR/Setapp.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.setapp.DesktopClient.SetappAgent.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Setapp*'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.setapp.DesktopClient.SetappAgent'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.setapp.DesktopClient.SetappAgent.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/HTTPStorages/com.setapp.DesktopClient*'\ntrash $LOGGED_IN_USER '~/Library/LaunchAgents/com.setapp.DesktopClient.*plist'\ntrash $LOGGED_IN_USER '~/Library/Logs/Setapp'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.setapp.DesktopClient.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.setapp.DesktopClient.SetappAgent.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.setapp.DesktopClient.savedState'\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Files:"
git ls-files | rg 'ee/maintained-apps/outputs/setapp/darwin.json|setapp|darwin' || true

echo
echo "Target excerpt:"
sed -n '1,80p' ee/maintained-apps/outputs/setapp/darwin.json 2>/dev/null || true

echo
echo "Search for same target script in repo:"
rg -n "SetappAgent|remove_launchctl_service|should_sudo|LOGGED_IN_USER|setapp.DesktopClient" .

Repository: fleetdm/fleet

Length of output: 50370


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json, pathlib
p = pathlib.Path('ee/maintained-apps/outputs/setapp/darwin.json')
if p.exists():
    data = json.loads(p.read_text())
    print(type(data))
    print(data.get('id'))
    print(data.get('os'))
    print(data.get('uninstall'))
    for k,v in data.items():
        if k in {'id','os','uninstall'} or isinstance(v,str) or isinstance(v,dict):
            print(f'{k}: {repr(v)[:500]}')
PY

Repository: fleetdm/fleet

Length of output: 688


Clean up launchd services in the logged-in user’s domain.

When this uninstall runs as root, the should_sudo=false branch makes non-sudo launchctl calls and expands paths with $HOME, which resolves to /var/root for the installer process. Setapp user services can therefore be left loaded or referenced from the wrong LaunchAgents location, causing them to persist after uninstall. Target /Users/$LOGGED_IN_USER for the plist path and invoke removal through the user GUI bootstrap/domain 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/setapp/darwin.json` at line 20, Update
remove_launchctl_service so non-sudo cleanup targets the logged-in user’s domain
rather than the installer’s root environment: build LaunchAgents paths under
/Users/$LOGGED_IN_USER and invoke launchctl removal through that user’s GUI
bootstrap/domain. Keep privileged daemon cleanup and existing wildcard/service
matching behavior unchanged.

"install_script_ref": "1cd57b3a",
"uninstall_script_ref": "b52ff2b2",
"sha256": "5be12e24ecc6e37d2ced0cf082761f296e70aa883863628f41556dad03595d27",
"uninstall_script_ref": "59bfdeae",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Point uninstall_script_ref to an uninstall script.

59bfdeae resolves to the install script at Line 20: it mounts the DMG, copies Snagit.app into /Applications, and relaunches it. An uninstall action will therefore reinstall Snagit instead of removing it. Restore the actual removal reference, such as b52ff2b2 if it remains valid.

Also applies to: 20-20

🤖 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/snagit/darwin.json` at line 11, Update the
uninstall_script_ref entry in the Snagit configuration to reference the actual
uninstall/removal script instead of the install script, using b52ff2b2 if it
remains valid. Ensure the referenced script removes Snagit rather than mounting
the DMG, copying the application, or relaunching it.

@github-actions

Copy link
Copy Markdown
Contributor

Closing in favor of #49804.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants