From ee5470dd7255ae67c77fa72c6b54c907c6d9703a Mon Sep 17 00:00:00 2001 From: GeiserX <9169332+GeiserX@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:20:09 +0200 Subject: [PATCH 1/2] fix: verify helper binary on disk after SMAppService registration SMAppService.register() can report success without actually placing the binary at /Library/PrivilegedHelperTools/. Observed with enterprise security tools like Zscaler that intercept daemon registration. Now checks the binary exists after registration and falls back to the legacy AppleScript install path if missing. Fixes #35 --- Sources/HelperManager.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Sources/HelperManager.swift b/Sources/HelperManager.swift index 93707bf..c8b794a 100644 --- a/Sources/HelperManager.swift +++ b/Sources/HelperManager.swift @@ -268,12 +268,21 @@ final class HelperManager: ObservableObject { let service = SMAppService.daemon(plistName: "\(kHelperToolMachServiceName).plist") try await service.register() - installationError = nil print("✅ Helper registered successfully via SMAppService") + + // SMAppService.register() can report success without actually placing the + // binary on disk (observed with enterprise security tools like Zscaler). + // Verify the binary exists before trusting the registration. + if !FileManager.default.fileExists(atPath: helperPath) { + print("⚠️ SMAppService reported success but helper binary not on disk, falling back to legacy install...") + return installHelperLegacy() + } + + installationError = nil return true } catch { print("⚠️ SMAppService failed: \(error.localizedDescription)") - print("🔐 Falling back to legacy SMJobBless...") + print("🔐 Falling back to legacy install...") return installHelperLegacy() } } From 8079724944348263d0a7a956cc9dbcb81e920a8d Mon Sep 17 00:00:00 2001 From: GeiserX <9169332+GeiserX@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:55:20 +0200 Subject: [PATCH 2/2] fix: also verify launchd plist exists after SMAppService registration --- Sources/HelperManager.swift | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Sources/HelperManager.swift b/Sources/HelperManager.swift index c8b794a..c4c6cc7 100644 --- a/Sources/HelperManager.swift +++ b/Sources/HelperManager.swift @@ -259,6 +259,7 @@ final class HelperManager: ObservableObject { // binary. For updates we must always go through the legacy path which does // the actual file copy. Only use SMAppService for first-time installs. let helperPath = "/Library/PrivilegedHelperTools/\(kHelperToolMachServiceName)" + let plistPath = "/Library/LaunchDaemons/\(kHelperToolMachServiceName).plist" if FileManager.default.fileExists(atPath: helperPath) { print("🔐 Helper exists on disk, using legacy path for update...") return installHelperLegacy() @@ -271,10 +272,11 @@ final class HelperManager: ObservableObject { print("✅ Helper registered successfully via SMAppService") // SMAppService.register() can report success without actually placing the - // binary on disk (observed with enterprise security tools like Zscaler). - // Verify the binary exists before trusting the registration. - if !FileManager.default.fileExists(atPath: helperPath) { - print("⚠️ SMAppService reported success but helper binary not on disk, falling back to legacy install...") + // binary/plist on disk (observed with enterprise security tools like Zscaler). + // Verify both files exist before trusting the registration. + if !FileManager.default.fileExists(atPath: helperPath) || + !FileManager.default.fileExists(atPath: plistPath) { + print("⚠️ SMAppService reported success but helper files missing on disk, falling back to legacy install...") return installHelperLegacy() }