indygreg / PyOxidizer

A modern Python application packaging and distribution tool
Mozilla Public License 2.0
5.4k stars 234 forks source link

Notarize a Mach-O binary? #681

Open OrBin opened 1 year ago

OrBin commented 1 year ago

Trying to sign and notarize a macOS Mach-O binary according to rcodesign docs, I encountered Error: do not know how to notarize /tmp/signed-cli at the notarization step:

# file /tmp/signed-app 
/tmp/signed-app: Mach-O 64-bit arm64 executable, flags:<|DYLDLINK|PIE>

# rcodesign notary-submit --verbose --api-key-path /tmp/generated-app-store-connect-api-key.json /tmp/signed-app 
Error: do not know how to notarize /tmp/signed-app

Following the source code, I understand from this block that notarization using rcodesign is currently unsupported for Mach-O binaries.

Is it possible to implement? Is it easy? Trying to put the binary in a zip, I stopped getting this error. Is it the right way to go?

05nelsonm commented 1 year ago

Running into the same issue. Also put binaries into a .zip and that worked, but stapling failed Error: do not know how to staple <file-name>.zip

05nelsonm commented 1 year ago

I Found that placing them in an app bundle worked. Just make the bundle executable a copy of your cli binary with .program extension (so that your actual binary gets signed + stapled), then use that.

MyApp.app
MyApp.app/Contents/MacOS/myapp
MyApp.app/Contents/MacOS/somelib.dylib
$ cp -a MyApp.app/Contents/MacOS/myapp MyApp.app/Contents/MacOS/myapp.program
$ touch MyApp.app/Contents/Info.plist
$ echo '<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>               
        <key>CFBundleExecutable</key>
        <string>myapp.program</string>
        <key>CFBundleIdentifier</key>
        <string>your.bundle.identifier</string>
        <key>LSUIElement</key>
        <true/>               
</dict>
</plist>' > Info.plist
$ rcodesign sign --p12-file /path/to/key.p12 --code-signature-flags runtime MyApp.app
$ rcodesign notary-submit --api-key-path /path/to/api-key.json --staple MyApp.app

Then just do whatever you want with files

MyApp.app/Contents/MacOS/myapp
MyApp.app/Contents/MacOS/somelib.dylib
$ cp MyApp.app/Contents/MacOS/myapp ~/Downloads
$ cp MyApp.app/Contents/MacOS/somelib.dylib ~/Downloads
$ cd ~/Downloads
$ spctl --assess --type install --context context:primary-signature -v myapp
myapp: accepted
source=Notarized Developer ID
$ spctl --assess --type install --context context:primary-signature -v somelib.dylib
somelib.dylib: accepted
source=Notarized Developer ID

The reason for copying myapp -> myapp.program and setting it as the executable program in the Info.plist (instead of simply using myapp) is b/c otherwise resources would be bunked and the codesignature when checked would be rejected. By simply copying it with .program extension, all the other binaries in the MacOS dir get signed + stapled. This also ensures that everything in the bundle has the same architecture, otherwise notary rejects it.

:clinking_glasses: