镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

macOS FMA uninstalls: move trashed files as the user, not root (5/11) - #57090

Merged
allenhouchins merged 1 commit into
mainfrom
allenhouchins/fma-trash-as-user-5
Nov 1, 2026
Merged

allenhouchins merged 1 commit into
mainfrom
allenhouchins/fma-trash-as-user-5

Conversation

@allenhouchins

Copy link
Copy Markdown
Member

Part 5 of 11, split from #56846. That PR changes 992 files, and the auto-approval only covers PRs under 100 files. Part 1, #57086, has the generator change, the tests, the custom scripts, and the frozen outputs; see it for the full explanation. The 11 PRs touch disjoint files, so they merge in any order without conflicts, and together they match #56846's tree exactly. Merge #57086 first.

Change

Generated macOS FMA uninstall scripts now move ~ paths from a cask's zap trash: into the console user's Trash as that user, with sudo -u, instead of as root. Other paths are deleted as root by a new remove_system_path helper, which skips a path when a folder in it below the top level is a symlink.

This PR regenerates 90 macOS outputs, front through julia-app. Each changes only its uninstall script and uninstall_script_ref: no versions, SHAs, URLs, install scripts or queries.

The darwin validator runs on these apps, so expect some failures from apps that had already drifted upstream. The Check Script Diff job will fail here: its comment is over GitHub's 65,536-character limit at this size. It isn't a required check.

Checklist for submitter

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

Testing

AI

AI: Claude Code (claude-opus-5-5)

allenhouchins added a commit that referenced this pull request Nov 1, 2026
…#57086)

Part 1 of 11, split from #56846. That PR changes 992 files, and the
auto-approval only covers PRs under 100 files. The 11 PRs touch disjoint
files, so they merge in any order without conflicts, and together they
match #56846's tree exactly. Merge this one first so the generator
change lands before, or with, the rest of the outputs.

Other parts:
- 2/11: #57087, `aldente` through `captain`
- 3/11: #57088, `capto` through `dia`
- 4/11: #57089, `dialpad` through `free-download-manager`
- 5/11: #57090, `front` through `julia-app`
- 6/11: #57091, `jump-desktop` through `microsoft-excel`
- 7/11: #57092, `microsoft-onenote` through `openboard`
- 8/11: #57093, `opencloud` through `raycast`
- 9/11: #57094, `readest` through `soundsource`
- 10/11: #57095, `sourcetree` through `twingate`
- 11/11: #57096, `typeface` through `zwift`

## Summary

Hardening for the `trash()` helper in generated macOS FMA uninstall
scripts. Fleet runs these scripts as root. `trash()` moved the cask's
`zap` paths into the console user's `~/.Trash` with a root `mv -f`.
Those paths and `~/.Trash` both belong to that user, so root shouldn't
be the one writing there.

