Sign and notarize macOS bundles

(cherry picked from commit 2482ecf9fe)
Signed-off-by: Itms <itms@wildfiregames.com>
This commit is contained in:
Itms 2024-12-31 13:26:55 +01:00
parent 90762a7626
commit 6cdf1d5a15
No known key found for this signature in database
GPG key ID: C7E52BD14CE14E09
4 changed files with 77 additions and 6 deletions

View file

@ -69,7 +69,22 @@ pipeline {
stage("Create Native macOS Bundle") {
steps {
sh "/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py --min_osx=${env.MIN_OSX_VERSION} ${params.BUNDLE_VERSION}"
withCredentials([
string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'),
string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'),
usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')])
{
sh '''
security unlock-keychain -p ${KEYCHAIN_PW} login.keychain
/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \
--min_osx=${MIN_OSX_VERSION} \
-s ${SIGNKEY_SHA} \
--notarytool_user=${NOTARIZATION_USER} \
--notarytool_team=P7YF26GARW \
--notarytool_password=${NOTARIZATION_PW} \
${BUNDLE_VERSION}
'''
}
}
}
@ -90,7 +105,23 @@ pipeline {
stage("Create Intel macOS Bundle") {
steps {
sh "/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py --architecture=x86_64 --min_osx=${env.MIN_OSX_VERSION} ${params.BUNDLE_VERSION}"
withCredentials([
string(credentialsId: 'apple-keychain', variable: 'KEYCHAIN_PW'),
string(credentialsId: 'apple-signing', variable: 'SIGNKEY_SHA'),
usernamePassword(credentialsId: 'apple-notarization', passwordVariable: 'NOTARIZATION_PW', usernameVariable: 'NOTARIZATION_USER')])
{
sh '''
security unlock-keychain -p ${KEYCHAIN_PW} login.keychain
/opt/wfg/venv/bin/python3 source/tools/dist/build-osx-bundle.py \
--architecture=x86_64 \
--min_osx=${MIN_OSX_VERSION} \
-s ${SIGNKEY_SHA} \
--notarytool_user=${NOTARIZATION_USER} \
--notarytool_team=P7YF26GARW \
--notarytool_password=${NOTARIZATION_PW} \
${BUNDLE_VERSION}
'''
}
}
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2012 Wildfire Games.
/* Copyright (C) 2025 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -32,7 +32,7 @@
* Check if app is running in a valid bundle
*
* @return true if valid bundle reference was found matching identifier
* property "com.wildfiregames.0ad"
* property "com.wildfiregames.play0ad"
*/
bool osx_IsAppBundleValid();

12
source/tools/dist/0ad.entitlements vendored Normal file
View file

@ -0,0 +1,12 @@
<?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>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View file

@ -15,6 +15,7 @@ import glob
import os
import plistlib
import shutil
import subprocess
import dmgbuild
@ -25,7 +26,11 @@ parser.add_argument('--architecture', help='aarch64 (arm64) or x86_64 (amd64)',
parser.add_argument('--min_osx', help='Minimum supported OSX version',
default='10.12')
parser.add_argument('--bundle_identifier', help='Bundle identifier',
default='com.wildfiregames.0ad')
default='com.wildfiregames.play0ad')
parser.add_argument('-s', '--signkey', help='Signature key sha sum')
parser.add_argument('--notarytool_user', help='Apple ID user for notarization')
parser.add_argument('--notarytool_team', help='Team ID for notarization')
parser.add_argument('--notarytool_password', help='App password for notarization')
parser.add_argument('--dev', help='Turn on dev mode, which isn\'t fit for release but faster',
action="store_true")
args = parser.parse_args()
@ -35,6 +40,11 @@ BUNDLE_IDENTIFIER = args.bundle_identifier
BUNDLE_VERSION = args.bundle_version
BUNDLE_MIN_OSX_VERSION = args.min_osx
SIGNKEY = args.signkey
NOTARYTOOL_USER = args.notarytool_user
NOTARYTOOL_TEAM = args.notarytool_team
NOTARYTOOL_PASSWORD = args.notarytool_password
BUNDLE_DMG_NAME = f"0ad-{BUNDLE_VERSION}-macos-{ARCH}"
BUNDLE_OUTPUT = "0 A.D..app"
BUNDLE_CONTENTS = BUNDLE_OUTPUT + "/Contents"
@ -65,6 +75,12 @@ shutil.copy("binaries/system/libAtlasUI.dylib", BUNDLE_FRAMEWORKS)
shutil.copy("binaries/system/libCollada.dylib", BUNDLE_FRAMEWORKS)
shutil.copy("binaries/system/libMoltenVK.dylib", BUNDLE_FRAMEWORKS)
if not args.dev:
print("Signing libs")
subprocess.run(["codesign", "-s", SIGNKEY, "-f", "--timestamp", BUNDLE_FRAMEWORKS + "/libAtlasUI.dylib"], check=True)
subprocess.run(["codesign", "-s", SIGNKEY, "-f", "--timestamp", BUNDLE_FRAMEWORKS + "/libCollada.dylib"], check=True)
subprocess.run(["codesign", "-s", SIGNKEY, "-f", "--timestamp", BUNDLE_FRAMEWORKS + "/libMoltenVK.dylib"], check=True)
if not args.dev:
print("Copying archived game data from archives/")
for mod in glob.glob("archives/*/"):
@ -138,6 +154,9 @@ if args.dev:
print(f"Dev mode bundle complete, located at {BUNDLE_OUTPUT}")
exit(0)
print("Signing bundle")
subprocess.run(["codesign", "-s", SIGNKEY, "-f", "--timestamp", "-o", "runtime", "--entitlements", "source/tools/dist/0ad.entitlements", BUNDLE_OUTPUT], check=True)
print("Creating .dmg")
# Package the app into a dmg
@ -151,4 +170,13 @@ dmgbuild.build_dmg(
"icon": "build/resources/0ad.icns"
})
print(f"Bundle complete! Located in {BUNDLE_OUTPUT}, compressed as {BUNDLE_DMG_NAME}.dmg.")
print("Signing .dmg")
subprocess.run(["codesign", "-s", SIGNKEY, "-f", "--timestamp", "-i", BUNDLE_IDENTIFIER, BUNDLE_DMG_NAME + ".dmg"], check=True)
print("Notarizing .dmg")
subprocess.run(["xcrun", "notarytool", "submit", BUNDLE_DMG_NAME + ".dmg", "--apple-id", NOTARYTOOL_USER, "--team-id", NOTARYTOOL_TEAM, "--password", NOTARYTOOL_PASSWORD, "--wait"], check=True)
print("Stapling notarization ticket")
subprocess.run(["xcrun", "stapler", "staple", BUNDLE_DMG_NAME + ".dmg"], check=True)
print(f"Bundle complete! Installer located at {BUNDLE_DMG_NAME}.dmg.")