Xcode notarization and hardened runtime issue

Hi, I'm somewhat new to swift and coding in general, so thanks for your help in advance. I'm building an application that uses Process class to launch a Unix Executable (Swift 5, Cocoa). Unfortunately, when I go to notarize my application, I get the below error. The trouble is, hardened runtime is already enabled and working (along with sandbox). I have tried everything I can think of including removing and re-adding the executable, cleaning build folders, messing with targets, changing hardened runtime exceptions, etc. I have even attempted to force enable hardened runtime on the executable by using "codesign --force --deep --options runtime <Devloper ID Application cert identity> <path to executable>, however, this appears to break the executable, making zsh throw a "Segmentation Fault" when it is run. (the broken executable successfuly passes notarization, but that doesn't help me much) Thanks so much for your help, please tell me if anything was unclear or confusing. 🙂



Error:

Distribution items ineligible: Error Domain=IDEDistributionMethodDeveloperIDErrorDomain Code=1 "Hardened Runtime is not enabled." UserInfo={NSLocalizedDescription=Hardened Runtime is not enabled., NSLocalizedRecoverySuggestion="myunixexecutable" must be rebuilt with support for the Hardened Runtime. Enable the Hardened Runtime capability in the project editor, test your app, rebuild your archive, and upload again.}

Replies

These problems are usually caused by things like incorrectly structured bundles, bad Info.plists, incorrect entitlements, and just crazy stuff.


I'm curious about exactly what you are doing with zsh in this app. I suggest posting an outline of your bundle structure to start with. And maybe list your entitlements too.


And what are you doing with the sandbox? Is this going to be a Mac App Store app? Since you are having problems, it is best to focus on what your eventual target is - Developer ID or Mac App Store. We can debate the relative merits of the sandbox outside of the Mac App Store at a later date.

Interesting, Its definitely possible that one of those things could be the issue, as i'm not well versed in, well, any of them.


The zsh was just what responds when the broken file is opened (the executable normally outputs data to command line). "exit; zsh: segmentation fault" But my main application doesn;t appear to be able to start the process at all, nothing happens.


The sandbox isn't neccicary as far as I know, I was just under the impression that it's considered good practice. Developer ID. The application involves cryptocurrency, so I definitely don't want to get anywhere near the App Store. Thanks for the help.

Is there an easy way to post the bundle structure? Should I just type it out? Screenshot? I don't think I need Resource Access at all, and i'm currently not sure about Runtime Exceptions.

Just type it out.


You can also just look at any old existing app and state what you do differently. TextEdit is a good example. Look at the structure of TextEdit. Don't consider any of the "pl.lproj", "zh_TW.lproj", etc. language resources. How is your app structured differently?


For Resource Access or Runtime exceptions, you talking about hardened runtime exceptions. Exceptions don't break anything. They don't prevent signing or notarization. Sometimes you need Info.plist explations for why you are asking for the camera or something. But that is something else. Just turn them all off. If that breaks something in your app, then you can deal with that later.


You can also deal with zsh later too. It sounds like that only breaks when you are trying to hack the code signing. An easy solution to many code signing/notarization issues is to not try to hack the code signing. It does seem odd that your native app would be doing anything with zsh. I'm almost certain that's wrong, but, again, it's something you can look at later.

Let me confirm my understanding here:

  • You can an app written in Swift.

  • Embedded within that app is a command-line tool, also written in Swift.

  • You want to run the latter from the former using

    Process
    .

First question: Are you building your command-line tool from source within your project? Or was it built separately and you’re trying to integrate the pre-built executable into you app?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I took a peek at TextEdit, looks like the only differences are that I have a frameworks folder and a library folder in "contents," and Textedit has a version.plist file in contents.


My app:

Contents

_CodeSignature

CodeResources

Frameworks

Sparkle.framework

LaunchAtLogin.framework

Library

LoginItems

MacOS

myAppExec

Resources

myProblemExec

Assets.car

Base.Iproj

storyboard1.storyboardc

storyboard2.storyboardc

Info.plist

PkgInfo


Is that what you were looking for?


Okay, i'll make sure not to hack the code signing. I'm not sure about zsh, It only ever appears when I break the exec with the code signing hack.

Yes, my main app is written in swift. The command line exec is definitly not written in Swift and is from an open source project. I believe it's acutally C++. I am succussfully running it using process (took me a while to get that one working), the issue is notarization fails on the exec.


