This commit improves the `find_mas_provisioning_profile.sh` script by expanding the search for provisioning profiles to include both `.provisionprofile` and `.mobileprovision` files. It also introduces a new function to print SHA-1 values for identities, helping to avoid ambiguity when multiple identities share the same display name. Additionally, the `check_signing_identities.sh` script is updated to provide clearer recommendations for using SHA-1 hashes with codesigning and installer identities, enhancing the overall usability and clarity for developers working with macOS builds.
247 lines
8.4 KiB
Bash
Executable File
247 lines
8.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ts() { date +"%H:%M:%S"; }
|
|
lower() { echo "$1" | tr '[:upper:]' '[:lower:]'; }
|
|
|
|
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd -- "${script_dir}/../.." && pwd)"
|
|
|
|
ensure_keychain_search_list() {
|
|
# codesign builds the cert chain using the user keychain search list.
|
|
# If the list is missing the System keychain, you can get:
|
|
# "unable to build chain to self-signed root" + errSecInternalComponent
|
|
local login_kc="$HOME/Library/Keychains/login.keychain-db"
|
|
local system_kc="/Library/Keychains/System.keychain"
|
|
local roots_kc="/System/Library/Keychains/SystemRootCertificates.keychain"
|
|
|
|
local current
|
|
current="$(security list-keychains -d user 2>/dev/null | tr -d '"' | tr -d ' ' || true)"
|
|
|
|
if echo "$current" | grep -Fq "$system_kc"; then
|
|
return 0
|
|
fi
|
|
|
|
echo "==> [$(ts)] Note: adding System keychains to the user keychain search list (fixes common codesign chain errors)"
|
|
echo " (This changes the user keychain search list; run 'security list-keychains -d user' to view.)"
|
|
security list-keychains -d user -s "$login_kc" "$system_kc" "$roots_kc" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
|
|
preflight_identity() {
|
|
local what="$1"
|
|
local policy="$2"
|
|
local identity="$3"
|
|
|
|
# NOTE: security expects "-p <policy>" as *two* args; do not pass "-p codesigning" as one string.
|
|
if ! security find-identity -p "$policy" -v 2>/dev/null | grep -Fq "$identity"; then
|
|
echo "Error: ${what} identity not found/usable in Keychain: $identity" >&2
|
|
echo "Run: ./build_tools/macos/check_signing_identities.sh" >&2
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./build_tools/macos/build_mas_pkg.sh --run [options]
|
|
|
|
What it does:
|
|
- Builds Strawberry in Mac App Store mode (BUILD_FOR_MAC_APP_STORE=ON)
|
|
- Runs deploy (macdeployqt + bundling) so the app bundle is self-contained
|
|
- Embeds a Mac App Store provisioning profile into the app bundle
|
|
- Codesigns the app with an Apple Distribution identity + entitlements
|
|
- Builds a signed .pkg suitable for uploading to App Store Connect
|
|
|
|
Required options:
|
|
--run
|
|
--codesign-identity "<name>" (e.g. "Apple Distribution: Dry Ark LLC (TEAMID)")
|
|
--installer-identity "<name>" (e.g. "3rd Party Mac Developer Installer: Dry Ark LLC (TEAMID)")
|
|
--provisionprofile <path> Path to a *Mac App Store* provisioning profile (*.provisionprofile)
|
|
|
|
Optional:
|
|
--release | --debug Build config (default: Release)
|
|
--clean Clean build dir before build
|
|
--build-dir <path> Override build directory
|
|
--entitlements <plist> Codesign entitlements (default: dist/macos/entitlements.mas.plist)
|
|
--bundle-id <id> Override CFBundleIdentifier (default: com.dryark.strawberry)
|
|
--pkg-out <path> Output .pkg path (default: <build-dir>/strawberry-mas.pkg)
|
|
|
|
Examples:
|
|
./build_tools/macos/build_mas_pkg.sh --run --release --clean \
|
|
--codesign-identity "Apple Distribution: Your Name (TEAMID)" \
|
|
--installer-identity "3rd Party Mac Developer Installer: Your Name (TEAMID)" \
|
|
--provisionprofile "$HOME/Library/MobileDevice/Provisioning Profiles/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.provisionprofile"
|
|
|
|
Notes:
|
|
- Mac App Store submissions do NOT use Developer ID notarization.
|
|
- You must create a Mac App Store provisioning profile for your App ID in Apple Developer.
|
|
EOF
|
|
}
|
|
|
|
if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
echo "Error: This script is for macOS only." >&2
|
|
exit 1
|
|
fi
|
|
|
|
do_run=0
|
|
config="Release"
|
|
do_clean=0
|
|
build_dir=""
|
|
codesign_identity=""
|
|
installer_identity=""
|
|
provisionprofile=""
|
|
entitlements=""
|
|
bundle_id="com.dryark.strawberry"
|
|
pkg_out=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--run) do_run=1; shift ;;
|
|
--release) config="Release"; shift ;;
|
|
--debug) config="Debug"; shift ;;
|
|
--clean) do_clean=1; shift ;;
|
|
--build-dir) build_dir="${2:-}"; shift 2 ;;
|
|
--codesign-identity) codesign_identity="${2:-}"; shift 2 ;;
|
|
--installer-identity) installer_identity="${2:-}"; shift 2 ;;
|
|
--provisionprofile) provisionprofile="${2:-}"; shift 2 ;;
|
|
--entitlements) entitlements="${2:-}"; shift 2 ;;
|
|
--bundle-id) bundle_id="${2:-}"; shift 2 ;;
|
|
--pkg-out) pkg_out="${2:-}"; shift 2 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
if [[ "$do_run" -eq 0 ]]; then
|
|
usage
|
|
echo
|
|
echo "==> [$(ts)] Tip: list available signing identities:"
|
|
echo " security find-identity -p codesigning -v"
|
|
echo " security find-identity -p basic -v"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ -z "$codesign_identity" ]]; then
|
|
echo "Error: missing --codesign-identity" >&2
|
|
exit 2
|
|
fi
|
|
if [[ -z "$installer_identity" ]]; then
|
|
echo "Error: missing --installer-identity" >&2
|
|
exit 2
|
|
fi
|
|
if [[ -z "$provisionprofile" || ! -f "$provisionprofile" ]]; then
|
|
echo "Error: missing/invalid --provisionprofile: $provisionprofile" >&2
|
|
exit 2
|
|
fi
|
|
|
|
if [[ -z "$entitlements" ]]; then
|
|
entitlements="${repo_root}/dist/macos/entitlements.mas.plist"
|
|
fi
|
|
if [[ ! -f "$entitlements" ]]; then
|
|
echo "Error: entitlements file not found: $entitlements" >&2
|
|
exit 2
|
|
fi
|
|
|
|
if [[ -z "$build_dir" ]]; then
|
|
build_dir="${repo_root}/cmake-build-macos-$(lower "$config")-mas"
|
|
fi
|
|
|
|
if [[ -z "$pkg_out" ]]; then
|
|
pkg_out="${build_dir}/strawberry-mas.pkg"
|
|
fi
|
|
|
|
echo "==> [$(ts)] Repo: ${repo_root}"
|
|
echo "==> [$(ts)] Build dir: ${build_dir}"
|
|
echo "==> [$(ts)] Config: ${config}"
|
|
echo "==> [$(ts)] Bundle ID: ${bundle_id}"
|
|
echo "==> [$(ts)] Entitlements: ${entitlements}"
|
|
echo "==> [$(ts)] Provisioning profile: ${provisionprofile}"
|
|
echo "==> [$(ts)] Output pkg: ${pkg_out}"
|
|
|
|
echo "==> [$(ts)] Building (Mac App Store mode)"
|
|
build_args=( "--release" )
|
|
if [[ "$config" == "Debug" ]]; then build_args=( "--debug" ); fi
|
|
if [[ "$do_clean" -eq 1 ]]; then build_args+=( "--clean" ); fi
|
|
build_args+=( "--build-dir" "$build_dir" "--mas" "--deploy" )
|
|
|
|
# Provide bundle id via CMake cache variable.
|
|
export MACOS_BUNDLE_ID="$bundle_id"
|
|
|
|
"${repo_root}/build_tools/macos/build_app.sh" "${build_args[@]}"
|
|
|
|
app_path="${build_dir}/strawberry.app"
|
|
bin_path="${app_path}/Contents/MacOS/strawberry"
|
|
if [[ ! -x "$bin_path" ]]; then
|
|
echo "Error: built app not found at: $app_path" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> [$(ts)] Embedding provisioning profile"
|
|
cp -f "$provisionprofile" "${app_path}/Contents/embedded.provisionprofile"
|
|
|
|
ensure_keychain_search_list
|
|
preflight_identity "codesign" "codesigning" "$codesign_identity"
|
|
preflight_identity "installer" "basic" "$installer_identity"
|
|
|
|
|
|
|
|
echo "==> [$(ts)] Codesigning app (Mac App Store)"
|
|
codesign_args=( --force --timestamp --options runtime --sign "$codesign_identity" --entitlements "$entitlements" )
|
|
|
|
# Clean up any leftover codesign temp files from previous interrupted runs.
|
|
find "$app_path" -name "*.cstemp" -print0 2>/dev/null | while IFS= read -r -d '' f; do
|
|
rm -f "$f" || true
|
|
done
|
|
|
|
# Clear macOS provenance/quarantine metadata which can interfere with modifying files in-place.
|
|
xattr -dr com.apple.provenance "$app_path" >/dev/null 2>&1 || true
|
|
xattr -dr com.apple.quarantine "$app_path" >/dev/null 2>&1 || true
|
|
|
|
# Sign nested code first, then frameworks, then the main app bundle.
|
|
find "$app_path" -type f \( -name "*.dylib" -o -name "*.so" -o -perm -111 \) \
|
|
! -name "*.cstemp" \
|
|
! -path "*/Contents/Frameworks/*.framework/*" \
|
|
! -path "*/Contents/Frameworks/*.app/*" \
|
|
! -path "*/Contents/Frameworks/*.xpc/*" \
|
|
! -path "*/Contents/PlugIns/*.framework/*" \
|
|
! -path "*/Contents/PlugIns/*.app/*" \
|
|
! -path "*/Contents/PlugIns/*.xpc/*" \
|
|
-print0 | while IFS= read -r -d '' f; do
|
|
# Only sign Mach-O binaries.
|
|
if file -b "$f" | grep -q "Mach-O"; then
|
|
codesign "${codesign_args[@]}" "$f" >/dev/null
|
|
fi
|
|
done
|
|
|
|
find "$app_path" -type d \( -name "*.xpc" -o -name "*.app" \) -print0 2>/dev/null | while IFS= read -r -d '' b; do
|
|
codesign "${codesign_args[@]}" "$b" >/dev/null
|
|
done
|
|
|
|
find "$app_path/Contents/Frameworks" "$app_path/Contents/PlugIns" -type d -name "*.framework" -print0 2>/dev/null | while IFS= read -r -d '' fw; do
|
|
codesign "${codesign_args[@]}" "$fw" >/dev/null
|
|
done
|
|
|
|
codesign "${codesign_args[@]}" "$app_path" >/dev/null
|
|
|
|
echo "==> [$(ts)] Verifying codesign"
|
|
codesign --verify --deep --strict --verbose=2 "$app_path"
|
|
|
|
echo "==> [$(ts)] Building signed .pkg for App Store upload"
|
|
rm -f "$pkg_out" >/dev/null 2>&1 || true
|
|
|
|
productbuild \
|
|
--component "$app_path" /Applications \
|
|
--sign "$installer_identity" \
|
|
"$pkg_out"
|
|
|
|
echo "==> [$(ts)] Verifying pkg signature"
|
|
pkgutil --check-signature "$pkg_out" || true
|
|
|
|
echo
|
|
echo "Done."
|
|
echo "App: $app_path"
|
|
echo "PKG: $pkg_out"
|
|
|