Skip to content

fix(clean): preserve nested E5RT caches - #1264

Merged
tw93 merged 2 commits into
tw93:mainfrom
z0ffy:fix/preserve-sandbox-e5rt-cache
Jul 25, 2026
Merged

fix(clean): preserve nested E5RT caches#1264
tw93 merged 2 commits into
tw93:mainfrom
z0ffy:fix/preserve-sandbox-e5rt-cache

Conversation

@z0ffy

@z0ffy z0ffy commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Preserve nested com.apple.e5rt.e5bundlecache directories when cleaning sandboxed application caches.
  • Prevent applications using Apple TextRecognition/E5RT from losing compiled model caches while running, which can cause OCR failures until restart.
  • Add a regression test confirming the E5RT cache is retained while an unrelated sibling cache is still removed.

Safety Review

  • This change affects cleanup behavior in process_container_cache().
  • It introduces a narrow protection boundary: a top-level sandbox cache entry is skipped when it directly contains a com.apple.e5rt.e5bundlecache directory.
  • The check occurs after existing symlink rejection, so it does not follow or preserve cache entries through top-level symlinks.
  • No changes were made to path validation, protected directory handling, sudo boundaries, uninstall behavior, or release/install integrity.
  • The intentional tradeoff is minor under-cleaning: the parent cache entry is retained in full when it contains an E5RT cache.

Tests

Automated tests:

  • MOLE_TEST_NO_AUTH=1 bats tests/clean_user_core.bats tests/clean_app_caches.bats tests/clean_cached_device_firmware.bats
    • 91 tests passed.
  • ./scripts/check.sh --format
  • ./scripts/check.sh
    • Go vet, ShellCheck, and shell syntax checks passed.
  • MOLE_TEST_NO_AUTH=1 ./scripts/test.sh
    • 1079 tests passed, 0 failures, 13 skipped.
    • Go tests, module loading, and integration tests passed.
    • The skipped tests require an unavailable timeout utility and are unrelated to this change.

Manual checks:

  • Confirmed the real sandbox layout places the compiled model cache at:
    ~/Library/Containers//Data/Library/Caches//com.apple.e5rt.e5bundlecache
  • Confirmed Mole previously removed the containing application cache directory.
  • Reviewed the deletion branch to ensure unrelated sibling caches still pass through the existing safe_remove path.
  • Verified the working tree was clean after commit.

Additional Context

This was reproduced with a sandboxed OCR application using Apple TextRecognition:

  1. Mole removed the application's top-level cache directory.
  2. Subsequent OCR requests failed with E5RT Code 13.
  3. Repeating OCR in the existing process did not rebuild the cache.
  4. Restarting the application triggered E5 model compilation and restored OCR.

The fix is generic and matches the E5RT cache marker rather than a specific application bundle ID.

Safety-related changes

  • Adds protection for nested Apple E5RT compiled model caches during sandboxed application cache cleanup.

@z0ffy
z0ffy requested a review from tw93 as a code owner July 22, 2026 02:53
The container-only guard left the same failure reachable through
clean_user_essentials: ~/Library/Caches/* removes each top-level entry,
and com.apple.duetexpertd / com.apple.Spotlight both hold an E5RT bundle
cache one level down. clean_app_caches also wiped the shared
com.apple.e5rt.e5bundlecache outright. Same breakage, same daemons.

Move the rule into holds_compiled_model_cache() next to the other shared
protection predicates and apply it in safe_clean() as well, so the
container sweep and the plain cache sweep agree. Drop the explicit E5RT
cleanup target that now contradicts it.

The regression test passed with the fix reverted: its assertions sit at
the tail of a heredoc that bash never reaches, so the script exits 0 with
the cache already deleted. Report state from the inner script and assert
on $output instead, and cover the non-container path through safe_clean.
@tw93
tw93 merged commit 1791ac8 into tw93:main Jul 25, 2026
9 checks passed
@tw93

tw93 commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Merged, thanks for the careful writeup and the E5RT Code 13 repro, that made the root cause obvious.

I extended the fix a little before merging: the same cache is also reachable through the non-sandboxed ~/Library/Caches/* sweep (com.apple.duetexpertd and com.apple.Spotlight both keep an e5bundlecache one level down), so I moved the rule into a shared holds_compiled_model_cache() predicate and applied it in safe_clean too, and dropped the now-contradictory explicit E5RT cleanup target. I also reworked the regression test: its assertions sat past the end of the heredoc, so bash never reached them and the test passed even with the guard removed, now it reports state and asserts on the captured output.

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.

2 participants