Skip to content

Update Fleet-maintained apps#44257

Merged
allenhouchins merged 1 commit intomainfrom
fma-2604272126
Apr 28, 2026
Merged

Update Fleet-maintained apps#44257
allenhouchins merged 1 commit intomainfrom
fma-2604272126

Conversation

@fleet-release
Copy link
Copy Markdown
Contributor

@fleet-release fleet-release commented Apr 27, 2026

Automated ingestion of latest Fleet-maintained app data.

Summary by CodeRabbit

  • Chores
    • Updated maintained-app metadata for 7-Zip (26.01), Discord (0.0.388), Nextcloud (33.0.3), Parallels Desktop (26.3.2), Textexpander (8.4.3), and Zen Browser (1.19.10b) with corresponding installer checksums and references.

Generated automatically with cmd/maintained-apps.
Copy link
Copy Markdown

@claude claude Bot left a comment

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.

@github-actions
Copy link
Copy Markdown
Contributor

Script Diff Results

ee/maintained-apps/outputs/7-zip/windows.json

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

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

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

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

=== Install // 46529a82 -> e8382cb7 ===

--- /tmp/old.ro4Rpu	2026-04-27 21:33:14.683687405 +0000
+++ /tmp/new.l7uG01	2026-04-27 21:33:14.683687405 +0000
@@ -96,5 +96,5 @@
 
 # install pkg files
 quit_and_track_application 'com.nextcloud.desktopclient'
-sudo installer -pkg "$TMPDIR/Nextcloud-33.0.2.pkg" -target /
+sudo installer -pkg "$TMPDIR/Nextcloud-33.0.3.pkg" -target /
 relaunch_application 'com.nextcloud.desktopclient'

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

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

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

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

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

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

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Walkthrough

This pull request updates the maintained-app metadata for six applications across multiple platforms. For each application—7-Zip, Discord, Nextcloud, Parallels, Textexpander, and Zen Browser—the version field is incremented to a newer release. Correspondingly, the version comparison SQL queries used to determine patched status are updated to reference the new version thresholds, installer download URLs are changed to point to the new release artifacts, and SHA256 checksums are replaced with hashes matching the updated installers. Nextcloud additionally includes a new install script reference reflecting the updated target package.

Possibly related PRs

  • Add Zen Browser as a macOS FMA #44126: Updates Zen Browser maintained-app metadata by incrementing the version, patched query, installer URL, and sha256 in the same file.
  • Update Fleet-maintained apps #43822: Modifies Discord and other maintained-app JSON metadata files with version bumps, patched SQL adjustments, installer URL updates, and sha256 replacement.
  • Update Fleet-maintained apps #43920: Updates maintained-app JSON metadata including Discord with version increments, patched query revisions, installer URL changes, and sha256 checksum updates.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is minimal but appropriate for an automated data ingestion change. However, it does not follow the repository's detailed template, missing required checklist items and sections. Add a brief comment explaining that automated updates do not require all template checks, or fill in applicable sections like 'Testing' and 'Changes file' as relevant.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Update Fleet-maintained apps' accurately summarizes the main change: updating metadata for multiple Fleet-maintained applications across different platforms.
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 fma-2604272126

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/maintained-apps/outputs/zen/darwin.json (1)

19-20: ⚠️ Potential issue | 🟠 Major

Change shebangs from #!/bin/sh to #!/bin/bash to match the bash-specific syntax used in both scripts.

Fleet honors shebangs and executes scripts directly using the specified interpreter. When the scripts declare #!/bin/sh but use bash-only features (<<< here-strings, [[ ]] conditionals, local variables, while (( ... )) arithmetic), they will fail on systems where /bin/sh is not bash or where it's executed in strict POSIX mode.

Additionally, sudo rmdir '~/Library/Caches/Mozilla' with single quotes prevents tilde expansion, making this cleanup ineffective. Replace with: sudo rmdir "/Users/$LOGGED_IN_USER/Library/Caches/Mozilla" 2>/dev/null || true

Minimal fixes

For uninstall script (ID 045f019e):

  • Change shebang from #!/bin/sh to #!/bin/bash
  • Fix tilde expansion in the rmdir command

