Skip to content

fix: handle protected app uninstall removals#103

Merged
momenbasel merged 1 commit into
momenbasel:mainfrom
brainx:codex/fix-issue-93
May 23, 2026
Merged

fix: handle protected app uninstall removals#103
momenbasel merged 1 commit into
momenbasel:mainfrom
brainx:codex/fix-issue-93

Conversation

@brainx
Copy link
Copy Markdown
Contributor

@brainx brainx commented May 22, 2026

Summary

Fixes protected app-uninstaller removals by separating Full Disk Access failures from administrator-required uninstall artifacts.

Fixes #93. Related to #100.

Root Cause

The uninstaller previously treated removal failures as Full Disk Access problems. Some selected uninstall artifacts, such as root-owned app bundles, package receipts, and launch plists, can still require administrator authorization even after PureMac has Full Disk Access.

Changes

  • Keep FileManager.trashItem as the first removal attempt so TCC attribution stays with PureMac.
  • Route narrow protected uninstall artifacts through the existing administrator cleaner.
  • Revalidate privileged paths in CleaningEngine before escalation.
  • Support app bundles, package receipts, LaunchDaemons, and LaunchAgents in the uninstall admin path.
  • Show the Full Disk Access settings action only when FDA is actually the blocker.

Security Notes

  • The administrator path remains allow-listed and revalidated in CleaningEngine; callers cannot pass arbitrary selected paths directly to privileged removal.
  • Paths are staged as NUL-separated data and consumed by xargs -0, preserving spaces/newlines in filenames.
  • The UI distinguishes TCC/FDA remediation from administrator-auth failures so users are not sent back to System Settings when FDA is not the cause.

Validation

  • Built successfully with:
    xcodebuild -project PureMac.xcodeproj -scheme PureMac -configuration Debug -derivedDataPath DerivedData CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO build
  • Checked diff hygiene with git diff --check.

Distinguish Full Disk Access failures from administrator-required uninstall artifacts and route narrow app bundle, receipt, and launch plist removals through the vetted admin cleaner.
@brainx brainx marked this pull request as ready for review May 22, 2026 17:35
@momenbasel momenbasel merged commit 6fe3f0f into momenbasel:main May 23, 2026
1 check passed
momenbasel pushed a commit that referenced this pull request May 23, 2026
Supersedes #76.

- Adds Brazilian Portuguese (pt-BR) localization with 227 keys at parity with en.
- Localizes the post-#80 dashboard surface (DashboardView, MainWindow, CategoryDetailView, AppListView, AppFilesView, OrphanListView, OnboardingView, SettingsView, AppearancePill).
- Settings → General → Language picker with System Default + every bundled language. Mutates only AppleLanguages on apply (AppleLocale preserved so number/date/currency formatting follows the host locale).
- Extracts AppLanguage + AppLanguagePreferences into Models/.
- Relaunch prompt after language switch (AppleLanguages is consumed at startup) via /usr/bin/open -n.
- AppState gains injection points (performStartupTasks, locationsProvider, appFileScanner) so the app-file scan path is unit-testable.
- New PureMacTests target with three test cases: LocalizationFilesTests (locale key-parity guard), AppLanguagePreferencesTests, AppStateTests. project.yml registers the test target + shared scheme.

Rebased onto post-#103 main; AppState.swift @published additions kept side-by-side.
momenbasel pushed a commit that referenced this pull request May 23, 2026
Stage 1 of in-app updates. Adds Sparkle as an opt-in dependency.

- New `UpdateService` (singleton) wraps `SPUStandardUpdaterController` started with `startingUpdater: false` so no automatic update checks happen at launch.
- `Updates → Check for Updates` command added to the main menu.
- Safe fallback: when no `SUFeedURL` is configured in Info.plist, the menu item opens https://github.com/momenbasel/PureMac/releases/latest in NSWorkspace instead of starting Sparkle.
- Sparkle SPM package pinned to `from: 2.0.0` in project.yml.

Stage 2 (signed appcast, EdDSA key management, release-workflow integration that makes auto-update actually fire on new releases) is tracked separately.

Rebased onto post-#103 main; the original PR's unrelated AppState concurrency-warning workaround was dropped during rebase. Verified: `xcodebuild build` succeeds on macOS 13 / Xcode 16.

Refs #94.
momenbasel added a commit that referenced this pull request May 23, 2026
Bundles three user-facing fixes and one new feature for the next release:

