Enhance macOS build tools with keychain management and troubleshooting guidance

This commit updates the `README_MAS.md` to include important notes on keychain trust settings and the installation of Apple intermediate certificates, addressing common codesigning issues. Additionally, the `build_mas_pkg.sh` script is enhanced with functions to prepare the login keychain for signing, diagnose chain failures, and provide clear error messages for authorization issues during the build process. These improvements aim to streamline the macOS build experience and assist developers in resolving keychain-related errors effectively.
This commit is contained in:
2026-01-22 23:27:20 +09:00
parent 7a954b3f32
commit 8d49b87b7c
2 changed files with 168 additions and 4 deletions

View File

@@ -1,12 +1,46 @@
#!/usr/bin/env bash
set -euo pipefail
# Guard: this script must be executed with bash (not sourced into zsh, not run via sh).
if [[ -z "${BASH_VERSION:-}" ]]; then
echo "Error: this script must be run with bash (it uses bash arrays)." >&2
echo "Run:" >&2
echo " bash ./build_tools/macos/build_mas_pkg.sh --run ..." >&2
exit 2
fi
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)"
prepare_login_keychain_for_signing() {
# Some setups require explicitly granting Apple tooling access to the private key(s)
# (otherwise productbuild/codesign can fail with authorization errors like:
# CSSM Exception: -60008 Unable to obtain authorization for this operation
# or "User interaction is not allowed").
#
# This function is optional and only runs if a keychain password is provided.
local keychain_path="$HOME/Library/Keychains/login.keychain-db"
local pw="${1:-}"
if [[ -z "$pw" ]]; then
echo "==> [$(ts)] Note: no keychain password provided; skipping keychain access-control preparation."
echo " If productbuild later fails with -60008 authorization errors, fix it with either:"
echo " - Keychain Access → login → My Certificates → select the *private key* under the Installer cert → Get Info → Access Control → allow productbuild"
echo " - OR (CLI): security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k <password> \"$keychain_path\""
return 0
fi
echo "==> [$(ts)] Preparing login keychain for signing (unlock + key partition list)"
# Unlock so Security/Authorization can use keys without prompting.
security unlock-keychain -p "$pw" "$keychain_path" >/dev/null 2>&1 || true
# Allow Apple tools (codesign/productbuild) to access the private key without GUI prompts.
# This is the standard fix used for non-interactive signing.
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$pw" "$keychain_path" >/dev/null 2>&1 || true
}
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:
@@ -27,6 +61,22 @@ ensure_keychain_search_list() {
security list-keychains -d user -s "$login_kc" "$system_kc" "$roots_kc" >/dev/null 2>&1 || true
}
diagnose_chain_failure() {
echo "==> [$(ts)] Codesign failed. Common causes on macOS:"
echo " - System keychains not in the user keychain search list"
echo " - Missing/invalid WWDR intermediate certificate"
echo " - Keychain/key access issues"
echo
echo "==> [$(ts)] Keychain search list:"
security list-keychains -d user || true
echo
echo "==> [$(ts)] Checking for Apple WWDR intermediate in System keychain:"
security find-certificate -a -c "Apple Worldwide Developer Relations" /Library/Keychains/System.keychain 2>/dev/null | head -n 5 || true
echo
echo "==> [$(ts)] If WWDR is missing, install the current Apple WWDR intermediate certificate (via Xcode or Apple Developer portal)."
echo "==> [$(ts)] Then re-run this script."
}
preflight_identity() {
local what="$1"
@@ -67,8 +117,17 @@ Optional:
--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)
--keychain-password <pw> OPTIONAL: unlock/login keychain + set key partition list for Apple tools
(alternative: set env var STRAWBERRY_KEYCHAIN_PASSWORD)
Examples:
# Tip: if your keychain password contains characters like ! or $, prefer the env var or single quotes.
STRAWBERRY_KEYCHAIN_PASSWORD='your-login-keychain-password' \
./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"
./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)" \
@@ -95,6 +154,7 @@ provisionprofile=""
entitlements=""
bundle_id="com.dryark.strawberry"
pkg_out=""
keychain_password="${STRAWBERRY_KEYCHAIN_PASSWORD:-}"
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -109,6 +169,7 @@ while [[ $# -gt 0 ]]; do
--entitlements) entitlements="${2:-}"; shift 2 ;;
--bundle-id) bundle_id="${2:-}"; shift 2 ;;
--pkg-out) pkg_out="${2:-}"; shift 2 ;;
--keychain-password) keychain_password="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown arg: $1" >&2; usage; exit 2 ;;
esac
@@ -182,6 +243,7 @@ echo "==> [$(ts)] Embedding provisioning profile"
cp -f "$provisionprofile" "${app_path}/Contents/embedded.provisionprofile"
ensure_keychain_search_list
prepare_login_keychain_for_signing "$keychain_password"
preflight_identity "codesign" "codesigning" "$codesign_identity"
preflight_identity "installer" "basic" "$installer_identity"
@@ -231,10 +293,26 @@ 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"
if ! productbuild \
--component "$app_path" /Applications \
--sign "$installer_identity" \
"$pkg_out"; then
echo "Error: productbuild failed while signing the .pkg." >&2
echo "Common cause: keychain/private-key authorization (e.g. CSSM -60008)." >&2
echo >&2
echo "Fix options:" >&2
echo "1) Keychain Access UI:" >&2
echo " - Keychain Access → login → My Certificates" >&2
echo " - Find: $installer_identity" >&2
echo " - Expand it and select the *private key* under it" >&2
echo " - Get Info → Access Control → allow /usr/bin/productbuild (optionally also allow /usr/bin/pkgbuild)" >&2
echo "2) CLI (recommended for repeatable builds):" >&2
echo " security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k <password> \"$HOME/Library/Keychains/login.keychain-db\"" >&2
echo >&2
echo "Tip: you can also rerun this script with:" >&2
echo " --keychain-password <login-keychain-password>" >&2
exit 1
fi
echo "==> [$(ts)] Verifying pkg signature"
pkgutil --check-signature "$pkg_out" || true