For install script (ID b195d3bf):

  • Change shebang from #!/bin/sh to #!/bin/bash
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/zen/darwin.json` around lines 19 - 20, Update the
two embedded scripts (IDs "045f019e" and "b195d3bf") to use bash by changing
their shebangs from #!/bin/sh to #!/bin/bash because they use bash-only features
(e.g., here-strings, [[ ]], local, (( )) ) — for the uninstall script (045f019e)
also fix the rmdir command that uses a single-quoted tilde: replace the sudo
rmdir '~/Library/Caches/Mozilla' with a form that expands the logged-in user
(use LOGGED_IN_USER, e.g., rmdir "/Users/$LOGGED_IN_USER/Library/Caches/Mozilla"
and suppress errors with 2>/dev/null || true) so the cleanup actually targets
the correct path; the install script (b195d3bf) only needs its shebang updated
(functions to inspect: trash, quit_and_track_application, relaunch_application).
🧹 Nitpick comments (3)
ee/maintained-apps/outputs/discord/darwin.json (2)

9-9: Installer URL update: verify artifact stability and naming.

installer_url now points to https://dl.discordapp.net/apps/osx/0.0.388/Discord.dmg. Ensure that:

  • the DMG actually exists at that path, and
  • the file name/path matches what your installer download logic expects (some projects are sensitive to case/filenames).

This is likely correct given the coordinated version/sha update, but it’s worth validating during release cut.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/discord/darwin.json` at line 9, Verify that the
new installer_url value ("installer_url" in
ee/maintained-apps/outputs/discord/darwin.json) points to an existing DMG and
that its exact filename/case ("Discord.dmg" at path /apps/osx/0.0.388/) matches
what the installer download logic expects; during release cut, perform a HEAD
GET to confirm the artifact is present, ensure any code that parses or
constructs the URL (installer download logic / file name normalization) accepts
the exact casing/path, and if checksums or coordinated sha/version fields exist
for Discord in the same output, validate those align with the DMG returned by
the server.

19-20: Shell scripts declare #!/bin/sh but use bashisms—make interpreter explicit.

Both refs["10be5baa"] (line 19) and refs["8ed76f08"] (line 20) are declared as #!/bin/sh, but the script bodies include bash-style constructs such as:

  • [[ ... ]]
  • local ...
  • the SECONDS variable

On macOS this may currently “work” depending on what /bin/sh points to, but it’s a portability/reliability risk. Recommended fix: change shebang to #!/bin/bash (or rewrite to POSIX sh).

♻️ Suggested diff (explicit bash shebang)
-"#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_and_track_application() {\n"
+"#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_and_track_application() {\n"
-"#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n"
+"#!/bin/bash\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n"

To verify bashisms exist in these refs, a quick static check is:

  • search for #!/bin/sh plus [[ within the same ref blocks.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/discord/darwin.json` around lines 19 - 20, The
scripts in refs["10be5baa"] and refs["8ed76f08"] use bash-only constructs (eg.
[[ ... ]], local declarations, SECONDS) while declaring #!/bin/sh; update the
shebang lines in those two refs to #!/bin/bash (or else refactor functions like
quit_and_track_application, relaunch_application, and trash to be strictly
POSIX-compliant) so the bashisms are supported reliably on macOS.
ee/maintained-apps/outputs/zen/darwin.json (1)

20-20: Quote $INSTALLER_PATH when passing to realpath.

Install script line 20 contains realpath $INSTALLER_PATH without quotes. If INSTALLER_PATH ever contains spaces (or other shell-special characters), realpath and dirname will receive broken arguments.

