Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automate signed pkg build for macOS App Store submission #2624

Merged
merged 3 commits into from
Jul 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 62 additions & 5 deletions .github/autobuild/mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ setup() {
}

prepare_signing() {
## Certificate types in use:
# - MACOS_CERTIFICATE - Developer ID Application - for codesigning for adhoc release
# - MAC_STORE_APP_CERT - Mac App Distribution - codesigning for App Store submission
# - MAC_STORE_INST_CERT - Mac Installer Distribution - for signing installer pkg file for App Store submission

[[ "${SIGN_IF_POSSIBLE:-0}" == "1" ]] || return 1

# Signing was requested, now check all prerequisites:
[[ -n "${MACOS_CERTIFICATE:-}" ]] || return 1
[[ -n "${MACOS_CERTIFICATE_ID:-}" ]] || return 1
[[ -n "${MACOS_CERTIFICATE_PWD:-}" ]] || return 1
[[ -n "${NOTARIZATION_PASSWORD:-}" ]] || return 1
[[ -n "${KEYCHAIN_PASSWORD:-}" ]] || return 1

# Check for notarization (not wanted on self signed build)
Expand All @@ -90,8 +96,8 @@ prepare_signing() {

echo "Signing was requested and all dependencies are satisfied"

# Put the cert to a file
echo "${MACOS_CERTIFICATE}" | base64 --decode > certificate.p12
## Put the certs to files
echo "${MACOS_CERTIFICATE}" | base64 --decode > macos_certificate.p12

# If set, put the CA public key into a file
if [[ -n "${MACOS_CA_PUBLICKEY}" ]]; then
Expand All @@ -104,8 +110,8 @@ prepare_signing() {
# Remove default re-lock timeout to avoid codesign hangs:
security set-keychain-settings build.keychain
security unlock-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain
security import certificate.p12 -k build.keychain -P "${MACOS_CERTIFICATE_PWD}" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${KEYCHAIN_PASSWORD}" build.keychain
security import macos_certificate.p12 -k build.keychain -P "${MACOS_CERTIFICATE_PWD}" -A -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" build.keychain

# Tell Github Workflow that we want signing
echo "macos_signed=true" >> "$GITHUB_OUTPUT"
Expand All @@ -125,6 +131,34 @@ prepare_signing() {
echo "macos_notarize=true" >> "$GITHUB_OUTPUT"
fi

# If distribution cert is present, set for store signing + submission
if [[ -n "${MAC_STORE_APP_CERT}" ]]; then

# Check all Github secrets are in place
# MAC_STORE_APP_CERT already checked
[[ -n "${MAC_STORE_APP_CERT_ID:-}" ]] || return 1
[[ -n "${MAC_STORE_APP_CERT_PWD:-}" ]] || return 1
[[ -n "${MAC_STORE_INST_CERT:-}" ]] || return 1
[[ -n "${MAC_STORE_INST_CERT_ID:-}" ]] || return 1
[[ -n "${MAC_STORE_INST_CERT_PWD:-}" ]] || return 1

# Put the certs to files
echo "${MAC_STORE_APP_CERT}" | base64 --decode > macapp_certificate.p12
echo "${MAC_STORE_INST_CERT}" | base64 --decode > macinst_certificate.p12

echo "App Store distribution dependencies are satisfied, proceeding..."

# Add additional certs to the keychain
security set-keychain-settings build.keychain
security unlock-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain
security import macapp_certificate.p12 -k build.keychain -P "${MAC_STORE_APP_CERT_PWD}" -A -T /usr/bin/codesign
security import macinst_certificate.p12 -k build.keychain -P "${MAC_STORE_INST_CERT_PWD}" -A -T /usr/bin/productbuild
security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" build.keychain

# Tell Github Workflow that we are building for store submission
echo "macos_store=true" >> "$GITHUB_OUTPUT"
fi

return 0
}

Expand All @@ -136,7 +170,7 @@ build_app_as_dmg_installer() {
# Mac's bash version considers BUILD_ARGS unset without at least one entry:
BUILD_ARGS=("")
if prepare_signing; then
BUILD_ARGS=("-s" "${MACOS_CERTIFICATE_ID}")
BUILD_ARGS=("-s" "${MACOS_CERTIFICATE_ID}" "-a" "${MAC_STORE_APP_CERT_ID}" "-i" "${MAC_STORE_INST_CERT_ID}" "-k" "${KEYCHAIN_PASSWORD}")
fi
TARGET_ARCHS="${TARGET_ARCHS}" ./mac/deploy_mac.sh "${BUILD_ARGS[@]}"
}
Expand All @@ -146,6 +180,26 @@ pass_artifact_to_job() {
echo "Moving build artifact to deploy/${artifact}"
mv ./deploy/Jamulus-*installer-mac.dmg "./deploy/${artifact}"
echo "artifact_1=${artifact}" >> "$GITHUB_OUTPUT"

artifact2="jamulus_${JAMULUS_BUILD_VERSION}_mac${ARTIFACT_SUFFIX:-}.pkg"
file=(./deploy/Jamulus_*.pkg)
pljones marked this conversation as resolved.
Show resolved Hide resolved
if [ -f "${file[0]}" ]; then
echo "Moving build artifact2 to deploy/${artifact2}"
mv "${file[0]}" "./deploy/${artifact2}"
echo "artifact_2=${artifact2}" >> "$GITHUB_OUTPUT"
fi
}

appstore_submit() {
echo "Submitting package to AppStore Connect..."
# test the signature of package
pkgutil --check-signature "${ARTIFACT_PATH}"

xcrun notarytool submit "${ARTIFACT_PATH}" \
--apple-id "${NOTARIZATION_USERNAME}" \
--team-id "${APPLE_TEAM_ID}" \
--password "${NOTARIZATION_PASSWORD}" \
--wait
}

case "${1:-}" in
Expand All @@ -158,6 +212,9 @@ case "${1:-}" in
get-artifacts)
pass_artifact_to_job
;;
appstore-submit)
appstore_submit
;;
*)
echo "Unknown stage '${1:-}'"
exit 1
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/autobuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,12 @@ jobs:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERT}}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERT_PWD }}
MACOS_CERTIFICATE_ID: ${{ secrets.MACOS_CERT_ID }}
MAC_STORE_APP_CERT: ${{ secrets.MACAPP_CERT}}
MAC_STORE_APP_CERT_PWD: ${{ secrets.MACAPP_CERT_PWD }}
MAC_STORE_APP_CERT_ID: ${{ secrets.MACAPP_CERT_ID }}
MAC_STORE_INST_CERT: ${{ secrets.MACAPP_INST_CERT}}
MAC_STORE_INST_CERT_PWD: ${{ secrets.MACAPP_INST_CERT_PWD }}
MAC_STORE_INST_CERT_ID: ${{ secrets.MACAPP_INST_CERT_ID }}
NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
MACOS_CA_PUBLICKEY: ${{ secrets.MACOS_CA_PUBKEY }}
Expand Down Expand Up @@ -430,6 +436,20 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