I am building it seperately using cmake (per the developer's instructions), then integrating it into my app. Did that answer your question?

Create a new folder named "Helpers" and move "myProblemExec" to "Helpers".


Do you actually have any items in LoginHelpers? If so, that's fine. If not, then you probably shouldn't have the "Library" folder. I'm not sure if this would be a problem or not. The executable inside the resources folder is definitely a problem.


You can definitely build the helper externally. Just make sure to sign it with the hardened runtime and timestamp flags. I'm still concerned by the zsh reference. Are you executing it via zsh? Or is it doing something with zsh? Regardless, zsh is an interactive shell. It shouldn't be used in this context. If you really, really need a shell in an automated task, use "/bin/sh". But when running one app from another like this, you normally don't want to route it through a shell at all if you can help it. This probably doesn't have anything to do with notarization, but it could be a problem in other ways.

Okay, I moved it to Helpers. I'm not sure how to retrive the path for the exec in this new folder. "Bundle.path(forResource: "execname", ofType: nil, inDirectory: "Helpers")" doesn't seem to work. Before I was using Bundle.main.path(forResource: <String?>, ofType: <String?>).


Yes I do have a helper in LoginHelpers.


How can I sign it with the hardened runtime and timestamp flags that when the "codesign --force --deep --options runtime <Devloper ID Application cert identity> <path to executable>" (specifically the --options runtime option ) breaks it?


I'm not sure how its being executed (I'm just using let a = process() , a.run()) How would I run it without a shell? Normally, when this problem exec is run without my program, it is an automated command line application.

I also believe moving the exec may have fixed the notarazation issue, but I don't have a reliable internet connection at the moment, so i'm going to have to try again later.

Okay, I moved it to Helpers. I'm not sure how to retrive the path for the exec in this new folder. "Bundle.path(forResource: "execname", ofType: nil, inDirectory: "Helpers")" doesn't seem to work. Before I was using Bundle.main.path(forResource: <String?>, ofType: <String?>).


Just use bundlePath and append Contents/Helpers/myProblemExec


How can I sign it with the hardened runtime and timestamp flags that when the "codesign --force --deep --options runtime <Devloper ID Application cert identity> <path to executable>" (specifically the --options runtime option ) breaks it?


Maybe this should be re-worded. The app is broken. The code signing identifies the bug. Not the other way around.


To be clear - both "--force" and "--deep" are hacks. They are option that you use when you want to spend weeks and weeks debugging notarization issues. If you don't want to do that, remove them. The app may not work now. But now your app doesn't work for a reason that clearly identifies the bug, allowing you to fix it. Use of "--force" and "--deep" only obscure the bug so that you can be mystified by random other failures further down the line.


To code sign an executable, do this:

codesign --timestamp --options=runtime -s "Developer ID Application: Whoeveryouare" -v /path/to/executable


I'm not sure how its being executed (I'm just using let a = process() , a.run()) How would I run it without a shell? Normally, when this problem exec is run without my program, it is an automated command line application.


I'm pretty sure there is more to it than that. What I am asking is this - are you using the string "zsh" or not? I strongly suggest you figure out exactly what code you are executing. What if you release this cryptocurrency app and someone comes to you asking where their money is. They ask what the app is doing and you don't know. You might want to double-up on that ole' business liability insurance for this one.


Normally, if you need to run some helper app, you are going to want to extract data from it somehow. Normally that takes a more work. I've got almost 600 lines of Objective-C to do this. Some of the tools I run need a pseudo terminal, and that is 200 lines of slightly different code.

Just use bundlePath and append Contents/Helpers/myProblemExec


I'm getting this: Error Domain=NSCocoaErrorDomain Code=4 "The file “xmrig” doesn’t exist." I dont think xcode is acutally adding the Helpers folder in the contents folder. Should the folder's location be "relative to group?" The file definitely exists in my project files, just not in the actual application contents folder?


Thanks for clarifying on the code signing stuff.


No, it should not be using zsh. Funny enough, i don't actually need to extract data from it, I have another way of making sure it gets its job done. Thanks so much.

I don't know what xmrig is. I just use a "Copy Files" build script to copy the helper to the "Wrapper" destination at subpath "Contents/Helpers"

xmrig is the problem exec (https://github.com/xmrig/xmrig). After adding the copy phase, looks like we're back to the same old issue. " 'xmrig' must be rebuilt with support for the Hardened Runtime. Enable the Hardened Runtime capability in the project editor, test your app, rebuild your archive, and upload again." Enabling the "Code sign on copy" checkbox in the Copy Files Phase causes the exec to stop working, and notarization fails regardless of whether that option is enabled or not.

Did that answer your question?

Yes. It seems like you’re integrating a pre-built executable.

Next question: Is your main app sandboxed?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"