🛠️ Proposed fix
-  TMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")
+  TMPDIR=$(dirname \"$(realpath \"$INSTALLER_PATH\")\")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/zen/darwin.json` at line 20, The TMPDIR assignment
uses unquoted $INSTALLER_PATH in the realpath call which breaks on paths with
spaces; update the TMPDIR line (the assignment that sets TMPDIR using dirname
and realpath) to quote INSTALLER_PATH so realpath receives a single argument
(i.e., call realpath "$INSTALLER_PATH") to ensure correct behavior when
INSTALLER_PATH contains spaces or special characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ee/maintained-apps/outputs/nextcloud/darwin.json`:
- Line 20: The TMPDIR assignment and installer invocation mishandle quoting and
a hardcoded package name: update the TMPDIR line that uses INSTALLER_PATH
(TMPDIR=$(dirname "$(realpath $INSTALLER_PATH)") ) to quote $INSTALLER_PATH
properly (use "$(realpath "$INSTALLER_PATH")"), and change the installer
invocation (the sudo installer -pkg ... line) to install the actual downloaded
file instead of the hardcoded "Nextcloud-33.0.3.pkg" (e.g., reference the
package path built from TMPDIR and the installer filename variable or glob), and
while editing consider replacing eval usage in
quit_and_track_application/relaunch_application that sets APP_WAS_RUNNING_* with
a safer associative or explicit variable assignment to avoid eval.
- Around line 9-12: The installer_url currently points to the unreleased v33.0.3
artifact (installer_url) which will 404; update installer_url to reference the
latest publicly released tag (e.g., v33.0.2) or another stable release, and
update the corresponding sha256 value to the checksum for that released package;
also verify and adjust install_script_ref and uninstall_script_ref if they
depend on the released tag so they match the chosen stable version.

---

Outside diff comments:
In `@ee/maintained-apps/outputs/zen/darwin.json`:
- Around line 19-20: Update the two embedded scripts (IDs "045f019e" and
"b195d3bf") to use bash by changing their shebangs from #!/bin/sh to #!/bin/bash
because they use bash-only features (e.g., here-strings, [[ ]], local, (( )) ) —
for the uninstall script (045f019e) also fix the rmdir command that uses a
single-quoted tilde: replace the sudo rmdir '~/Library/Caches/Mozilla' with a
form that expands the logged-in user (use LOGGED_IN_USER, e.g., rmdir
"/Users/$LOGGED_IN_USER/Library/Caches/Mozilla" and suppress errors with
2>/dev/null || true) so the cleanup actually targets the correct path; the
install script (b195d3bf) only needs its shebang updated (functions to inspect:
trash, quit_and_track_application, relaunch_application).

---

Nitpick comments:
In `@ee/maintained-apps/outputs/discord/darwin.json`:
- Line 9: Verify that the new installer_url value ("installer_url" in
ee/maintained-apps/outputs/discord/darwin.json) points to an existing DMG and
that its exact filename/case ("Discord.dmg" at path /apps/osx/0.0.388/) matches
what the installer download logic expects; during release cut, perform a HEAD
GET to confirm the artifact is present, ensure any code that parses or
constructs the URL (installer download logic / file name normalization) accepts
the exact casing/path, and if checksums or coordinated sha/version fields exist
for Discord in the same output, validate those align with the DMG returned by
the server.
- Around line 19-20: The scripts in refs["10be5baa"] and refs["8ed76f08"] use
bash-only constructs (eg. [[ ... ]], local declarations, SECONDS) while
declaring #!/bin/sh; update the shebang lines in those two refs to #!/bin/bash
(or else refactor functions like quit_and_track_application,
relaunch_application, and trash to be strictly POSIX-compliant) so the bashisms
are supported reliably on macOS.

In `@ee/maintained-apps/outputs/zen/darwin.json`:
- Line 20: The TMPDIR assignment uses unquoted $INSTALLER_PATH in the realpath
call which breaks on paths with spaces; update the TMPDIR line (the assignment
that sets TMPDIR using dirname and realpath) to quote INSTALLER_PATH so realpath
receives a single argument (i.e., call realpath "$INSTALLER_PATH") to ensure
correct behavior when INSTALLER_PATH contains spaces or special characters.
🪄 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: 1c89bede-9c8f-4474-a038-849278726979

📥 Commits

Reviewing files that changed from the base of the PR and between 899dc5a and 7a63645.

📒 Files selected for processing (6)
  • ee/maintained-apps/outputs/7-zip/windows.json
  • ee/maintained-apps/outputs/discord/darwin.json
  • ee/maintained-apps/outputs/nextcloud/darwin.json
  • ee/maintained-apps/outputs/parallels/darwin.json
  • ee/maintained-apps/outputs/textexpander/darwin.json
  • ee/maintained-apps/outputs/zen/darwin.json

Comment on lines +9 to +12
"installer_url": "https://github.com/nextcloud-releases/desktop/releases/download/v33.0.3/Nextcloud-33.0.3.pkg",
"install_script_ref": "e8382cb7",
"uninstall_script_ref": "2614231b",
"sha256": "c1cd72fef13708fbd61ff668df5bde89355466a9fa3cef80996a10f6af9654f0",
"sha256": "f0ccf66d1a871cfcc8bf5124949449734b26e64e9f06532924aa62258df73365",
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, read the file to confirm the content
cat -n "ee/maintained-apps/outputs/nextcloud/darwin.json" | sed -n '1,20p'

Repository: fleetdm/fleet

Length of output: 10755


🏁 Script executed:

#!/bin/bash
# Download the Nextcloud installer and compute its SHA256 hash
URL="https://github.com/nextcloud-releases/desktop/releases/download/v33.0.3/Nextcloud-33.0.3.pkg"
EXPECTED_HASH="f0ccf66d1a871cfcc8bf5124949449734b26e64e9f06532924aa62258df73365"

echo "Downloading: $URL"
curl -sL --max-redirs 5 -o /tmp/Nextcloud-33.0.3.pkg "$URL" 2>&1 | head -20

if [ -f /tmp/Nextcloud-33.0.3.pkg ]; then
  ACTUAL_HASH=$(sha256sum /tmp/Nextcloud-33.0.3.pkg | awk '{print $1}')
  echo ""
  echo "Downloaded file size: $(stat -f%z /tmp/Nextcloud-33.0.3.pkg 2>/dev/null || stat -c%s /tmp/Nextcloud-33.0.3.pkg)"
  echo "Expected SHA256: $EXPECTED_HASH"
  echo "Actual SHA256:   $ACTUAL_HASH"
  echo ""
  if [ "$ACTUAL_HASH" = "$EXPECTED_HASH" ]; then
    echo "✓ MATCH: Hash verification successful"
  else
    echo "✗ MISMATCH: Hash does not match"
  fi
else
  echo "Failed to download file"
fi

Repository: fleetdm/fleet

Length of output: 431


🏁 Script executed:

#!/bin/bash
# Search for references to this version and hash in the codebase
echo "=== Searching for v33.0.3 references ==="
rg "33\.0\.3" --max-count 20

echo -e "\n=== Searching for the SHA256 hash ==="
rg "f0ccf66d1a871cfcc8bf5124949449734b26e64e9f06532924aa62258df73365" --max-count 5

echo -e "\n=== Searching for Nextcloud version files ==="
fd "nextcloud" -t f | head -20

Repository: fleetdm/fleet

Length of output: 7596


🌐 Web query:

Nextcloud desktop v33.0.3 release sha256 hash

💡 Result:

No SHA256 hash found for Nextcloud desktop client version 33.0.3. Searches across GitHub releases (nextcloud/desktop and nextcloud-releases/desktop), Nextcloud websites, and general web did not locate a release page or assets for v33.0.3. Latest found releases are v33.0.2 (published March 31, 2026) with binaries like Nextcloud-33.0.2-x86_64.AppImage (170886 KB), but no SHA256 checksums provided there either—only .asc PGP signatures. Milestone 117 for 33.0.3 exists but shows incomplete status as of early April 2026. On today's date (2026-04-27), v33.0.3 may not be publicly released yet, or hashes are not published in standard locations.

Citations:


The installer URL references a non-existent release; v33.0.3 is not yet publicly available.

The URL https://github.com/nextcloud-releases/desktop/releases/download/v33.0.3/Nextcloud-33.0.3.pkg points to a release that is not publicly available. As of April 2026, the latest released version is v33.0.2 (March 31, 2026), and v33.0.3 milestone shows incomplete status. This means the install pipeline will fail with a 404 error when attempting to download the artifact, regardless of the hash value. The version must either be released publicly before this configuration can work, or the configuration should reference v33.0.2 or an earlier stable version.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/nextcloud/darwin.json` around lines 9 - 12, The
installer_url currently points to the unreleased v33.0.3 artifact
(installer_url) which will 404; update installer_url to reference the latest
publicly released tag (e.g., v33.0.2) or another stable release, and update the
corresponding sha256 value to the checksum for that released package; also
verify and adjust install_script_ref and uninstall_script_ref if they depend on
the released tag so they match the chosen stable version.

"refs": {
"2614231b": "#!/bin/sh\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\nquit_application() {\n local bundle_id=\"$1\"\n local timeout_duration=10\n\n # check if the application is running\n local app_running\n app_running=$(osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null)\n if [[ \"$app_running\" != \"true\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ -z \"$console_user\" || \"$console_user\" == \"root\" || \"$console_user\" == \"loginwindow\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nremove_launchctl_service() {\n local service=\"$1\"\n local booleans=(\"true\" \"false\")\n local plist_status\n local paths\n local should_sudo\n\n echo \"Removing launchctl service ${service}\"\n\n 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.nextcloud.desktopclient'\nquit_application 'com.nextcloud.desktopclient'\nremove_pkg_files 'com.nextcloud.desktopclient'\nforget_pkg 'com.nextcloud.desktopclient'\nsudo rm -rf '/Applications/Nextcloud.app'\ntrash $LOGGED_IN_USER '~/Library/Application Scripts/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Application Support/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Caches/Nextcloud'\ntrash $LOGGED_IN_USER '~/Library/Containers/com.nextcloud.desktopclient.FinderSyncExt'\ntrash $LOGGED_IN_USER '~/Library/Group Containers/com.nextcloud.desktopclient'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.nextcloud.desktopclient.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/Nextcloud'\n",
"46529a82": "#!/bin/sh\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.nextcloud.desktopclient'\nsudo installer -pkg \"$TMPDIR/Nextcloud-33.0.2.pkg\" -target /\nrelaunch_application 'com.nextcloud.desktopclient'\n"
"e8382cb7": "#!/bin/sh\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.nextcloud.desktopclient'\nsudo installer -pkg \"$TMPDIR/Nextcloud-33.0.3.pkg\" -target /\nrelaunch_application 'com.nextcloud.desktopclient'\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

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file structure and content
cat -n ee/maintained-apps/outputs/nextcloud/darwin.json | head -30

Repository: fleetdm/fleet

Length of output: 10775


🏁 Script executed:

# Let's get the full content of the e8382cb7 key value to see the actual script
jq -r '.e8382cb7' ee/maintained-apps/outputs/nextcloud/darwin.json | head -50

Repository: fleetdm/fleet

Length of output: 62


🏁 Script executed:

# Let's check the entire script to understand the context better
jq -r '.e8382cb7' ee/maintained-apps/outputs/nextcloud/darwin.json | wc -l

Repository: fleetdm/fleet

Length of output: 59


🏁 Script executed:

# Extract and display the actual script content cleanly to verify
jq -r '.refs.e8382cb7' ee/maintained-apps/outputs/nextcloud/darwin.json | sed -n '2,7p'

Repository: fleetdm/fleet

Length of output: 155


🏁 Script executed:

# Search for TMPDIR usage in the script to understand full context
jq -r '.refs.e8382cb7' ee/maintained-apps/outputs/nextcloud/darwin.json | grep -n "TMPDIR\|INSTALLER_PATH"

Repository: fleetdm/fleet

Length of output: 171


Fix $INSTALLER_PATH quoting and hardcoded filename in install script.

In the e8382cb7 install script:

  • TMPDIR=$(dirname "$(realpath $INSTALLER_PATH)")$INSTALLER_PATH is unquoted, risking failures if the path contains spaces or is unset.
  • sudo installer -pkg "$TMPDIR/Nextcloud-33.0.3.pkg" -target / — hardcoded filename couples the script to a specific package version; if Fleet downloads the file under a different name, installation fails even with a correct hash.

The minimal fix is to quote the variable and install the file directly:

Suggested patch
- TMPDIR=$(dirname "$(realpath $INSTALLER_PATH)")
+ TMPDIR=$(dirname "$(realpath "$INSTALLER_PATH")")
...
- sudo installer -pkg "$TMPDIR/Nextcloud-33.0.3.pkg" -target /
+ sudo installer -pkg "$INSTALLER_PATH" -target /

Secondary: The script uses eval to set variables derived from bundle_id. While the bundle ID is hardcoded here (low exploitability risk), removing eval would improve maintainability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/outputs/nextcloud/darwin.json` at line 20, The TMPDIR
assignment and installer invocation mishandle quoting and a hardcoded package
name: update the TMPDIR line that uses INSTALLER_PATH (TMPDIR=$(dirname
"$(realpath $INSTALLER_PATH)") ) to quote $INSTALLER_PATH properly (use
"$(realpath "$INSTALLER_PATH")"), and change the installer invocation (the sudo
installer -pkg ... line) to install the actual downloaded file instead of the
hardcoded "Nextcloud-33.0.3.pkg" (e.g., reference the package path built from
TMPDIR and the installer filename variable or glob), and while editing consider
replacing eval usage in quit_and_track_application/relaunch_application that
sets APP_WAS_RUNNING_* with a safer associative or explicit variable assignment
to avoid eval.

@allenhouchins allenhouchins merged commit ba1dbe2 into main Apr 28, 2026
8 checks passed
@allenhouchins allenhouchins deleted the fma-2604272126 branch April 28, 2026 01:42
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