Part of: #9941
Problem
The main app and FinderSyncExt carry com.apple.security.temporary-exception entitlements. Apple explicitly prohibits these in Mac App Store submissions.
Confirmed in the release build via codesign:
FinderSync IPC (main app + FinderSyncExt):
FinderSyncXPCManager.m:91 opens NSXPCConnection initWithMachServiceName: for {bundleId}.FinderSyncService — a globally-registered Mach service. This requires temporary-exception.mach-register.global-name (main app) and temporary-exception.mach-lookup.global-name (FinderSyncExt).
Sources:
admin/osx/macosx.entitlements.cmake lines 17–25
shell_integration/MacOSX/FinderSyncExt.entitlements.cmake lines 11–14
Sparkle spks/spki names (main app only):
com.nextcloud.desktopclient-spks and -spki are looked up by Sparkle, not by our own code — which is why grepping src/ for them finds nothing. They are required whenever the updater is built, and dead only when it is not.
Source: admin/osx/macosx.entitlements.cmake lines 21–25
Required changes
- FinderSync XPC: move the listener into a Service Management login item and rendezvous through it. See the note below on why the embedded-XPC-service approach originally proposed here cannot work.
- spks/spki: make them conditional on
BUILD_UPDATER rather than deleting them.
Correction (2026-07-30)
Both originally proposed changes needed revising. Details, since the reasoning matters more than the conclusions:
1. An embedded XPC service cannot be reached by the extension
The original proposal was to embed Contents/XPCServices/FinderSyncService.xpc and connect with initWithServiceName:. That does not work: app-embedded XPC services are scoped to the containing app only.
xpc_connection_create(3):
Services bundled with an application are only accessible to that application. An external process cannot connect to those services.
Apple DTS on exactly this topology — a sandboxed Finder Sync extension connecting to a .xpc in its containing app (forums/thread/112628):
app-based XPC Services are scoped to the app that contains them, and you have two apps in play (well, your Finder Sync extension is an app extension, but it behaves like an app in this regard).
And on using one as a rendezvous broker (forums/thread/715338):
The launchd job in step one cannot be an XPC service. Third-party XPC services are always scoped to their container app and thus can't fulfil the primary requirement of an XPC rendezvous, namely, to be visible to both parties.
Prefixing the Mach name with the App Group does not help either. The App Group prefix lifts the sandbox check (application.sb: allow mach-lookup mach-register (global-name-prefix …)), but launchd still refuses to let a non-job check in under a name no launchd.plist declares. Both layers have to pass.
What works, and what has now been implemented: a Service Management login item vends the name; the client creates an anonymous listener and publishes its endpoint to the login item; the extension collects the endpoint and connects peer-to-peer. The broker relays nothing after the introduction. Its Mach service name is its own bundle identifier, <team>.<reverse domain>.FinderSyncBroker, which is simultaneously team-prefixed (a login item requirement) and inside the App Group prefix — so both temporary exceptions for FinderSync are gone, which is what this issue set out to achieve.
This is also the root cause of FinderSync being completely non-functional in 34.0.0: NSXPCListener in the app silently failed to activate (xpc_error=[1: Operation not permitted]), launchd answered every lookup from the extension with error = 3: No such process, and the client logged FinderSync XPC listener started successfully anyway. It appeared to work in development because Xcode's XPC debugging support grants precisely the dynamic-registration allowance the man page says will "absolutely NOT be made in the production scenario".
2. The Sparkle names are not dead
As already noted in the comment below, -spks/-spki are required in production builds with the updater enabled. Concretely:
cmake/modules/MacOSXBundleInfo.plist.in sets SUEnableInstallerLauncherService = true, which routes installation through Sparkle's Installer XPC service.
Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/{Downloader,Installer}.xpc ship in the bundle, and the Sparkle binary contains the -spki / -spks suffixes.
- A sandboxed app can only reach those Mach names via a temporary exception.
Deleting them therefore breaks updating — and only at update time, which is a bad failure mode to introduce.
They are dead when BUILD_UPDATER is off, which is necessarily the App Store configuration since App Store apps cannot self-update. So they have been made conditional on BUILD_UPDATER in admin/osx/CMakeLists.txt, with the manifest carrying @SPARKLE_ENTITLEMENTS@. Verified both ways:
BUILD_UPDATER=ON → valid plist containing the Sparkle exception.
BUILD_UPDATER=OFF → valid plist with no temporary-exception entitlement at all.
Follow-up worth splitting out
The Sparkle binary also contains a third suffix, -spkp, which is absent from our entitlements. It may be unused in our configuration or it may be a latent gap in the sandboxed installer's progress reporting — not yet investigated.
Part of: #9941
Problem
The main app and FinderSyncExt carry
com.apple.security.temporary-exceptionentitlements. Apple explicitly prohibits these in Mac App Store submissions.Confirmed in the release build via
codesign:FinderSync IPC (main app + FinderSyncExt):
FinderSyncXPCManager.m:91opensNSXPCConnection initWithMachServiceName:for{bundleId}.FinderSyncService— a globally-registered Mach service. This requirestemporary-exception.mach-register.global-name(main app) andtemporary-exception.mach-lookup.global-name(FinderSyncExt).Sources:
admin/osx/macosx.entitlements.cmakelines 17–25shell_integration/MacOSX/FinderSyncExt.entitlements.cmakelines 11–14Sparkle spks/spki names (main app only):
com.nextcloud.desktopclient-spksand-spkiare looked up by Sparkle, not by our own code — which is why greppingsrc/for them finds nothing. They are required whenever the updater is built, and dead only when it is not.Source:
admin/osx/macosx.entitlements.cmakelines 21–25Required changes
BUILD_UPDATERrather than deleting them.Correction (2026-07-30)
Both originally proposed changes needed revising. Details, since the reasoning matters more than the conclusions:
1. An embedded XPC service cannot be reached by the extension
The original proposal was to embed
Contents/XPCServices/FinderSyncService.xpcand connect withinitWithServiceName:. That does not work: app-embedded XPC services are scoped to the containing app only.xpc_connection_create(3):Apple DTS on exactly this topology — a sandboxed Finder Sync extension connecting to a
.xpcin its containing app (forums/thread/112628):And on using one as a rendezvous broker (forums/thread/715338):
Prefixing the Mach name with the App Group does not help either. The App Group prefix lifts the sandbox check (
application.sb:allow mach-lookup mach-register (global-name-prefix …)), but launchd still refuses to let a non-job check in under a name nolaunchd.plistdeclares. Both layers have to pass.What works, and what has now been implemented: a Service Management login item vends the name; the client creates an anonymous listener and publishes its endpoint to the login item; the extension collects the endpoint and connects peer-to-peer. The broker relays nothing after the introduction. Its Mach service name is its own bundle identifier,
<team>.<reverse domain>.FinderSyncBroker, which is simultaneously team-prefixed (a login item requirement) and inside the App Group prefix — so both temporary exceptions for FinderSync are gone, which is what this issue set out to achieve.This is also the root cause of FinderSync being completely non-functional in 34.0.0:
NSXPCListenerin the app silently failed to activate (xpc_error=[1: Operation not permitted]), launchd answered every lookup from the extension witherror = 3: No such process, and the client loggedFinderSync XPC listener started successfullyanyway. It appeared to work in development because Xcode's XPC debugging support grants precisely the dynamic-registration allowance the man page says will "absolutely NOT be made in the production scenario".2. The Sparkle names are not dead
As already noted in the comment below,
-spks/-spkiare required in production builds with the updater enabled. Concretely:cmake/modules/MacOSXBundleInfo.plist.insetsSUEnableInstallerLauncherService = true, which routes installation through Sparkle's Installer XPC service.Contents/Frameworks/Sparkle.framework/Versions/B/XPCServices/{Downloader,Installer}.xpcship in the bundle, and the Sparkle binary contains the-spki/-spkssuffixes.Deleting them therefore breaks updating — and only at update time, which is a bad failure mode to introduce.
They are dead when
BUILD_UPDATERis off, which is necessarily the App Store configuration since App Store apps cannot self-update. So they have been made conditional onBUILD_UPDATERinadmin/osx/CMakeLists.txt, with the manifest carrying@SPARKLE_ENTITLEMENTS@. Verified both ways:BUILD_UPDATER=ON→ valid plist containing the Sparkle exception.BUILD_UPDATER=OFF→ valid plist with notemporary-exceptionentitlement at all.Follow-up worth splitting out
The Sparkle binary also contains a third suffix,
-spkp, which is absent from our entitlements. It may be unused in our configuration or it may be a latent gap in the sandboxed installer's progress reporting — not yet investigated.