Execute command line tools /usr/bin from a SwiftUI Sandboxed app

For some years I have developed and maintained a SwiftUI based app as GUI ontop of the command line tool rsync. The app is available on HomeBrew and works as expected, included using rsync command line tool from HomeBrew.

I have now developed a new GUI, a downscale version of the original app, using SwiftData and using only the default rsync in /usr/bin/rsync. No access to remote servers by ssh-keys, only local attached disk on your Mac. SwiftData is used for storing data about synchronise tasks and log records from run.

The app works, but as soon as I enable the App Sandbox, the app does not permit to executed default included command line tool from /usr/bin. The GUI app executes the command line tool by a Swift Process object.

Replies

See On File System Permissions for important background on this issue.

I coulda sworn /usr/bin was in the static sandbox…

Yeah, I remembered correctly. Consider the following code:

do {
    let p = Process()
    p.executableURL = URL(fileURLWithPath: "/usr/bin/zip")
    try p.run()
} catch {
    print(error)
}

When I wire this up to a button in a sandboxed app and then click that button, the zip tool runs and prints its usage.

Are you sure you’re not talking about /usr/local/bin? That’s not in the static sandbox IIRC.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thx, I will try to use the URL.. My code look like this. The task.launchpath = /usr/bin/rsync... Will try to replace as you advice...

func executeProcess() async {
        // Must check valid rsync exists
        guard SharedReference.shared.norsync == false else { return }
        // Process
        let task = Process()
        // Getting version of rsync
        task.launchPath = GetfullpathforRsync().rsyncpath
        task.arguments = arguments
        // Pipe for reading output from Process
        let pipe = Pipe()
        task.standardOutput = pipe
        task.standardError = pipe
        let outHandle = pipe.fileHandleForReading
        outHandle.waitForDataInBackgroundAndNotify()
        // Combine, subscribe to NSNotification.Name.NSFileHandleDataAvailable
        NotificationCenter.default.publisher(
            for: NSNotification.Name.NSFileHandleDataAvailable)
            .sink { _ in
                let data = outHandle.availableData
                if data.count > 0 {
                    if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
                        self.outputprocess?.addlinefromoutput(str: str as String)
                    }
                    outHandle.waitForDataInBackgroundAndNotify()
                }
            }.store(in: &subscriptons)
        // Combine, subscribe to Process.didTerminateNotification
        NotificationCenter.default.publisher(
            for: Process.didTerminateNotification)
            .debounce(for: .milliseconds(500), scheduler: globalMainQueue)
            .sink { _ in
                // Process termination and Log to file
                self.processtermination(self.outputprocess?.getOutput(), self.config?.hiddenID)
                _ = Logfile(TrimTwo(self.outputprocess?.getOutput() ?? []).trimmeddata, error: false)
                // Release Combine subscribers
                self.subscriptons.removeAll()
            }.store(in: &subscriptons)
        SharedReference.shared.process = task
        do {
            try task.run()
        } catch let e {
            let error = e
            propogateerror(error: error)
        }
        if let launchPath = task.launchPath, let arguments = task.arguments {
            Logger.process.info("RsyncProcessAsync: \(launchPath, privacy: .public)")
            Logger.process.info("RsyncProcessAsync: \(arguments.joined(separator: "\n"), privacy: .public)")
        }
    }

Tried to change the run as advised p.executableURL = URL(fileURLWithPath: "/usr/bin/rsync"), enabled Sandbox and granted the app Full Disc Access.. Still /usr/bin/rsync throws an error : rsync: execv/us/libexec/rsync/rsync.samba): Operation not permitted .. without Sandbox the rsync version show: rsync version 2.6.9 protocol version 29...