Files
strawberry/build_tools/macos/check_signing_identities.sh
David Helkowski 7a954b3f32 Enhance macOS build scripts for provisioning profile handling and identity management
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.
2026-01-22 21:15:07 +09:00

208 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# macOS signing identity sanity check for:
# - Developer ID (outside Mac App Store)
# - Mac App Store (Apple Distribution + 3rd Party Mac Developer Installer)
ts() { date +"%H:%M:%S"; }
if [[ "$(uname -s)" != "Darwin" ]]; then
echo "Error: This script is for macOS only." >&2
exit 1
fi
echo "==> [$(ts)] Strawberry macOS signing identity check"
echo "==> [$(ts)] Host: $(sw_vers -productName 2>/dev/null || true) $(sw_vers -productVersion 2>/dev/null || true)"
echo
echo "==> [$(ts)] Keychains searched by 'security' (user)"
security list-keychains -d user || true
echo
echo "==> [$(ts)] Valid code signing identities (must include private key)"
codesigning_out="$(security find-identity -p codesigning -v 2>&1 || true)"
echo "$codesigning_out"
echo
echo "==> [$(ts)] Valid installer/pkg identities (must include private key)"
basic_out="$(security find-identity -p basic -v 2>&1 || true)"
echo "$basic_out"
echo
echo "==> [$(ts)] Note"
cat <<'EOF'
- Apple uses multiple certificate types. The "basic" identity list can include certificates that are not usable
for signing a Mac App Store upload package.
- For App Store Connect uploads via .pkg, you typically need an *Installer* identity (e.g. "3rd Party Mac Developer Installer"
or "Mac Installer Distribution") and it must have a private key on this Mac.
EOF
echo
list_cert_labels() {
local query="$1"
# Extract "labl" lines like: "labl"<blob>="Apple Distribution: ..."
security find-certificate -a -c "$query" 2>/dev/null \
| sed -n 's/.*"labl"<blob>="\(.*\)".*/\1/p' \
| sort -u
}
check_label_in_identities() {
local label="$1"
local out="$2"
if echo "$out" | grep -Fq "$label"; then
echo "YES"
else
echo "NO"
fi
}
check_label_in_installer_identities() {
local label="$1"
local out="$2"
# Only treat as installer-capable if the cert label itself is an installer cert.
case "$label" in
*Installer*|*installer*) ;;
*) echo "NO"; return 0 ;;
esac
if echo "$out" | grep -Fq "$label"; then
echo "YES"
else
echo "NO"
fi
}
print_section() {
local title="$1"
shift
local queries=("$@")
echo "==> [$(ts)] ${title}"
local any=0
local q
for q in "${queries[@]}"; do
local labels
labels="$(list_cert_labels "$q" || true)"
if [[ -z "$labels" ]]; then
continue
fi
any=1
while IFS= read -r label; do
[[ -z "$label" ]] && continue
local in_codesign in_basic
in_codesign="$(check_label_in_identities "$label" "$codesigning_out")"
in_basic="$(check_label_in_installer_identities "$label" "$basic_out")"
printf -- "- %s\n" "$label"
printf -- " - codesigning identity: %s\n" "$in_codesign"
printf -- " - installer identity: %s\n" "$in_basic"
if [[ "$in_codesign" == "NO" && "$in_basic" == "NO" ]]; then
printf -- " - note: certificate exists, but it is NOT a usable identity on this Mac (almost always missing private key)\n"
fi
done <<<"$labels"
done
if [[ "$any" -eq 0 ]]; then
echo "(no matching certificates found)"
fi
echo
}
print_section "Expected for Developer ID (outside Mac App Store)" \
"Developer ID Application" \
"Developer ID Installer"
print_section "Expected for Mac App Store submissions" \
"Apple Distribution" \
"Mac App Distribution" \
"3rd Party Mac Developer Application" \
"3rd Party Mac Developer Installer" \
"Mac Installer Distribution"
echo "==> [$(ts)] Quick interpretation"
cat <<'EOF'
- If a certificate label appears above, but both:
- codesigning identity: NO
- installer identity: NO
then the certificate is present but NOT usable for signing on this Mac.
The most common cause is: the private key is missing.
Fix:
- Open Keychain Access → login → "My Certificates"
- Expand the certificate. You must see a private key underneath it.
- If there is no private key:
- Recreate the certificate on this Mac via Xcode (Accounts → Manage Certificates), OR
- Import a .p12 that includes the private key from the machine where it was created.
EOF
echo
echo "==> [$(ts)] Provisioning profiles (Mac App Store builds require one)"
prof_dirs=(
"${HOME}/Library/Developer/Xcode/UserData/Provisioning Profiles"
"${HOME}/Library/MobileDevice/Provisioning Profiles"
)
any_prof=0
for prof_dir in "${prof_dirs[@]}"; do
if [[ -d "${prof_dir}" ]]; then
any_prof=1
echo " ${prof_dir}"
ls -la "${prof_dir}" | head -n 20
echo
fi
done
if [[ "$any_prof" -eq 0 ]]; then
echo "(no provisioning profile directories found in common locations)"
fi
echo "Tip: to pick the right MAS profile for a bundle id, run:"
echo " ./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry"
\n\necho\n
echo "==> [$(ts)] Recommended SHA-1 values to use (avoids ambiguity when names are duplicated)"
cat <<'EOF'
When you have multiple identities with the same display name, prefer using the SHA-1 hash in scripts:
--codesign-identity "<SHA1>"
--installer-identity "<SHA1>"
This prevents codesign/productbuild from picking an unexpected identity.
EOF
echo
extract_identities() {
local policy="$1" # codesigning | basic
# Output: SHA1|LABEL
security find-identity -p "$policy" -v 2>/dev/null \
| sed -n 's/^[[:space:]]*[0-9][0-9]*[)] \([0-9A-F]\{40\}\) "\(.*\)"$/\1|\2/p'
}
print_sha_list() {
local title="$1"
local policy="$2"
local label_match="$3"
echo "$title"
local matches
matches="$(extract_identities "$policy" | grep -F "$label_match" || true)"
if [[ -z "$matches" ]]; then
echo " (none found)"
return 0
fi
local first=1
while IFS='|' read -r sha label; do
[[ -z "$sha" || -z "$label" ]] && continue
if [[ $first -eq 1 ]]; then
echo " recommended: $sha ($label)"
first=0
else
echo " alternative: $sha ($label)"
fi
done <<<"$matches"
}
print_sha_list "Mac App Store (app signing) [use with --codesign-identity]:" "codesigning" "Apple Distribution:"
print_sha_list "Mac App Store (pkg signing) [use with --installer-identity]:" "basic" "3rd Party Mac Developer Installer:"
print_sha_list "Developer ID (app signing) [outside App Store]:" "codesigning" "Developer ID Application:"
print_sha_list "Developer ID (pkg signing) [outside App Store]:" "basic" "Developer ID Installer:"