## RELEASE PROCEDURE FOR: macOS App Store - storesigned pkg
- name: Validate and Upload macOS Storesign Pkg
if: >-
steps.build.outputs.macos_store == 'true' &&
needs.create_release.outputs.publish_to_release == 'true'
id: macos_validate_upload
run: ${{ matrix.config.base_command }} appstore-submit
env:
ARTIFACT_PATH: deploy/${{ steps.get-artifacts.outputs.artifact_2 }}
NOTARIZATION_USERNAME: ${{ secrets.NOTARIZATION_USERNAME }}
NOTARIZATION_PASSWORD: ${{ secrets.NOTARIZATION_PASSWORD }}
JAMULUS_BUILD_VERSION: ${{ needs.create_release.outputs.build_version }}
APPLE_TEAM_ID: XXXXXXXXXXX

- name: Perform CodeQL Analysis
if: matrix.config.run_codeql
uses: github/codeql-action/analyze@v3
Expand Down
48 changes: 42 additions & 6 deletions mac/deploy_mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,36 @@ resources_path="${root_path}/src/res"
build_path="${root_path}/build"
deploy_path="${root_path}/deploy"
cert_name=""
macapp_cert_name=""
macinst_cert_name=""
keychain_pass=""

while getopts 'hs:' flag; do
while getopts 'hs:k:a:i:' flag; do
case "${flag}" in
s)
cert_name=$OPTARG
if [[ -z "$cert_name" ]]; then
echo "Please add the name of the certificate to use: -s \"<name>\""
fi
;;
a)
macapp_cert_name=$OPTARG
if [[ -z "$macapp_cert_name" ]]; then
echo "Please add the name of the codesigning certificate to use: -a \"<name>\""
fi
;;
i)
macinst_cert_name=$OPTARG
if [[ -z "$macinst_cert_name" ]]; then
echo "Please add the name of the installer signing certificate to use: -i \"<name>\""
fi
;;
k)
keychain_pass=$OPTARG
if [[ -z "$keychain_pass" ]]; then
echo "Please add keychain password to use: -k \"<name>\""
fi
;;
h)
echo "Usage: -s <cert name> for signing mac build"
exit 0
Expand Down Expand Up @@ -83,6 +104,25 @@ build_app() {
else
macdeployqt "${build_path}/${target_name}.app" -verbose=2 -always-overwrite -hardened-runtime -timestamp -appstore-compliant -sign-for-notarization="${cert_name}"
fi

## Build installer pkg file - for submission to App Store
if [[ -z "$macapp_cert_name" ]]; then
echo "No cert to sign for App Store, bypassing..."
else
# Clone the build directory to leave the adhoc signed app untouched
cp -a "${build_path}" "${build_path}_storesign"

# Add Qt deployment deps and codesign the app for App Store submission
macdeployqt "${build_path}_storesign/${target_name}.app" -verbose=2 -always-overwrite -hardened-runtime -timestamp -appstore-compliant -sign-for-notarization="${macapp_cert_name}"

# Create pkg installer and sign for App Store submission
productbuild --sign "${macinst_cert_name}" --keychain build.keychain --component "${build_path}_storesign/${target_name}.app" /Applications "${build_path}/Jamulus_${JAMULUS_BUILD_VERSION}.pkg"

# move created pkg file to prep for download
mv "${build_path}/Jamulus_${JAMULUS_BUILD_VERSION}.pkg" "${deploy_path}"
fi

# move app bundle to prep for dmg creation
mv "${build_path}/${target_name}.app" "${deploy_path}"

# Cleanup
Expand Down Expand Up @@ -114,10 +154,6 @@ build_installer_image() {
# FIXME: Currently caching is disabled due to an error in the extract step
brew install create-dmg

# Get Jamulus version
local app_version
app_version=$(sed -nE 's/^VERSION *= *(.*)$/\1/p' "${project_path}")

# Build installer image

# When this script is run on Github's CI with CodeQL enabled, CodeQL adds dynamic library
Expand All @@ -141,7 +177,7 @@ build_installer_image() {
--icon "${client_target_name}.app" 630 210 \
--icon "${server_target_name}.app" 530 210 \
--eula "${root_path}/COPYING" \
"${deploy_path}/${client_target_name}-${app_version}-installer-mac.dmg" \
"${deploy_path}/${client_target_name}-${JAMULUS_BUILD_VERSION}-installer-mac.dmg" \
"${deploy_path}/"
}

Expand Down