Skip to content

Commit

Permalink
Codesign and notarize empress executable for macOS on GitHub Actions (#…
Browse files Browse the repository at this point in the history
…237)

Codesign and notarize empress executable for macOS on GitHub Actions so that the gatekeeper service allows users to open the app without going to System Preferences > Security and Privacy -> Open Anyway.

I use my own (Santi Santichaivekin's) Apple ID to codesign and notarize the application. The certificate is stored in repository secrets.

Additional Resources on how to set this up:
https://docs.github.com/en/actions/guides/installing-an-apple-certificate-on-macos-runners-for-xcode-development
https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions
https://haim.dev/posts/2020-08-08-python-macos-app/
  • Loading branch information
ssantichaivekin committed Jun 7, 2021
1 parent 27637db commit 22bbf00
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 9 deletions.
55 changes: 48 additions & 7 deletions .github/workflows/macos-build-gui-executable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,26 @@ jobs:
runs-on: macos-10.15
# https://github.com/actions/virtual-environments/blob/main/images/macos/macos-10.15-Readme.md
# macos-10.15 already has python 3.7.8, no need to install, refer to this version as python3.7

env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.MACOS_BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.MACOS_BUILD_P12_PASSWORD }}
KEYCHAIN_PASSWORD: this-password-is-temporary-so-you-can-use-anything
CERTIFICATE_PATH: ./certificate.p12
KEYCHAIN_PATH: ./app-signing.keychain-db
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: '3.7.8' # this sets python to use the correct version

- name: Install pipenv
run: |
python -m pip install pipenv
- name: Install geos (Shapely Dependency)
run: |
brew install geos
- name: Install dependencies via pipenv
# Sometimes macOS 10.15 pipenv thinks it's already running in a virtual environment
# when it is actually not. PIPENV_IGNORE_VIRTUALENVS=1 forces pipenv to create a new
Expand All @@ -36,17 +44,50 @@ jobs:
export PIP_NO_BINARY="shapely"
python -m pipenv lock --keep-outdated
python -m pipenv install --dev
- name: Create macos app
run: |
pipenv run pyinstaller pyinstaller_spec/empress_gui_app.spec
- name: Import codesign certificate to keychain
# Codesign and notarize app so that we don't have to go to Security and Privacy to
# allow the app to run.
# see https://docs.github.com/en/actions/guides/installing-an-apple-certificate-on-macos-runners-for-xcode-development
# see https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions
# see https://haim.dev/posts/2020-08-08-python-macos-app/
run: |
echo "import certificate from secrets"
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output $CERTIFICATE_PATH
echo "create temporary keychain with 600 seconds timeout"
security create-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
security set-keychain-settings -lut 600 $KEYCHAIN_PATH
security unlock-keychain -p $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
echo "import certificate to keychain"
security import $CERTIFICATE_PATH -P $P12_PASSWORD -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Codesign macOS app
run: |
echo "turn off prompts for codesign and xcrun"
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD $KEYCHAIN_PATH
echo "sign the application"
codesign -s Developer -v --deep --timestamp --entitlements ./pyinstaller_spec/macos_entitlements.plist -o runtime ./dist/empress.app
- name: Compress macos app
# actions/upload-artifact@v2 cannot upload symlinks correctly
# https://github.com/actions/upload-artifact/issues/92
# This can be fixed by zipping the folder before uploading. By doing this, we end up
# double-zipping the file, which is not optimal.
run: |
cd ./dist
zip -r macos_empress_app.zip empress.app
ditto -c -k --keepParent ./dist/empress.app ./dist/macos_empress_app.zip
- name: Send macOS app to Apple's notarizatation service
env:
APPLE_USERNAME: ${{ secrets.APPLE_USERNAME }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
run: |
xcrun altool --notarize-app -t osx -f ./dist/macos_empress_app.zip -u $APPLE_USERNAME -p $APPLE_APP_SPECIFIC_PASSWORD --primary-bundle-id edu.hmc.cs.empress
- name: Upload executable
uses: actions/upload-artifact@v2
with:
Expand Down
13 changes: 11 additions & 2 deletions pyinstaller_spec/empress_gui_app.spec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ a = Analysis(['../empress_gui.py'],
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)

# Windows and Linux
exe = EXE(pyz,
a.scripts,
[],
Expand All @@ -33,6 +35,7 @@ exe = EXE(pyz,
upx=True,
icon='../assets/jane_icon.ico',
console=False)

coll = COLLECT(exe,
a.binaries,
a.zipfiles,
Expand All @@ -41,13 +44,19 @@ coll = COLLECT(exe,
upx=True,
upx_exclude=[],
name='empress')

# macOS
app = BUNDLE(coll,
name='empress.app',
icon='../assets/jane_icon.icns',
bundle_identifier=None,
info_plist={
'NSPrincipalClass': 'NSApplication', # Enable retina display
'CFBundleName': 'Empress DTL Computational Biology Tool', # Enable Siri
# Enable retina display
'NSPrincipalClass': 'NSApplication',
# Enable Siri and Spotlight to search this app
'CFBundleName': 'Empress DTL Computational Biology Tool',
# Set bundle id so gatekeeper can find it
'CFBundleIdentifier': 'edu.hmc.cs.empress',
# Forces macOS to open this app in light mode
'NSRequiresAquaSystemAppearance': True,
}
Expand Down
12 changes: 12 additions & 0 deletions pyinstaller_spec/macos_entitlements.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- Entitlements for code signing on macos. See https://github.com/pyinstaller/pyinstaller/issues/4629#issuecomment-574375331 -->
<?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>
<!-- These are required for binaries built by PyInstaller -->
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
</dict>
</plist>

0 comments on commit 22bbf00

Please sign in to comment.