MacOS now requires that all applications are hardened, signed and notarized. How does one sign and notarize an application created outside of XCode with a tool like PyInstaller?
I've sorted out the signing and notarization for .app
files created outside of XTools. There's a really helpful thread here that shows how to add an entitlements.plist
which fulfills the hardening of PyInstaller .app
files. I believe this also works on command line utilities as well, but could be missing something. Submitting a .dmg
containing a .app
for notarization using altool
will pass the tests and be notarized by Apple.
Submitting a single command line utility using the same process will also pass Notarization, but does not appear signed or notarized to the GateKeeper function on other machines. I assume this has something to do with the fact that a valid Info.plist
file is not included in the PyInstaller binary as detailed in this blog post about building and delivering command line tools for Catalina.
Checking the signature of a signed file using codesign -dvv
indicates that the Info.plist
is "not bound".
$ codesign -dvv ./dist/helloworld
Executable=/Users/aaronciuffo/Documents/src/toy/codesign/dist/helloworld
Identifier=helloworld
Format=Mach-O thin (x86_64)
CodeDirectory v=20500 size=72086 flags=0x10000(runtime) hashes=2244+5 location=embedded
Signature size=9054
Authority=Developer ID Application: Aaron Ciuffo (4H9P6Q65AM)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Nov 2, 2020 at 9:03:30 PM
Info.plist=not bound
TeamIdentifier=4H9P6Q65AM
Runtime Version=10.11.0
Sealed Resources=none
Internal requirements count=1 size=172
One suggested solution is using the Go gon package but gon does not cover adding the required Info.plist
as far as I can tell.
Is there a workflow or application that can assist in this? How does one create an CL application outside of XCode and successfully sign it?
Apple requires that all distributed binaries are signed and notarized using a paid Apple Developer account. This can be done using commandline tools for binaries created with tools such as PyInstaller, or compiled using gcc.
The script linked below allows you to automate this process using project specific .ini
files.
If you already have a developer account with Developer ID Application
and Developer ID Installer
certificates configured in XCode, skip this step
+
in the lower left cornerApple ID
+
in the lower left corner and choose Developer ID Application+
in the lower left corner and choose Developer ID InstallerKeyChain Access
NB! Additional args such as --add-data
may be needed to build a functional binary
pyinstaller --onefile myapp.py
security find-identity -p basic -v
1) ABC123 "Apple Development: aaronciuffonl@gmail.com ()"
2) XYZ234 "Developer ID Installer: Aaron Ciuffo ()"
3) QRS333 "Developer ID Application: Aaron Ciuffo ()"
4) LMN343 "Developer ID Application: Aaron Ciuffo ()"
5) ZPQ234 "Apple Development: aaron.ciuffo@gmail.com ()"
6) ASD234 "Developer ID Application: Aaron Ciuffo ()"
7) 01010A "Developer ID Application: Aaron Ciuffo ()"
7 valid identities found
codesign --deep --force --options=runtime --entitlements ./entitlements.plist --sign "HASH_OF_DEVELOPER_ID APPLICATION" --timestamp ./dist/foo.app
mkdir /tmp/myapp
ditto /path/to/myapp /tmp/myapp/path/to/install/location
/Applications/
on the target use: ditto ~/src/whiz_bang/dist/whizBang /tmp/whiz_bang/Applications/
productbuild --identifier "com.your.pkgname.pkg" --sign "HASH_OF_INSTALLER_ID" --timestamp --root /tmp/myapp / myapp.pkg
--root
option is as follows: --root
<ditto path>
<relative path on target system to install from>
<signed .pkg file>
xcrun altool --notarize-app --primary-bundle-id "com.foobar.fooapp" --username="developer@foo.com" --password "@keychain:Developer-altool" --file ./myapp.pkg
xcrun altool --notarization-history 0 -u "developer@***" -p "@keychain:Developer-altool"
xcrun altool --notarization-info "Your-Request-UUID" \
--username "username@example.com" \
--password "@keychain:Developer-altool"
xcrun stapler staple ghostscript64.pkg
-p "@keychain:Key"
switch to workentitlements.plist
to the signing process