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

Add signed package build and App Store submission for Mac #3309

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
56 changes: 51 additions & 5 deletions .github/autobuild/mac.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,24 @@ 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 "${MAC_STORE_APP_CERT:-}" ]] || return 1
[[ -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
[[ -n "${NOTARIZATION_PASSWORD:-}" ]] || return 1
[[ -n "${KEYCHAIN_PASSWORD:-}" ]] || return 1
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This suggests that signing will be aborted if we do not also have certificates for app store submission. We need a way to allow just signing without store submission.


# Check for notarization (not wanted on self signed build)
Expand All @@ -90,8 +102,16 @@ 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 distribution cert is present, set for store signing + submission
if [[ -n "${MAC_STORE_APP_CERT}" ]]; then
echo "${MAC_STORE_APP_CERT}" | base64 --decode > macapp_certificate.p12
echo "${MAC_STORE_INST_CERT}" | base64 --decode > macinst_certificate.p12
# Tell Github Workflow that we are building for store submission
echo "macos_store=true" >> "$GITHUB_OUTPUT"
fi

# If set, put the CA public key into a file
if [[ -n "${MACOS_CA_PUBLICKEY}" ]]; then
Expand All @@ -104,8 +124,10 @@ 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 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ok even if no macinst_certificate or macapp_certificate exists?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just looking through the logic. I suspect we need to add some checks to allow signing without app store submission. At the moment it appears that signing will be skipped if the app store certificates are not also available. I'll raise a comment at the relevant place.

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 Down Expand Up @@ -136,7 +158,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 +168,27 @@ 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"
for file in ./deploy/Jamulus_*.pkg; do
if [ -f "${file}" ]; then
echo "Moving build artifact2 to deploy/${artifact2}"
mv "${file}" "./deploy/${artifact2}"
echo "artifact_2=${artifact2}" >> "$GITHUB_OUTPUT"
fi
done
}

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 +201,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