- #103: Protected-app uninstall now routes admin-required paths through
  the vetted CleaningEngine admin cleaner (fixes #93/#95/#97/#102).
- #96: Orphan-file context menu uses activateFileViewerSelecting +
  exposes Copy Path / Move to Trash per row.
- #92: AppInfoFetcher.appSize drops the broken directory-inode fast
  path; sums per-file allocated size so installed-app sizes match
  Finder's Size on disk.
- #101: pt-BR localization, locale parity test guard, Settings language
  picker.
- #99: Sparkle Stage 1 - opt-in UpdateService with Releases-page
  fallback. Signed-appcast work tracked in #104.
momenbasel pushed a commit that referenced this pull request May 24, 2026
Distinguishes Full Disk Access failures from administrator-required uninstall artifacts.

- Routes narrow allow-listed uninstall artifacts (app bundles under /Applications and ~/Applications, package receipts under /var/db/receipts and /private/var/db/receipts, LaunchDaemons/LaunchAgents plists) through the existing administrator cleaner.
- CleaningEngine re-validates each escalation path against the allow-list before invoking the privileged removal.
- Hardens the AppleScript shell payload by single-quoting the temp-file path (no longer trusting NSTemporaryDirectory to be free of metacharacters).
- AppState distinguishes missing-file, FDA-blocked, and admin-required failures, and the AppFilesView alert only offers the Open System Settings button when FDA is actually the blocker.

Fixes #93. Closes #95, #97, #102. Supersedes #100.
momenbasel pushed a commit that referenced this pull request May 24, 2026
Supersedes #76.

- Adds Brazilian Portuguese (pt-BR) localization with 227 keys at parity with en.
- Localizes the post-#80 dashboard surface (DashboardView, MainWindow, CategoryDetailView, AppListView, AppFilesView, OrphanListView, OnboardingView, SettingsView, AppearancePill).
- Settings → General → Language picker with System Default + every bundled language. Mutates only AppleLanguages on apply (AppleLocale preserved so number/date/currency formatting follows the host locale).
- Extracts AppLanguage + AppLanguagePreferences into Models/.
- Relaunch prompt after language switch (AppleLanguages is consumed at startup) via /usr/bin/open -n.
- AppState gains injection points (performStartupTasks, locationsProvider, appFileScanner) so the app-file scan path is unit-testable.
- New PureMacTests target with three test cases: LocalizationFilesTests (locale key-parity guard), AppLanguagePreferencesTests, AppStateTests. project.yml registers the test target + shared scheme.

Rebased onto post-#103 main; AppState.swift @published additions kept side-by-side.
momenbasel pushed a commit that referenced this pull request May 24, 2026
Stage 1 of in-app updates. Adds Sparkle as an opt-in dependency.

- New `UpdateService` (singleton) wraps `SPUStandardUpdaterController` started with `startingUpdater: false` so no automatic update checks happen at launch.
- `Updates → Check for Updates` command added to the main menu.
- Safe fallback: when no `SUFeedURL` is configured in Info.plist, the menu item opens https://github.com/momenbasel/PureMac/releases/latest in NSWorkspace instead of starting Sparkle.
- Sparkle SPM package pinned to `from: 2.0.0` in project.yml.

Stage 2 (signed appcast, EdDSA key management, release-workflow integration that makes auto-update actually fire on new releases) is tracked separately.

Rebased onto post-#103 main; the original PR's unrelated AppState concurrency-warning workaround was dropped during rebase. Verified: `xcodebuild build` succeeds on macOS 13 / Xcode 16.

Refs #94.
momenbasel added a commit that referenced this pull request May 24, 2026
Bundles three user-facing fixes and one new feature for the next release:

- #103: Protected-app uninstall now routes admin-required paths through
  the vetted CleaningEngine admin cleaner (fixes #93/#95/#97/#102).
- #96: Orphan-file context menu uses activateFileViewerSelecting +
  exposes Copy Path / Move to Trash per row.
- #92: AppInfoFetcher.appSize drops the broken directory-inode fast
  path; sums per-file allocated size so installed-app sizes match
  Finder's Size on disk.
- #101: pt-BR localization, locale parity test guard, Settings language
  picker.
- #99: Sparkle Stage 1 - opt-in UpdateService with Releases-page
  fallback. Signed-appcast work tracked in #104.
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.

[Bug] Grant Full Disk Access in System Settings

2 participants