Skip to content

macOS FMA - Amazon WorkSpaces - #46536

Merged
allenhouchins merged 2 commits into
mainfrom
macos-amazon-workspaces-fma
Jun 1, 2026
Merged

macOS FMA - Amazon WorkSpaces#46536
allenhouchins merged 2 commits into
mainfrom
macos-amazon-workspaces-fma

Conversation

@harrisonravazzolo

@harrisonravazzolo harrisonravazzolo commented Jun 1, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added Amazon WorkSpaces support on macOS (version 5.32.0.6080) with installation and uninstallation workflows.
    • App now appears in the apps list for macOS.
  • Documentation

    • Updated Amazon WorkSpaces description for the existing Windows entry.

@harrisonravazzolo
harrisonravazzolo marked this pull request as ready for review June 1, 2026 00:19

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

@harrisonravazzolo

Copy link
Copy Markdown
Member Author

#46249

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bdaedace-47cb-4d32-9c33-d956f7fc646a

📥 Commits

Reviewing files that changed from the base of the PR and between ac471ee and 064d2c6.

📒 Files selected for processing (1)
  • ee/maintained-apps/outputs/apps.json
✅ Files skipped from review due to trivial changes (1)
  • ee/maintained-apps/outputs/apps.json

Walkthrough

This PR adds Amazon WorkSpaces as a managed application to Fleet: input metadata for the app, a macOS implementation (version 5.32.0.6080) with SQL detection queries, installer download URL, checksum, and embedded Bash install/uninstall scripts, and a registry entry in the central apps list (including a revised Windows description).

Possibly related PRs

  • fleetdm/fleet#46304: Adds Amazon WorkSpaces metadata entries to the maintained-apps manifests, overlapping with this PR's additions to the same manifests.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request lacks a description entirely, violating the required template structure which mandates sections for issue references, checklists, testing, and verification steps. Add a comprehensive pull request description following the provided template, including related issue reference (#46249), relevant checklist items, and verification details.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding macOS support for Amazon WorkSpaces in the maintained apps configuration.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch macos-amazon-workspaces-fma

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 and usage tips.

@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: 2

