From 41527292bcccb90a4cbb0b31dd11f5de8fa8fd1d Mon Sep 17 00:00:00 2001 From: Dan G Date: Wed, 3 Jul 2024 22:58:27 +0100 Subject: [PATCH 1/3] Add signed package build and App Store submission This commit combines all the changes made by Dan G into one. --- .github/autobuild/mac.sh | 56 ++++++++++++++++++++++++++++++--- .github/workflows/autobuild.yml | 20 ++++++++++++ mac/deploy_mac.sh | 48 ++++++++++++++++++++++++---- 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/.github/autobuild/mac.sh b/.github/autobuild/mac.sh index 9db7ac6885..d61d00d874 100755 --- a/.github/autobuild/mac.sh +++ b/.github/autobuild/mac.sh @@ -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 # Check for notarization (not wanted on self signed build) @@ -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 @@ -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 + 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" @@ -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[@]}" } @@ -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 @@ -158,6 +201,9 @@ case "${1:-}" in get-artifacts) pass_artifact_to_job ;; + appstore-submit) + appstore_submit + ;; *) echo "Unknown stage '${1:-}'" exit 1 diff --git a/.github/workflows/autobuild.yml b/.github/workflows/autobuild.yml index 09cc7bf3d8..14fd1cf87e 100644 --- a/.github/workflows/autobuild.yml +++ b/.github/workflows/autobuild.yml @@ -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 }} @@ -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 diff --git a/mac/deploy_mac.sh b/mac/deploy_mac.sh index 1f48570066..3833ade050 100755 --- a/mac/deploy_mac.sh +++ b/mac/deploy_mac.sh @@ -7,8 +7,11 @@ 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 @@ -16,6 +19,24 @@ while getopts 'hs:' flag; do echo "Please add the name of the certificate to use: -s \"\"" fi ;; + a) + macapp_cert_name=$OPTARG + if [[ -z "$macapp_cert_name" ]]; then + echo "Please add the name of the codesigning certificate to use: -a \"\"" + 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 \"\"" + fi + ;; + k) + keychain_pass=$OPTARG + if [[ -z "$keychain_pass" ]]; then + echo "Please add keychain password to use: -k \"\"" + fi + ;; h) echo "Usage: -s for signing mac build" exit 0 @@ -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 @@ -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 @@ -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}/" } From 5ceb58e944bd7666f148542d175776962de85376 Mon Sep 17 00:00:00 2001 From: danryu Date: Wed, 17 Jul 2024 20:18:43 +0200 Subject: [PATCH 2/3] separate logic for apple appstore signing/distribution --- .github/autobuild/mac.sh | 46 +++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/.github/autobuild/mac.sh b/.github/autobuild/mac.sh index d61d00d874..977cad8e23 100755 --- a/.github/autobuild/mac.sh +++ b/.github/autobuild/mac.sh @@ -82,12 +82,6 @@ prepare_signing() { [[ -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 @@ -105,14 +99,6 @@ prepare_signing() { ## 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 echo "${MACOS_CA_PUBLICKEY}" | base64 --decode > CA.cer @@ -121,12 +107,10 @@ prepare_signing() { # Set up a keychain for the build: security create-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain security default-keychain -s build.keychain - # Remove default re-lock timeout to avoid codesign hangs: + # # 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 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 security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" build.keychain # Tell Github Workflow that we want signing @@ -147,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 } From c408aa8014175e60eedea8882c4cb1caa0fecef8 Mon Sep 17 00:00:00 2001 From: danryu Date: Sun, 21 Jul 2024 09:32:21 +0200 Subject: [PATCH 3/3] tidy-ups --- .github/autobuild/mac.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/autobuild/mac.sh b/.github/autobuild/mac.sh index 977cad8e23..7540a886e7 100755 --- a/.github/autobuild/mac.sh +++ b/.github/autobuild/mac.sh @@ -107,7 +107,7 @@ prepare_signing() { # Set up a keychain for the build: security create-keychain -p "${KEYCHAIN_PASSWORD}" build.keychain security default-keychain -s build.keychain - # # Remove default re-lock timeout to avoid codesign hangs: + # 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 macos_certificate.p12 -k build.keychain -P "${MACOS_CERTIFICATE_PWD}" -A -T /usr/bin/codesign @@ -182,13 +182,12 @@ pass_artifact_to_job() { 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 + file=(./deploy/Jamulus_*.pkg) + 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() {