Files
strawberry/build_tools/macos/find_mas_provisioning_profile.sh
David Helkowski c26e09e90b Enhance macOS provisioning profile handling in build scripts and documentation
This commit updates the check_signing_identities.sh script to search for provisioning profiles in multiple common directories, improving the detection process. Additionally, the README_MAS.md is updated to clarify where provisioning profiles are stored in newer Xcode versions and provides guidance on locating the correct profile for Mac App Store builds. This enhances the overall usability and clarity for developers working with macOS builds.
2026-01-22 20:38:28 +09:00

168 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ts() { date +"%H:%M:%S"; }
usage() {
cat <<'EOF'
Usage:
./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry
What it does:
- Scans common macOS provisioning profile locations (new Xcode + legacy)
- Decodes each *.provisionprofile (CMS) into plist
- Prints a readable table and recommends a best match for the given bundle id
Notes:
- A provisioning profile is required for Mac App Store signing.
- This script only helps you *find* the right profile file.
EOF
}
if [[ "$(uname -s)" != "Darwin" ]]; then
echo "Error: This script is for macOS only." >&2
exit 1
fi
bundle_id=""
while [[ $# -gt 0 ]]; do
case "$1" in
--bundle-id) bundle_id="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
esac
done
if [[ -z "$bundle_id" ]]; then
echo "Error: missing --bundle-id" >&2
usage
exit 2
fi
if ! command -v security >/dev/null 2>&1; then
echo "Error: 'security' not found." >&2
exit 1
fi
plutil_extract() {
local keypath="$1"
local plist="$2"
/usr/bin/plutil -extract "$keypath" raw -o - "$plist" 2>/dev/null || true
}
find_profiles_in_dir() {
local dir="$1"
if [[ -d "$dir" ]]; then
find "$dir" -maxdepth 1 -type f -name "*.provisionprofile" 2>/dev/null || true
fi
}
declare -a candidates
candidates=()
# Newer Xcode location (as reported by user)
while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles")
# Legacy location
while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/MobileDevice/Provisioning Profiles")
if [[ ${#candidates[@]} -eq 0 ]]; then
echo "==> [$(ts)] No .provisionprofile files found in common locations."
echo "Checked:"
echo " - $HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
echo " - $HOME/Library/MobileDevice/Provisioning Profiles"
exit 1
fi
echo "==> [$(ts)] Scanning ${#candidates[@]} provisioning profile(s) for bundle id: ${bundle_id}"
echo
best_score=-1
best_path=""
best_reason=""
printf "%-4s %-36s %-10s %-25s %-40s %s\n" "No." "UUID" "TeamID" "Expires" "AppID" "Path"
printf "%s\n" "---- ------------------------------------ ---------- ------------------------- ---------------------------------------- ----"
idx=0
for f in "${candidates[@]}"; do
idx=$((idx + 1))
tmp="$(mktemp -t strawberry-profile.XXXXXX.plist)"
if ! security cms -D -i "$f" >"$tmp" 2>/dev/null; then
rm -f "$tmp" >/dev/null 2>&1 || true
continue
fi
uuid="$(plutil_extract UUID "$tmp")"
name="$(plutil_extract Name "$tmp")"
teamid="$(plutil_extract 'TeamIdentifier.0' "$tmp")"
exp="$(plutil_extract ExpirationDate "$tmp")"
# Profiles vary in which key they use for the app identifier.
appid="$(plutil_extract 'Entitlements.application-identifier' "$tmp")"
if [[ -z "$appid" ]]; then
appid="$(plutil_extract 'Entitlements.com.apple.application-identifier' "$tmp")"
fi
rm -f "$tmp" >/dev/null 2>&1 || true
# Fallbacks for display.
[[ -z "$uuid" ]] && uuid="(unknown)"
[[ -z "$teamid" ]] && teamid="(unknown)"
[[ -z "$exp" ]] && exp="(unknown)"
[[ -z "$appid" ]] && appid="(unknown)"
printf "%-4s %-36s %-10s %-25s %-40s %s\n" "$idx" "$uuid" "$teamid" "$exp" "$appid" "$f"
# Score match quality.
score=0
reason=""
# Prefer exact team+bundle match.
if [[ "$appid" != "(unknown)" && "$teamid" != "(unknown)" ]]; then
if [[ "$appid" == "${teamid}.${bundle_id}" ]]; then
score=100
reason="exact match (${appid})"
elif [[ "$appid" == "${teamid}."* && "$appid" == *"*"* ]]; then
# Wildcard profile like TEAMID.*
score=60
reason="wildcard match (${appid})"
elif [[ "$appid" == *".${bundle_id}" ]]; then
score=50
reason="endswith match (${appid})"
fi
fi
# Prefer profiles with a plausible name for MAS (heuristic).
if [[ "$score" -gt 0 && -n "$name" ]]; then
case "$name" in
*Mac\ App\ Store*|*App\ Store*|*appstore*|*AppStore*)
score=$((score + 5))
reason="${reason}, name looks like MAS"
;;
esac
fi
if [[ "$score" -gt "$best_score" ]]; then
best_score="$score"
best_path="$f"
best_reason="$reason"
fi
done
echo
if [[ "$best_score" -le 0 ]]; then
echo "==> [$(ts)] Could not confidently auto-select a profile for ${bundle_id}."
echo "Pick the profile whose AppID is TEAMID.${bundle_id} and is a macOS Mac App Store profile."
exit 2
fi
echo "==> [$(ts)] Recommended profile:"
echo " $best_path"
echo " reason: $best_reason"
echo
echo "Use it like:"
echo " ./build_tools/macos/build_mas_pkg.sh --run ... --provisionprofile \"$best_path\""