Hello all,
I am building a macOS application that I codesign and notarize for distribution. I am able to download my zip, unzip and run my application successfully, but when I attempt to update to a new version I hit an error with ditto that "operation not permitted" when attempting to replace my .app with the new version.
For example, here is a sample output of the failure:
Update failed: binary update failed during ditto:
ditto: /Applications//tooler.app/Contents/_CodeSignature/CodeResources: Operation not permitted
ditto: /Applications//tooler.app/Contents/MacOS/tooler: Operation not permitted
ditto: /Applications//tooler.app/Contents/Resources/icons.icns: Operation not permitted
ditto: /Applications//tooler.app/Contents/Info.plist: Operation not permitted
My application code updates the user to a new version by executing a curl command to download the versions zip and then uses ditto to unzip. I am able to successfully download the zip with the curl command and remove the file with the rm command, but when I try to use ditto to copy and replace my application contents it fails. Here is my application code that does that (The directories are correct for the application and the zip is downloaded):
// Download the zip (Works)
homeDir, _ := os.UserHomeDir()
downloadPath := filepath.Join(homeDir, "Downloads", "tooler.zip")
err := exec.Command("curl", "-L", "-H", "Accept: application/octet-stream", "-H", "Authorization: Bearer REMOVED_TOKEN", "-H", "X-GitHub-Api-Version: 2022-11-28", release.AssetURL, "-o", downloadPath).Run()
if err != nil {
return fmt.Errorf("binary update failed during curl: %v", err)
}
// Get the executeable path (Works)
cmdPath, err := os.Executable()
appPath := strings.TrimSuffix(cmdPath, "tooler.app/Contents/MacOS/tooler")
if err != nil {
appPath = "/Applications/"
}
// Cleanup function to remove the downloaded .zip (Works)
defer func() {
err = exec.Command("rm", downloadPath).Run()
if err != nil {
// return fmt.Errorf("binary update failed during removal: %v", err)
}
}()
// Update application contents (This fails from the operation not permitted)
cmd := exec.Command("ditto", "-xk", downloadPath, appPath)
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("binary update failed during ditto: %v \n Args: %v \n CmdPath: %v \n AppPath %v", stderr.String(), cmd.Args, cmdPath, appPath)
}
return nil
Also, here are my entitlements:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
</dict>
</plist>
Anyone have any ideas on why the ditto command won't let me update the application contents and returns operation not permitted?
See my response on your other thread.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"