🤖 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/amazon-workspaces/darwin.json`:
- Line 19: remove_launchctl_service() currently uses $HOME for the non-sudo
branch and calls launchctl without domain qualifiers which causes it to target
/var/root when run as root; change it to use the console user (LOGGED_IN_USER)
and their UID (id -u "$LOGGED_IN_USER") to build per-user paths
(/Users/$LOGGED_IN_USER/Library/LaunchAgents/...) instead of prepending $HOME,
and update launchctl removal to explicitly target both system and
gui/<console_uid> domains (e.g., sudo launchctl remove
com.amazon.workspaces.updater for system and sudo launchctl remove
gui/<UID>/com.amazon.workspaces.updater for the user session), ensuring file
removals use /Users/$LOGGED_IN_USER paths and appropriate sudo where needed.
- Line 20: The quit_and_track_application function should reliably detect
whether the app actually exited and prevent continuing the install when it
didn't: replace the pgrep-based check with osascript-based verification (use the
same osascript invocation you used earlier: osascript -e "application id
\"${bundle_id}\" is running") inside the quit loop to set quit_success only when
that returns false, and have quit_and_track_application return a non-zero status
(or set a distinct failure flag) when the quit times out; then, before calling
sudo installer -pkg ..., check the exit status/flag from
quit_and_track_application and abort the installation (echo an error and exit 1)
if the app failed to quit. Use the function names quit_and_track_application and
relaunch_application to locate and change the logic.
🪄 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: 098bcc58-2611-4e77-b17f-29c17b3759c9

📥 Commits

Reviewing files that changed from the base of the PR and between 1f934e1 and ac471ee.

📒 Files selected for processing (3)
  • ee/maintained-apps/inputs/homebrew/amazon-workspaces.json
  • ee/maintained-apps/outputs/amazon-workspaces/darwin.json
  • ee/maintained-apps/outputs/apps.json

}
],
"refs": {
"c393d9c9": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\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 for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.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}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\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 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.amazon.workspaces.updater'\nremove_pkg_files 'com.amazon.workspaces'\nforget_pkg 'com.amazon.workspaces'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Amazon Web Services/Amazon WorkSpaces'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.amazon.workspaces'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.amazon.workspaces.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.amazon.workspaces.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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n --hidden --no-ignore-vcs "com\.amazon\.workspaces\.updater" . || true
rg -n --hidden --no-ignore-vcs "workspaces\.updater(\.plist)?|workspaces.*updater" . || true
rg -n --hidden --no-ignore-vcs "LaunchAgents/|LaunchDaemons/|launchctl (remove|bootout)" ee/maintained-apps/outputs/amazon-workspaces . || true
rg -n --hidden --no-ignore-vcs "amazon-workspaces" ee/maintained-apps . || true

# show the relevant embedded uninstall script chunk around remove_launchctl_service
python3 - <<'PY'
import json, re, pathlib
p = pathlib.Path("ee/maintained-apps/outputs/amazon-workspaces/darwin.json")
data = p.read_text(encoding="utf-8")
m = re.search(r'remove_launchctl_service\(\)[\s\S]{0,5000}', data)
print("FOUND remove_launchctl_service:", bool(m))
if m:
    print(data[m.start()-200:m.start()+2000])
PY

Repository: fleetdm/fleet

Length of output: 50370


Target the console user’s launch agent in remove_launchctl_service() (don’t rely on $HOME)

In ee/maintained-apps/outputs/amazon-workspaces/darwin.json, remove_launchctl_service() deletes "$HOME/Library/LaunchAgents|LaunchDaemons/${service}.plist" in the non-sudo branch, but LOGGED_IN_USER is never used—so if the uninstall runs as root it will operate on /var/root/Library/... rather than the console user’s ~/Library/.... It also calls launchctl remove "${service}" without a domain/session qualifier; use domain-scoped removal (e.g., system and gui/<console_uid>) for the updater job.

🤖 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/amazon-workspaces/darwin.json` at line 19,
remove_launchctl_service() currently uses $HOME for the non-sudo branch and
calls launchctl without domain qualifiers which causes it to target /var/root
when run as root; change it to use the console user (LOGGED_IN_USER) and their
UID (id -u "$LOGGED_IN_USER") to build per-user paths
(/Users/$LOGGED_IN_USER/Library/LaunchAgents/...) instead of prepending $HOME,
and update launchctl removal to explicitly target both system and
gui/<console_uid> domains (e.g., sudo launchctl remove
com.amazon.workspaces.updater for system and sudo launchctl remove
gui/<UID>/com.amazon.workspaces.updater for the user session), ensuring file
removals use /Users/$LOGGED_IN_USER paths and appropriate sudo where needed.

],
"refs": {
"c393d9c9": "#!/bin/bash\n\n# variables\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\nexpand_pkgid_and_map() {\n local PKGID=\"$1\"\n local FUNC=\"$2\"\n if [[ \"$PKGID\" == *\"*\" ]]; then\n local prefix=\"${PKGID%\\*}\"\n echo \"Expanding wildcard for PKGID: $PKGID\"\n for receipt in $(pkgutil --pkgs | grep \"^${prefix}\"); do\n echo \"Processing $receipt\"\n \"$FUNC\" \"$receipt\"\n done\n else\n \"$FUNC\" \"$PKGID\"\n fi\n}\n\nforget_pkg() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" forget_receipt\n}\n\nforget_receipt() {\n local PKGID=\"$1\"\n sudo pkgutil --forget \"$PKGID\"\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 for should_sudo in \"${booleans[@]}\"; do\n plist_status=$(launchctl list \"${service}\" 2>/dev/null)\n\n if [[ $plist_status == \\{* ]]; then\n if [[ $should_sudo == \"true\" ]]; then\n sudo launchctl remove \"${service}\"\n else\n launchctl remove \"${service}\"\n fi\n sleep 1\n fi\n\n paths=(\n \"/Library/LaunchAgents/${service}.plist\"\n \"/Library/LaunchDaemons/${service}.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}\n\nremove_pkg_files() {\n local PKGID=\"$1\"\n expand_pkgid_and_map \"$PKGID\" remove_receipt_files\n}\n\nremove_receipt_files() {\n local PKGID=\"$1\"\n local PKGINFO VOLUME INSTALL_LOCATION FULL_INSTALL_LOCATION\n\n echo \"pkgutil --pkg-info-plist \\\"$PKGID\\\"\"\n PKGINFO=$(pkgutil --pkg-info-plist \"$PKGID\")\n VOLUME=$(echo \"$PKGINFO\" | awk '/<key>volume<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n INSTALL_LOCATION=$(echo \"$PKGINFO\" | awk '/<key>install-location<\\/key>/ {getline; gsub(/.*<string>|<\\/string>.*/, \"\"); print}')\n\n if [ -z \"$INSTALL_LOCATION\" ] || [ \"$INSTALL_LOCATION\" = \"/\" ]; then\n FULL_INSTALL_LOCATION=\"$VOLUME\"\n else\n FULL_INSTALL_LOCATION=\"$VOLUME/$INSTALL_LOCATION\"\n FULL_INSTALL_LOCATION=$(echo \"$FULL_INSTALL_LOCATION\" | sed 's|//|/|g')\n fi\n\n echo \"sudo pkgutil --only-files --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-files --files \"$PKGID\" | sed \"s|^|/${INSTALL_LOCATION}/|\" | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n echo \"sudo pkgutil --only-dirs --files \\\"$PKGID\\\" | sed \\\"s|^|${FULL_INSTALL_LOCATION}/|\\\" | grep '\\\\.app$' | tr '\\\\\\\\n' '\\\\\\\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\"\n sudo pkgutil --only-dirs --files \"$PKGID\" | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" | grep '\\.app$' | tr '\\n' '\\0' | /usr/bin/sudo -u root -E -- /usr/bin/xargs -0 -- /bin/rm -rf\n\n root_app_dir=$(\n sudo pkgutil --only-dirs --files \"$PKGID\" \\\n | sed \"s|^|${FULL_INSTALL_LOCATION}/|\" \\\n | grep 'Applications' \\\n | awk '{ print length, $0 }' \\\n | sort -n \\\n | head -n1 \\\n | cut -d' ' -f2-\n )\n if [ -n \"$root_app_dir\" ]; then\n echo \"sudo rmdir -p \\\"$root_app_dir\\\" 2>/dev/null || :\"\n sudo rmdir -p \"$root_app_dir\" 2>/dev/null || :\n fi\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 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.amazon.workspaces.updater'\nremove_pkg_files 'com.amazon.workspaces'\nforget_pkg 'com.amazon.workspaces'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Amazon Web Services/Amazon WorkSpaces'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.amazon.workspaces'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.amazon.workspaces.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.amazon.workspaces.savedState'\n",
"d33e4ee6": "#!/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# install pkg files\nquit_and_track_application 'com.amazon.workspaces'\nsudo installer -pkg \"$TMPDIR/WorkSpaces.pkg\" -target /\nrelaunch_application 'com.amazon.workspaces'\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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="ee/maintained-apps/outputs/amazon-workspaces/darwin.json"

echo "== file =="
ls -la "$FILE"
echo

echo "== surrounding lines (numbered) =="
# Print lines 1-120 (JSON likely small)
nl -ba "$FILE" | sed -n '1,140p'

echo
echo "== extract embedded script =="
# Extract the big bash string value roughly by grabbing between first and last " characters after key, naive:
# Use node to parse JSON safely if possible; fall back to grep.
if command -v node >/dev/null 2>&1; then
  node <<'NODE'
const fs=require('fs');
const p=process.argv[1];
const txt=fs.readFileSync(p,'utf8');
const j=JSON.parse(txt);
for (const [k,v] of Object.entries(j)) {
  console.log("key:", k);
  console.log(String(v).split("\n").slice(0,200).join("\n"));
  break;
}
NODE "$FILE"
else
  # fallback: show a chunk around "quit_and_track_application"
  rg -n "quit_and_track_application|pgrep -f|application id.*is running" "$FILE" || true
fi

echo
echo "== search for pgrep -f usage with bundle_id in repo =="
rg -n "pgrep -f\s+\"?\$bundle_id\"?|pgrep -f.*bundle_id" . || true

echo
echo "== search for osascript 'application id ... is running' usage in repo =="
rg -n "application id.* is running" . || true

Repository: fleetdm/fleet

Length of output: 272


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="ee/maintained-apps/outputs/amazon-workspaces/darwin.json"

echo "== surrounding JSON lines (1-120) =="

python3 - <<PY
import pathlib
p=pathlib.Path("$FILE")
lines=p.read_text(encoding="utf-8").splitlines()
for i,l in enumerate(lines[:120], start=1):
    print(f"{i:4d}\t{l}")
PY

echo
echo "== extract first script-like value from JSON (show only relevant matches) =="
python3 - <<PY
import json, pathlib, re
p=pathlib.Path("$FILE")
j=json.loads(p.read_text(encoding="utf-8"))
text=None
for k,v in j.items():
    if isinstance(v,str) and "quit_and_track_application" in v:
        text=v
        print("found key:", k)
        break
if not text:
    # fallback: pick first string value
    for k,v in j.items():
        if isinstance(v,str):
            text=v
            print("fallback key:", k)
            break
print("len(script):", len(text or ""))
for pat in [
    r'pgrep -f .*\\$bundle_id',
    r'pgrep -f .*bundle_id',
    r'application id .* is running',
    r'tell application id .* to quit'
]:
    m=re.findall(pat, text or "", flags=re.MULTILINE)
    print(pat, "=>", m[:3], ("..." if len(m)>3 else ""))
PY

echo
echo "== repo-wide check in ee/maintained-apps for same pattern =="

rg -n --hidden --no-ignore -S "quit_and_track_application|pgrep -f .*bundle_id|application id .*is running" ee/maintained-apps || true

Repository: fleetdm/fleet

Length of output: 9459


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="ee/maintained-apps/outputs/amazon-workspaces/darwin.json"

python3 - <<'PY'
import json, pathlib
p=pathlib.Path("ee/maintained-apps/outputs/amazon-workspaces/darwin.json")
j=json.loads(p.read_text(encoding="utf-8"))
script=j["refs"]["d33e4ee6"]
# Print only the relevant section
start=script.find("quit_and_track_application()")
end=script.find("}\n\n\nrelaunch_application()")
print(script[start:end+2])
PY

echo "---- repo search: pgrep -f with bundle_id ----"
rg -n "pgrep -f.*bundle_id" ee || true

echo "---- repo search: pgrep -f with hard-coded bundle id strings ----"
rg -n "pgrep -f.*com\." ee || true

echo "---- repo search: osascript application id ... is running patterns ----"
rg -n "application id .* is running" ee || true

Repository: fleetdm/fleet

Length of output: 50371


Abort the WorkSpaces install when the app doesn’t actually exit.

  • quit_and_track_application currently treats tell application id ... to quit + ! pgrep -f "$bundle_id" as proof the app is gone, but pgrep -f matches process command lines (not bundle IDs), so it can succeed early.
  • If the quit times out, the function only logs Application '$bundle_id' did not quit. and still allows the script to continue to sudo installer ... unconditionally.
Possible fix
 quit_and_track_application() {
   local bundle_id="$1"
   local var_name="APP_WAS_RUNNING_$(echo "$bundle_id" | tr '.-' '__')"
   local timeout_duration=10
@@
   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
+    osascript -e "tell application id \"$bundle_id\" to quit" >/dev/null 2>&1 || true
+    app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null || echo false)
+    if [[ "$app_running" != "true" ]]; then
+      echo "Application '$bundle_id' quit successfully."
+      quit_success=true
+      break
+    fi
     sleep 1
   done
 
   if [[ "$quit_success" = false ]]; then
     echo "Application '$bundle_id' did not quit."
+    return 1
   fi
 }
@@
-quit_and_track_application 'com.amazon.workspaces'
+quit_and_track_application 'com.amazon.workspaces' || exit 1
 sudo installer -pkg "$TMPDIR/WorkSpaces.pkg" -target /
📝 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
"d33e4ee6": "#!/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# install pkg files\nquit_and_track_application 'com.amazon.workspaces'\nsudo installer -pkg \"$TMPDIR/WorkSpaces.pkg\" -target /\nrelaunch_application 'com.amazon.workspaces'\n"
"d33e4ee6": "#!/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 osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1 || true\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null || echo false)\n if [[ \"$app_running\" != \"true\" ]]; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n return 1\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# install pkg files\nquit_and_track_application 'com.amazon.workspaces' || exit 1\nsudo installer -pkg \"$TMPDIR/WorkSpaces.pkg\" -target /\nrelaunch_application 'com.amazon.workspaces'\n"
🤖 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/amazon-workspaces/darwin.json` at line 20, The
quit_and_track_application function should reliably detect whether the app
actually exited and prevent continuing the install when it didn't: replace the
pgrep-based check with osascript-based verification (use the same osascript
invocation you used earlier: osascript -e "application id \"${bundle_id}\" is
running") inside the quit loop to set quit_success only when that returns false,
and have quit_and_track_application return a non-zero status (or set a distinct
failure flag) when the quit times out; then, before calling sudo installer -pkg
..., check the exit status/flag from quit_and_track_application and abort the
installation (echo an error and exit 1) if the app failed to quit. Use the
function names quit_and_track_application and relaunch_application to locate and
change the logic.

@harrisonravazzolo

Copy link
Copy Markdown
Member Author

As long as #46304 ships first, don't need to add a logo to this one.

@allenhouchins
allenhouchins merged commit 71a82d0 into main Jun 1, 2026
14 checks passed
@allenhouchins
allenhouchins deleted the macos-amazon-workspaces-fma branch June 1, 2026 13:40
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.

3 participants