- **Paths in the user's home (`~/...`)** are moved to the Trash as the
user, with `sudo -u "$logged_in_user" mv -f`. If the user's move fails,
the script logs `Failed to move <path> to the Trash.` and root doesn't
take over.
- **Other paths** are deleted as root by a new `remove_system_path`
helper instead of being moved into the user's Trash, such as
`/Library/LaunchDaemons/*.plist`, `/Library/PrivilegedHelperTools/*` and
`/Users/Shared/*`. The helper already deleted these at the login window
(#56457).
- **A symlinked parent folder can't redirect a root delete.** `rm -rf`
doesn't follow a symlink at the end of a path, but it does follow one in
a parent folder. For example, a user who creates
`/Users/Shared/TechSmith` as a symlink first could aim Camtasia's
`/Users/Shared/TechSmith/Camtasia` delete at a root-only folder.
`remove_system_path` uses `cd -P` to enter the real parent folder,
checks that it's the folder the path names, and deletes `./<name>` from
there, so a symlink swapped in after the check has no effect. Only
top-level symlinks such as `/tmp` and `/etc` are followed, because users
can't write to `/`. A path that fails the check is left in place and
logged as `Skipped <path>: a folder in its path is a symlink.`
- At the login window, `~` paths are still skipped, and cleanup stays
best-effort: `trash()` never fails the uninstall.

**Behavior change:** system paths listed in a cask's `zap trash:` are
deleted, not moved to the user's Trash. A system path with a symlink in
its parent folders below the top level is skipped.

A shell without Full Disk Access can still move files into `~/.Trash` by
name (only listing it is blocked), so the move as the user doesn't
depend on fleetd's TCC grants.

## Outputs

Across all 11 parts, 974 macOS outputs change. Each changes only its
uninstall script and `uninstall_script_ref`. Version, URL, sha256,
install script and queries are byte-identical to `main`.

This part has the generator, its tests, the 16 custom uninstall scripts,
and 73 outputs:

- **16 custom-script outputs**: each embeds its updated input script.
The custom scripts carry a copy of `trash()`, now the new one plus
`remove_system_path()`, including Citrix Workspace's, added on main in
#57081. `TestCustomUninstallScriptsUseCurrentTrash` keeps both identical
to the generator.
- **20 more frozen outputs**: the ingest job never rewrites these, so
they ship here. (WezTerm is both custom and frozen.)
- **37 generated outputs**, `010-editor` through `alcove`.

Parts 2–11 have the other 901 generated outputs. The outputs were built
and cross-checked against `cmd/maintained-apps` regeneration in #56846.

Because these outputs change, the darwin validator runs on each part's
apps. Expect some failures from apps that had already drifted upstream.
The Check Script Diff job will fail here: its comment is over GitHub's
65,536-character limit at this size. It isn't a required check.

# Checklist for submitter

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.

## Testing

- [x] Added/updated automated tests
- [ ] QA'd all new/changed functionality manually

`TestUninstallScriptTrash` (renamed from
`TestUninstallScriptTrashWithoutGUIUser`) runs generated `trash` calls
in bash with the user's home under a temp dir. A bare `mv` is stubbed to
fail, so the test fails if root ever moves a file. It checks that:
- home paths really land in `~/.Trash` through `sudo -u`
- system paths are deleted
- a system path under a symlinked parent folder, given directly or
through a glob, is skipped, and the files the symlink points to stay in
place
- a failed user move is reported and nothing is removed as root

The test fails against the old helper, and also fails with the symlink
check in `remove_system_path` turned off.

Also checked:
- `go test ./cmd/maintained-apps/... ./ee/maintained-apps/...` passes on
this branch alone, and on each of parts 2–11 alone
- every custom script passes `bash -n`
- run directly on macOS, `remove_system_path` deletes a normal path,
skips one under a symlinked folder, removes a symlink at the end of the
path without touching its target, and follows `/tmp`

Not yet run as root by fleetd on a real Mac.

## AI

**AI:** Claude Code (claude-opus-5-5)
@allenhouchins
allenhouchins marked this pull request as ready for review November 1, 2026 01:50
Copilot AI balanced review requested due to automatic review settings November 1, 2026 01:51
@allenhouchins
allenhouchins merged commit 5491ee0 into main Nov 1, 2026
18 of 19 checks passed
@allenhouchins
allenhouchins deleted the allenhouchins/fma-trash-as-user-5 branch November 1, 2026 01:51

Copilot AI 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.

🔵 Needs a closer look

The scripts recursively delete system paths as root, but fleetd execution on a real Mac remains untested, requiring human validation of user permissions, TCC behavior, and symlink-safe deletion.

No open issues 🎉

What changed in this PR

This PR propagates the macOS uninstall-script hardening from #57086 into Fleet-maintained app outputs as part 5 of the rollout. App versions, download URLs, checksums, and install scripts remain unchanged.

Changes:

  • Move home-directory cleanup targets to the console user’s Trash using sudo -u, without falling back to root.
  • Delete system cleanup targets through remove_system_path, which skips paths with symlinked parent folders below the top level.
  • Refresh embedded uninstall scripts and their references while preserving best-effort cleanup and login-window handling.
File Description
ee/​maintained-apps/​outputs/​jordanbaird-ice/​darwin.json Refresh Ice uninstall helper and reference.
ee/​maintained-apps/​outputs/​intellidock/​darwin.json Refresh IntelliDock uninstall helper and reference.
ee/​maintained-apps/​outputs/​imhex/​darwin.json Refresh ImHex uninstall helper and reference.
ee/​maintained-apps/​outputs/​idagio/​darwin.json Refresh IDAGIO uninstall helper and reference.
ee/​maintained-apps/​outputs/​iconjar/​darwin.json Update IconJar user and shared-directory cleanup.
ee/​maintained-apps/​outputs/​ibm-notifier/​darwin.json Refresh IBM Notifier uninstall helper and reference.
ee/​maintained-apps/​outputs/​hubstaff/​darwin.json Refresh Hubstaff uninstall helper and reference.
ee/​maintained-apps/​outputs/​home-assistant/​darwin.json Update Home Assistant container cleanup helper.
ee/​maintained-apps/​outputs/​highlight-ai/​darwin.json Refresh Highlight uninstall helper and reference.
ee/​maintained-apps/​outputs/​hidock/​darwin.json Refresh HiDock uninstall helper and reference.
ee/​maintained-apps/​outputs/​hides/​darwin.json Update Hides container and wildcard cleanup helper.
ee/​maintained-apps/​outputs/​helium/​darwin.json Refresh Helium uninstall helper and reference.
ee/​maintained-apps/​outputs/​handy/​darwin.json Refresh Handy uninstall helper and reference.
ee/​maintained-apps/​outputs/​goodsync/​darwin.json Update GoodSync user and system cleanup.
ee/​maintained-apps/​outputs/​godot/​darwin.json Refresh Godot uninstall helper and reference.
ee/​maintained-apps/​outputs/​go2shell/​darwin.json Refresh Go2Shell uninstall helper and reference.
ee/​maintained-apps/​outputs/​gitup-app/​darwin.json Update GitUp user-data and wildcard cleanup helper.
ee/​maintained-apps/​outputs/​gimp/​darwin.json Refresh GIMP uninstall helper and reference.
ee/​maintained-apps/​outputs/​geekbench/​darwin.json Update Geekbench user-data and wildcard cleanup helper.
ee/​maintained-apps/​outputs/​geany/​darwin.json Refresh Geany uninstall helper and reference.
ee/​maintained-apps/​outputs/​gather/​darwin.json Refresh Gather uninstall helper and reference.
ee/​maintained-apps/​outputs/​front/​darwin.json Refresh Front uninstall helper and reference.

Review effort: Balanced

This branch was previously deployed

1 inactive deployment
Docker Hub — 1654d35d Deployed Oct 31, 2026 by allenhouchins via publish #111950
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