Skip to content

fix: register PureMac with TCC so Full Disk Access works (#75) + dashboard redesign#80

Open
ceorkm wants to merge 2 commits intomomenbasel:mainfrom
ceorkm:fix/issue-75-fda-and-cleaning
Open

fix: register PureMac with TCC so Full Disk Access works (#75) + dashboard redesign#80
ceorkm wants to merge 2 commits intomomenbasel:mainfrom
ceorkm:fix/issue-75-fda-and-cleaning

Conversation

@ceorkm
Copy link
Copy Markdown

@ceorkm ceorkm commented Apr 29, 2026

Closes #75 (and likely #78 — same root cause).

The bug

PureMac never appears in System Settings → Privacy & Security → Full Disk Access, even after a fresh install via Homebrew. Granting FDA manually with the + button doesn't help — the uninstaller still fails with "files could not be removed."

The reason is that the uninstaller delegated deletions to Finder via NSAppleScript. macOS records the Finder process as the requester for those file syscalls, so PureMac itself never tripped TCC and never got registered in the FDA pane. Granting access to PureMac was a no-op because PureMac wasn't the process being blocked.

What changed

Fixes

  • Replaced the AppleScript-via-Finder bridge with FileManager.trashItem, so the syscall originates from PureMac and TCC registers it.
  • Added FullDiskAccessManager.triggerRegistration() invoked at launch, which performs real reads on a few protected paths (/Library/Application Support/com.apple.TCC/TCC.db, ~/Library/Mail, ~/Library/Safari/CloudTabs.db). Forces TCC registration on first run.
  • Added recovery helpers for the cases reported in the issue thread: a "Reveal PureMac" button (drag-into-list workaround for Homebrew installs that strip the quarantine attribute) and a "Reset & re-prompt" action that runs tccutil reset SystemPolicyAllFiles com.puremac.app for the stale-bundle case.
  • Strengthened FDA detection: real FileHandle/contentsOfDirectory reads instead of isReadableFile metadata calls, since metadata calls don't always trigger TCC.
  • Info.plist gains NSDesktopFolderUsageDescription, NSDocumentsFolderUsageDescription, NSDownloadsFolderUsageDescription, NSRemovableVolumesUsageDescription, NSSystemAdministrationUsageDescription, NSAppleEventsUsageDescription so the OS surfaces per-folder consent prompts.

Cleaning fixes (surfaced while debugging)

  • Extended isSafeToDelete allow-list with the dev-cache roots scanners actually emit (~/Library/Developer/Xcode/DerivedData, Xcode/Archives, CoreSimulator/Caches, ~/.npm, ~/.cache, ~/Library/Containers/com.docker.docker) and /var/log / /var/tmp (the symlink-resolved forms of /private/var/...). System log/tmp deletion was silently failing the safety check before.
  • isSafeToDelete now accepts whole-root paths (path == root), not just paths inside roots. Xcode/Brew/Node scanners emit at the root, so they were getting silently skipped.
  • CleaningResult.cleanedPaths tracks what actually got deleted; the UI now removes only those items instead of wiping the list and pretending success.
  • Permission-denied failures get routed to a single admin-privileged batch via do shell script "xargs -0 /bin/rm -rf -- < <tempfile>" with administrator privileges. One auth prompt covers the whole batch. Paths are re-validated against the safety allow-list before escalation, passed via NUL-separated tempfile so quoting can't go wrong, and post-stat'd to confirm what disappeared.
  • cleanError now surfaces a real failure dialog with paths logged to Logger, instead of fake-succeeding.

Other fixes flagged in the issue comments

  • Directory sizes were rendering as 0 B because attributesOfItem(.size) returns the directory's metadata size, not its contents. AppFilesView and OrphanListView now use totalFileAllocatedSizeKey.
  • Removed a depth > 5000 { break } cap from scanLargeFiles that bailed after 5,000 enumerated entries. With 600,000+ files in Downloads/Documents/Desktop, the scan never reached anything actually large.

UI overhaul

  • Storage-led dashboard replaces the old Smart Scan landing: % used gauge (gradient turns orange/red over 85%), free-space numerals, stacked usage bar with legend, four stat tiles, contextual suggestions.
  • Sidebar redesigned with tinted icon tiles per row, capsule size badges, and a persistent system-health footer that turns orange when FDA isn't granted.
  • Category detail pages get a hero card with the tinted icon, description, item count + size, and a rescan action.
  • Flat orange FDA bar replaced with a gradient toast card that matches the dashboard surfaces.
  • Onboarding now walks the user through Settings step-by-step (intro → numbered instructions → granted), auto-advances when access is detected, includes a "Trouble?" menu with reveal/reset/diagnostics.
  • Toolbar gets a 3-segment appearance pill (system / light / dark) with a sliding indicator. ThemeManager persists the preference via AppStorage.
  • docs/ui-prototype/{old,new}.html are clickable HTML mockups of the previous and proposed designs, included for design review.

Test plan

  • Build succeeds (xcodebuild -project PureMac.xcodeproj -scheme PureMac build)
  • Fresh launch with onboarding reset registers PureMac in System Settings → Privacy & Security → Full Disk Access
  • Granting FDA and running Smart Scan → Clean actually deletes user-owned items (e.g. ~/.npm/_cacache)
  • Root-owned items (/Library/Caches/*, /private/var/log/*) trigger the admin auth prompt and get deleted via the privileged pass
  • Large & Old Files scan finds items beyond the previous 5k cap on a Mac with 600k+ files in user folders
  • Light / dark / system appearance toggle persists across launches

livit added 2 commits April 29, 2026 04:28
The uninstaller delegated file deletions to Finder via NSAppleScript,
which meant Finder made the TCC-gated syscalls — not PureMac. macOS
only adds an app to the Full Disk Access list once that app itself
hits a protected path, so granting FDA to PureMac had no effect.

Replaced trashViaFinder with FileManager.trashItem, and added a
launch-time triggerRegistration() that performs real reads on protected
paths so the bundle gets registered on first run. Onboarding now walks
the user through Settings step-by-step with reveal-in-Finder and
tccutil reset helpers for the Homebrew-quarantine and stale-bundle
cases that surfaced in the issue thread.

Cleaning fixes that surfaced while debugging the same issue:

  - extend isSafeToDelete allow-list with dev caches (Xcode/DerivedData,
    ~/.npm, ~/.cache, Docker container) and the symlink-resolved forms
    of /private/var/log and /private/var/tmp
  - accept whole-root paths so Xcode/Brew/Node scanners that emit at
    the root no longer get silently skipped
  - track cleanedPaths so the UI removes only items that actually got
    deleted instead of wiping the list and pretending success
  - escalate EACCES failures to a single admin-privileged xargs/rm
    pass via NSAppleScript "with administrator privileges"; one auth
    prompt covers the whole batch
  - surface a real failure alert with paths logged for diagnosis

Also fixes the size display bug noted in the comments: directories
were rendering as 0 B because attributesOfItem(.size) returns the
directory metadata size, not its contents. Now uses
totalFileAllocatedSizeKey in AppFilesView and OrphanListView.

Removed the 5,000-entry cap from scanLargeFiles — with hundreds of
thousands of files in Downloads/Documents/Desktop, the scan never
reached anything actually large.

Info.plist gains the per-folder usage description keys
(NSDesktopFolderUsageDescription etc.) so the OS surfaces consent
prompts that register PureMac in the relevant TCC panes.
Replaces the old Smart Scan landing with a storage-led dashboard:

  - circular gauge showing % of disk used; gradient turns orange/red
    once usage crosses 85%
  - free-space hero numerals with a stacked usage bar (used / junk /
    purgeable) and a legend
  - four stat tiles (Free Space, Junk Found, Apps, Purgeable)
  - contextual suggestion cards — surfaces the largest pending category
    and an FDA nudge when access is missing; nothing is shown when
    there are no real suggestions
  - same surface for scanning/completed/cleaning/cleaned states with
    an animated rotating gauge during scans

Sidebar gets tinted icon tiles per row, capsule size badges per
category, and a persistent system-health footer that turns orange
when FDA isn't granted. Category detail pages get a hero card on
top showing the tinted icon, description, item count + size, and
the rescan action.

The flat orange FDA bar is replaced with a gradient toast card that
matches the dashboard surfaces. Toolbar gets a 3-segment appearance
pill (system / light / dark) with an animated indicator that slides
between segments — backed by a ThemeManager whose preference lives
in AppStorage so it persists.

docs/ui-prototype/{old,new}.html are clickable HTML mockups of the
previous and proposed designs, included for design review.
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] No PureMac in system settings "Allow full disk access"

1 participant