macOS FMA - Amazon WorkSpaces - #46536
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.
Tip: disable this comment in your organization's Code Review settings.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
WalkthroughThis 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
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 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
📒 Files selected for processing (3)
ee/maintained-apps/inputs/homebrew/amazon-workspaces.jsonee/maintained-apps/outputs/amazon-workspaces/darwin.jsonee/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", |
There was a problem hiding this comment.
🧩 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])
PYRepository: 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" |
There was a problem hiding this comment.
🧩 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" . || trueRepository: 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 || trueRepository: 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 || trueRepository: fleetdm/fleet
Length of output: 50371
Abort the WorkSpaces install when the app doesn’t actually exit.
quit_and_track_applicationcurrently treatstell application id ... to quit+! pgrep -f "$bundle_id"as proof the app is gone, butpgrep -fmatches 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 tosudo 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.
| "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.
|
As long as #46304 ships first, don't need to add a logo to this one. |
Summary by CodeRabbit
New Features
Documentation