Context
I'm building a Github Actions job to build, sign and notarize a PKG file.
I'm using an Apple Id account (the workflow needs username and password) as well as a Developer Id Installer certificate with private key (encrypted). Both are saved as secrets (base64) and will be converted in the workflow to a .p12 file, then added to keychain.
This job is part of a bigger workflow in a private repository, that generates first the files (using Pyinstaller) from the software, and then export the PKG on a AWS S3 Bucket.
The implementation
jobs:
[...]
pkg:
needs: [...]
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download macos bin file
uses: actions/download-artifact@v2
with:
name: macos-bin-files
path: dist/
- name:
run: |
----- Create certificate files from secrets base64 -----
echo ${{ secrets.DEVELOPER_ID_INSTALLER_CER }} | base64 --decode > certificate_installer.cer
echo ${{ secrets.DEVELOPER_ID_INSTALLER_KEY }} | base64 --decode > certificate_installer.key
----- Create p12 file -----
openssl pkcs12 -export -name zup -in certificate_installer.cer -inkey certificate_installer.key -passin pass:${{ secrets.KEY_PASSWORD }} -out certificate_installer.p12 -passout pass:${{ secrets.P12_PASSWORD }}
----- Configure Keychain -----
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
security create-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" $KEYCHAIN_PATH
----- Import certificates on Keychain -----
security import certificate_installer.p12 -P "${{ secrets.P12_PASSWORD }}" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
----- Generate PKG from files -----
use a macos installer script (ref: https://github.com/KosalaHerath/macos-installer-builder/tree/master/macOS-x64)
----- Sign PKG file -----
productsign --sign "${{ secrets.DEVELOPER_ID_INSTALLER_NAME }}" $INPUT_FILE_PATH $OUTPUT_FILE_PATH
- name: "Notarize Release Build PKG"
uses: devbotsxyz/xcode-notarize@v1
with:
product-path: $PATH_TO_PKG
appstore-connect-username: ${{ secrets.APPLE_ACCOUNT_USERNAME }}
appstore-connect-password: ${{ secrets.APPLE_ACCOUNT_PASSWORD }}
primary-bundle-id: 'BUNDLE_ID'
- name: "Staple Release Build"
uses: devbotsxyz/xcode-staple@v1
with:
product-path: $PATH_TO_PKG
[...]
Issue
I followed the Github Action official documentation for installing an Apple certificate on macOS runners and this part is working as expected. I can add the certificate to keychain and use it to sign the PKG file with the productsign
command.
However, when I send the PKG to Apple for notarization, it returns me that error:
Error: Notarization status <invalid> - Package Invalid
Error: Notarization failed
What I tried
The PKG is working as expected when distributed (just need to be opened as admin as not notarized), so the problem doesn't seem related to the package implementation.
I tried to perform the notarization with command lines, following links from different sources:
- Notarization Rejected for .pkg installer
- How to notarize an MacOS command line tool created outside of XCode?
- Notarize a Command Line Tool
- How to notarize app at CI build?
However, even with those command lines (without using the notarize action), I couldn't notarize the PKG file.
Question
What is wrong with my workflow, did I miss something before trying to notarize the package?
PS: I couldn't find any reference doing this on a Github Actions macos runner...
CodePudding user response:
Solution
After setting the devbotsxyz/xcode-notarize@v1
field verbose:true
, I observed that Apple returns a link to a JSON explaining why the package is INVALID for notarization.
In this JSON, it was informed that all the files composing my PKG (there are many as I couldn't use --onefile
with Pyinstaller in my context) were invalid because they weren't signed and timestamped.
After some researches, I found this post on the Apple Developer Forum and understood that PKG files need to be sign INSIDE OUT: First, you sign each file generated by Pyinstaller, then sign the PKG gathering all those files.
To do so, you can't use the productsign
command (as it only work for .pkg, .zip and .dmg) but codesign
.
However, codesign
doesn't use a Developer Id Installer certificate
, but a Developer Id Application certificate
, so I had to add this new certificate to the workflow as well.
Note that as my PKG would be composed of hundreds of files, I also needed a bash script to use codesign to sign each one of them.
My final workflow looks like this:
```yaml
jobs:
[...]
pkg:
needs: [...]
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download macos bin file
uses: actions/download-artifact@v2
with:
name: macos-bin-files
path: dist/
- name:
run: |
----- Create certificate files from secrets base64 -----
echo ${{ secrets.DEVELOPER_ID_INSTALLER_CER }} | base64 --decode > certificate_installer.cer
echo ${{ secrets.DEVELOPER_ID_INSTALLER_KEY }} | base64 --decode > certificate_installer.key
echo ${{ secrets.DEVELOPER_ID_APPLICATION_CER }} | base64 --decode > certificate_application.cer
echo ${{ secrets.DEVELOPER_ID_APPLICATION_KEY }} | base64 --decode > certificate_application.key
----- Create p12 file -----
openssl pkcs12 -export -name zup -in certificate_installer.cer -inkey certificate_installer.key -passin pass:${{ secrets.KEY_PASSWORD }} -out certificate_installer.p12 -passout pass:${{ secrets.P12_PASSWORD }}
openssl pkcs12 -export -name zup -in certificate_application.cer -inkey certificate_application.key -passin pass:${{ secrets.KEY_PASSWORD }} -out certificate_application.p12 -passout pass:${{ secrets.P12_PASSWORD }}
----- Configure Keychain -----
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
security create-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "${{ secrets.KEYCHAIN_PASSWORD }}" $KEYCHAIN_PATH
----- Import certificates on Keychain -----
security import certificate_installer.p12 -P "${{ secrets.P12_PASSWORD }}" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security import certificate_application.p12 -P "${{ secrets.P12_PASSWORD }}" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
----- Codesign files with script -----
use a script to sign each file from the artifact (ref: https://gist.github.com/GuillaumeFalourd/4efc73f1a6014b791c0ef223a023520a)
----- Generate PKG from codesigned files -----
use a macos installer script (ref: https://github.com/KosalaHerath/macos-installer-builder/tree/master/macOS-x64)
----- Sign PKG file -----
productsign --sign "${{ secrets.DEVELOPER_ID_INSTALLER_NAME }}" $INPUT_FILE_PATH $OUTPUT_FILE_PATH
- name: "Notarize Release Build PKG"
uses: devbotsxyz/xcode-notarize@v1
with:
product-path: $PATH_TO_PKG
appstore-connect-username: ${{ secrets.APPLE_ACCOUNT_USERNAME }}
appstore-connect-password: ${{ secrets.APPLE_ACCOUNT_PASSWORD }}
primary-bundle-id: 'BUNDLE_ID'
- name: "Staple Release Build"
uses: devbotsxyz/xcode-staple@v1
with:
product-path: $PATH_TO_PKG
[...]