diff --git a/.github/workflows/macos-app-release.yml b/.github/workflows/macos-app-release.yml index c5e05ee..ca44b6c 100644 --- a/.github/workflows/macos-app-release.yml +++ b/.github/workflows/macos-app-release.yml @@ -128,6 +128,7 @@ jobs: || { echo "::error::CFBundleExecutable in $INFO_PLIST is not $EXECUTABLE"; exit 1; } if [[ "$GITHUB_REF_TYPE" == tag ]]; then + [[ "$GITHUB_REF_NAME" == v* ]] || { echo "::error::Tag $GITHUB_REF_NAME must start with v (v1.2.3)"; exit 1; } version="${GITHUB_REF_NAME#v}" elif [[ "$DRY_RUN" == true ]]; then version="$(plist_get CFBundleShortVersionString)" @@ -139,11 +140,11 @@ jobs: fi if [[ "$HAS_APP_CERT" == true ]]; then - missing=() - [[ "$HAS_P12_PASSWORD" == true ]] || missing+=(P12_PASSWORD) - [[ "$HAS_NOTARY_KEY" == true ]] || missing+=(ASC_KEY_ID/ASC_ISSUER_ID/ASC_KEY_P8_BASE64) - if (( ${#missing[@]} )); then - echo "::error::Developer ID certificate present but missing: ${missing[*]}"; exit 1 + missing="" + [[ "$HAS_P12_PASSWORD" == true ]] || missing+=" P12_PASSWORD" + [[ "$HAS_NOTARY_KEY" == true ]] || missing+=" ASC_KEY_ID/ASC_ISSUER_ID/ASC_KEY_P8_BASE64" + if [[ -n "$missing" ]]; then + echo "::error::Developer ID certificate present but missing:$missing"; exit 1 fi fi @@ -217,7 +218,7 @@ jobs: security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$keychain_password" "$KEYCHAIN" > /dev/null existing=() while IFS= read -r kc; do existing+=("$kc"); done < <(security list-keychains -d user | tr -d '"' | sed 's/^ *//') - security list-keychains -d user -s "$KEYCHAIN" "${existing[@]}" + security list-keychains -d user -s "$KEYCHAIN" ${existing[@]+"${existing[@]}"} app_identity="$(security find-identity -v -p codesigning "$KEYCHAIN" \ | awk '/"Developer ID Application: / { print $2; exit }')" @@ -308,7 +309,8 @@ jobs: else echo "::warning title=Unsigned pkg::$STEM.pkg is not signed (no DEVELOPER_ID_INSTALLER_P12_BASE64). Intune line-of-business deployment needs a Developer ID Installer signature." fi - productbuild --package "$component_pkg" "${sign[@]}" "$DIST/$STEM.pkg" + # ${a[@]+...}: macOS /bin/bash is 3.2, where an empty array trips `set -u`. + productbuild --package "$component_pkg" ${sign[@]+"${sign[@]}"} "$DIST/$STEM.pkg" pkgutil --check-signature "$DIST/$STEM.pkg" || true - name: Notarise and staple the pkg diff --git a/docs/releasing-macos-apps.md b/docs/releasing-macos-apps.md index 2346485..0210a66 100644 --- a/docs/releasing-macos-apps.md +++ b/docs/releasing-macos-apps.md @@ -102,7 +102,7 @@ them to both repos' `release` environments, and closes the vault again, even if a step fails. ```zsh -VAULT= # the Lucid platform Key Vault +VAULT="" # replace with the Lucid platform Key Vault name REPOS=(LucidLabsAU/sitrep LucidLabsAU/timer) MYIP=$(curl -fsS https://api.ipify.org) read -rs 'P12PW?.p12 export password: '; echo @@ -110,7 +110,8 @@ read -r 'KEYID?ASC key ID: ' read -r 'ISSUER?ASC issuer ID: ' az keyvault network-rule add --name "$VAULT" --ip-address "$MYIP/32" -o none -{ +{ ( + setopt err_exit pipe_fail # stop at the first failure; the always block still closes the vault az keyvault secret set --vault-name "$VAULT" -o none --name apple-developer-id-app-p12 --file DeveloperIDApplication.p12 --encoding base64 az keyvault secret set --vault-name "$VAULT" -o none --name apple-developer-id-installer-p12 --file DeveloperIDInstaller.p12 --encoding base64 az keyvault secret set --vault-name "$VAULT" -o none --name apple-asc-key-p8 --file AuthKey_"$KEYID".p8 --encoding base64 @@ -131,13 +132,21 @@ az keyvault network-rule add --name "$VAULT" --ip-address "$MYIP/32" -o none | tr -d '\n' | gh secret set "${pair%%:*}" --env release --repo "$repo" done done -} always { - az keyvault network-rule remove --name "$VAULT" --ip-address "$MYIP/32" -o none +) } always { + az keyvault network-rule remove --name "$VAULT" --ip-address "$MYIP/32" -o none \ + || print -u2 "✗ could not remove $MYIP/32 from $VAULT: remove it by hand now" unset P12PW } -az keyvault network-rule list --name "$VAULT" --query ipRules -o tsv # expect nothing +rules=$(az keyvault network-rule list --name "$VAULT" --query "ipRules[].value" -o tsv) \ + && [[ $rules != *"$MYIP"* ]] \ + && print "✓ vault closed to $MYIP" \ + || print -u2 "✗ can't confirm $MYIP was removed from $VAULT: check its network rules now" ``` +If a step fails, the block stops there, the vault still closes, and zsh +reports the failing command. Every command can safely run twice, so fix the +cause and run the block again. + Then keep the `.p12` files and `.p8` out of Downloads and cloud-synced folders, or delete them; Key Vault is the copy of record. To onboard another app repo later, create its `release` environment (required reviewer, `main` and `v*` @@ -184,7 +193,9 @@ Verify a download: shasum -a 256 -c SHA256SUMS.txt spctl --assess --type execute --verbose=2 Sitrep.app # source=Notarized Developer ID xcrun stapler validate Sitrep.app -pkgutil --check-signature Sitrep-1.0.0.pkg # Developer ID Installer, notarised +pkgutil --check-signature Sitrep-1.0.0.pkg # Developer ID Installer signature +xcrun stapler validate Sitrep-1.0.0.pkg # notarisation ticket stapled +spctl --assess --type install --verbose=2 Sitrep-1.0.0.pkg # source=Notarized Developer ID lipo -archs Sitrep.app/Contents/MacOS/Sitrep # x86_64 arm64 ```