Wire Apple KMS release signing
This commit is contained in:
parent
ed73d7d16a
commit
126af6b5cf
17 changed files with 1913 additions and 16 deletions
|
|
@ -13,13 +13,15 @@ derived_data="${BURROW_DERIVED_DATA_PATH:-${repo_root}/.derived-data/apple}"
|
|||
source_packages="${BURROW_SWIFTPM_CACHE_PATH:-${XDG_CACHE_HOME:-${HOME}/.cache}/burrow/swiftpm}"
|
||||
project="Apple/Burrow.xcodeproj"
|
||||
scheme="${BURROW_APPLE_SCHEME:-App}"
|
||||
bundle_id="${BURROW_APPLE_BUNDLE_ID:-com.hackclub.burrow}"
|
||||
bundle_id="${BURROW_APPLE_BUNDLE_ID:-net.burrow.app}"
|
||||
network_extension_bundle_id="${BURROW_APPLE_NETWORK_EXTENSION_BUNDLE_ID:-${bundle_id}.network}"
|
||||
signing_ready="${BURROW_APPLE_SIGNING_READY:-0}"
|
||||
signing_mode="${BURROW_APPLE_SIGNING_MODE:-keychain}"
|
||||
require_signing="${BURROW_APPLE_REQUIRE_SIGNING:-false}"
|
||||
sparkle_feed_url="${BURROW_SPARKLE_FEED_URL:-https://releases.burrow.net/sparkle/appcast.xml}"
|
||||
sparkle_public_ed_key="${BURROW_SPARKLE_PUBLIC_ED_KEY:-Myv9ZNZT6YGKMtMezh52ra4WqaeEKc4VlvVU0evhJeI=}"
|
||||
sparkle_sign_with_kms="${BURROW_SPARKLE_SIGN_WITH_KMS:-false}"
|
||||
notarize_macos="${BURROW_NOTARIZE_MACOS:-false}"
|
||||
|
||||
mkdir -p "$apple_root" "$archives_root" "$derived_data" "$source_packages"
|
||||
|
||||
|
|
@ -39,6 +41,74 @@ sha256_file() {
|
|||
fi
|
||||
}
|
||||
|
||||
safe_profile_slug() {
|
||||
python3 - "$1" <<'PY'
|
||||
import re
|
||||
import sys
|
||||
|
||||
print(re.sub(r"[^A-Za-z0-9]", "", sys.argv[1]).lower())
|
||||
PY
|
||||
}
|
||||
|
||||
profile_for() {
|
||||
local identifier="$1"
|
||||
local suffix="$2"
|
||||
local slug path
|
||||
slug="$(safe_profile_slug "$identifier")"
|
||||
for path in \
|
||||
".forgejo/actions/export/${slug}${suffix}.provisionprofile" \
|
||||
".forgejo/actions/export/${slug}${suffix}.mobileprovision" \
|
||||
"Apple/Profiles/${slug}${suffix}.provisionprofile" \
|
||||
"Apple/Profiles/${slug}${suffix}.mobileprovision"; do
|
||||
if [[ -s "$path" ]]; then
|
||||
printf '%s\n' "$path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
generate_entitlements_from_profile() {
|
||||
local profile="$1"
|
||||
local output="$2"
|
||||
Scripts/apple/profile-entitlements.py "$profile" --output "$output"
|
||||
}
|
||||
|
||||
apple_signing_available() {
|
||||
if [[ "$signing_mode" == "google-kms" || "$signing_mode" == "google-kms-staged" || "$signing_mode" == "kms" ]]; then
|
||||
return 0
|
||||
fi
|
||||
[[ "$signing_ready" == "1" ]]
|
||||
}
|
||||
|
||||
kms_sign_bundle() {
|
||||
local family="$1"
|
||||
local bundle_path="$2"
|
||||
local entitlements="$3"
|
||||
local runtime_flag=()
|
||||
if [[ "$family" == "developer-id" ]]; then
|
||||
runtime_flag=(--runtime)
|
||||
fi
|
||||
Scripts/apple/sign-with-google-kms.sh \
|
||||
--family "$family" \
|
||||
--path "$bundle_path" \
|
||||
--entitlements "$entitlements" \
|
||||
"${runtime_flag[@]}"
|
||||
}
|
||||
|
||||
kms_sign_file() {
|
||||
local family="$1"
|
||||
local file_path="$2"
|
||||
local runtime_flag=()
|
||||
if [[ "$family" == "developer-id" ]]; then
|
||||
runtime_flag=(--runtime)
|
||||
fi
|
||||
Scripts/apple/sign-with-google-kms.sh \
|
||||
--family "$family" \
|
||||
--path "$file_path" \
|
||||
"${runtime_flag[@]}"
|
||||
}
|
||||
|
||||
write_version() {
|
||||
mkdir -p Apple/Configuration
|
||||
printf 'CURRENT_PROJECT_VERSION = %s\n' "$build_number" > Apple/Configuration/Version.xcconfig
|
||||
|
|
@ -93,7 +163,7 @@ unsigned_note() {
|
|||
ensure_signing_or_note() {
|
||||
local platform_name="$1"
|
||||
local artifact_name="$2"
|
||||
if [[ "$signing_ready" == "1" ]]; then
|
||||
if apple_signing_available; then
|
||||
return 0
|
||||
fi
|
||||
if truthy "$require_signing"; then
|
||||
|
|
@ -151,6 +221,14 @@ build_ios_release() {
|
|||
build_ios_unsigned
|
||||
return 0
|
||||
fi
|
||||
if [[ "$signing_mode" == "google-kms-staged" ]]; then
|
||||
build_ios_kms_staged
|
||||
return 0
|
||||
fi
|
||||
if [[ "$signing_mode" == "google-kms" || "$signing_mode" == "kms" ]]; then
|
||||
build_ios_kms_release
|
||||
return 0
|
||||
fi
|
||||
|
||||
archive_path="${archives_root}/Burrow-iOS-${build_number}.xcarchive"
|
||||
export_dir="${apple_root}/ios-export"
|
||||
|
|
@ -181,6 +259,91 @@ build_ios_release() {
|
|||
sha256_file "${apple_root}/Burrow-iOS-${build_number}.ipa"
|
||||
}
|
||||
|
||||
build_ios_kms_staged() {
|
||||
local product_dir source_app stage_dir ipa
|
||||
xcodebuild build \
|
||||
"${xcode_common_args[@]}" \
|
||||
-destination "generic/platform=iOS" \
|
||||
ARCHS=arm64 \
|
||||
ONLY_ACTIVE_ARCH=YES \
|
||||
SKIP_INSTALL=NO \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGN_IDENTITY=
|
||||
|
||||
product_dir="${derived_data}/Build/Products/Release-iphoneos"
|
||||
source_app="${product_dir}/Burrow.app"
|
||||
if [[ ! -d "$source_app" ]]; then
|
||||
echo "iOS build completed but did not produce Burrow.app" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
stage_dir="${apple_root}/ios-unsigned/Payload"
|
||||
rm -rf "$stage_dir"
|
||||
mkdir -p "$stage_dir"
|
||||
ditto "$source_app" "${stage_dir}/Burrow.app"
|
||||
ipa="${apple_root}/Burrow-iOS-${build_number}.unsigned.ipa"
|
||||
rm -f "$ipa"
|
||||
(cd "${apple_root}/ios-unsigned" && zip -qry "$ipa" Payload)
|
||||
sha256_file "$ipa"
|
||||
}
|
||||
|
||||
build_ios_kms_release() {
|
||||
local product_dir source_app stage_dir app ext app_profile ext_profile app_entitlements ext_entitlements ipa
|
||||
xcodebuild build \
|
||||
"${xcode_common_args[@]}" \
|
||||
-destination "generic/platform=iOS" \
|
||||
ARCHS=arm64 \
|
||||
ONLY_ACTIVE_ARCH=YES \
|
||||
SKIP_INSTALL=NO \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGN_IDENTITY=
|
||||
|
||||
product_dir="${derived_data}/Build/Products/Release-iphoneos"
|
||||
source_app="${product_dir}/Burrow.app"
|
||||
if [[ ! -d "$source_app" ]]; then
|
||||
echo "iOS build completed but did not produce Burrow.app" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
stage_dir="${apple_root}/ios-kms/Payload"
|
||||
rm -rf "$stage_dir"
|
||||
mkdir -p "$stage_dir"
|
||||
ditto "$source_app" "${stage_dir}/Burrow.app"
|
||||
app="${stage_dir}/Burrow.app"
|
||||
ext="${app}/PlugIns/BurrowNetworkExtension.appex"
|
||||
if [[ ! -d "$ext" ]]; then
|
||||
echo "iOS app is missing BurrowNetworkExtension.appex" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
app_profile="$(profile_for "$bundle_id" "appstore")" || {
|
||||
echo "missing iOS App Store provisioning profile for ${bundle_id}" >&2
|
||||
exit 1
|
||||
}
|
||||
ext_profile="$(profile_for "$network_extension_bundle_id" "appstore")" || {
|
||||
echo "missing iOS App Store provisioning profile for ${network_extension_bundle_id}" >&2
|
||||
exit 1
|
||||
}
|
||||
cp "$app_profile" "${app}/embedded.mobileprovision"
|
||||
cp "$ext_profile" "${ext}/embedded.mobileprovision"
|
||||
|
||||
app_entitlements="${apple_root}/ios-kms/app-entitlements.plist"
|
||||
ext_entitlements="${apple_root}/ios-kms/extension-entitlements.plist"
|
||||
generate_entitlements_from_profile "$app_profile" "$app_entitlements"
|
||||
generate_entitlements_from_profile "$ext_profile" "$ext_entitlements"
|
||||
|
||||
rm -rf "${app}/_CodeSignature" "${ext}/_CodeSignature"
|
||||
kms_sign_bundle ios "$ext" "$ext_entitlements"
|
||||
kms_sign_bundle ios "$app" "$app_entitlements"
|
||||
|
||||
ipa="${apple_root}/Burrow-iOS-${build_number}.ipa"
|
||||
rm -f "$ipa"
|
||||
(cd "${apple_root}/ios-kms" && zip -qry "$ipa" Payload)
|
||||
sha256_file "$ipa"
|
||||
}
|
||||
|
||||
build_macos_unsigned() {
|
||||
local product_dir zip_path
|
||||
xcodebuild build \
|
||||
|
|
@ -203,6 +366,14 @@ build_macos_release() {
|
|||
build_macos_unsigned
|
||||
return 0
|
||||
fi
|
||||
if [[ "$signing_mode" == "google-kms-staged" ]]; then
|
||||
build_macos_kms_staged
|
||||
return 0
|
||||
fi
|
||||
if [[ "$signing_mode" == "google-kms" || "$signing_mode" == "kms" ]]; then
|
||||
build_macos_kms_release
|
||||
return 0
|
||||
fi
|
||||
|
||||
archive_path="${archives_root}/Burrow-macOS-${build_number}.xcarchive"
|
||||
export_dir="${apple_root}/macos-export"
|
||||
|
|
@ -264,6 +435,135 @@ EOF
|
|||
fi
|
||||
}
|
||||
|
||||
build_macos_kms_staged() {
|
||||
local product_dir source_app zip_path
|
||||
xcodebuild build \
|
||||
"${xcode_common_args[@]}" \
|
||||
-destination "platform=macOS" \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGN_IDENTITY=
|
||||
|
||||
product_dir="${derived_data}/Build/Products/Release"
|
||||
source_app="${product_dir}/Burrow.app"
|
||||
if [[ ! -d "$source_app" ]]; then
|
||||
echo "macOS build completed but did not produce Burrow.app" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
zip_path="${apple_root}/Burrow-macOS-${build_number}.unsigned.zip"
|
||||
rm -f "$zip_path"
|
||||
ditto -c -k --keepParent "$source_app" "$zip_path"
|
||||
sha256_file "$zip_path"
|
||||
}
|
||||
|
||||
write_sparkle_appcast() {
|
||||
local dmg="$1"
|
||||
local channel sparkle_dir length pubdate url
|
||||
channel="${SPARKLE_CHANNEL:-build-${build_number}}"
|
||||
sparkle_dir="${out_root}/sparkle/${channel}"
|
||||
mkdir -p "$sparkle_dir"
|
||||
cp "$dmg" "$sparkle_dir/"
|
||||
length="$(wc -c < "$dmg" | tr -d ' ')"
|
||||
pubdate="$(LC_ALL=C date -u '+%a, %d %b %Y %H:%M:%S +0000')"
|
||||
url="${SPARKLE_DOWNLOAD_PREFIX:-https://releases.burrow.net/sparkle}/${channel}/$(basename "$dmg")"
|
||||
cat > "${sparkle_dir}/appcast.xml" <<EOF
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||
<channel>
|
||||
<title>Burrow ${channel}</title>
|
||||
<item>
|
||||
<title>Burrow ${build_number}</title>
|
||||
<pubDate>${pubdate}</pubDate>
|
||||
<sparkle:version>${build_number}</sparkle:version>
|
||||
<sparkle:shortVersionString>0.1</sparkle:shortVersionString>
|
||||
<enclosure url="${url}" sparkle:version="${build_number}" length="${length}" type="application/octet-stream" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
EOF
|
||||
|
||||
if truthy "$sparkle_sign_with_kms"; then
|
||||
Scripts/sparkle/sign-appcast-kms.py \
|
||||
--appcast "${sparkle_dir}/appcast.xml" \
|
||||
--artifact-dir "$sparkle_dir"
|
||||
fi
|
||||
}
|
||||
|
||||
notarize_dmg_if_requested() {
|
||||
local dmg="$1"
|
||||
local key_json
|
||||
if ! truthy "$notarize_macos"; then
|
||||
return 0
|
||||
fi
|
||||
if [[ -z "${ASC_API_KEY_ID:-}" || -z "${ASC_API_ISSUER_ID:-}" || -z "${ASC_API_KEY_PATH:-}" ]]; then
|
||||
echo "macOS notarization requires ASC_API_KEY_ID, ASC_API_ISSUER_ID, and ASC_API_KEY_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
key_json="${apple_root}/notary-api-key.json"
|
||||
rcodesign encode-app-store-connect-api-key \
|
||||
"$ASC_API_ISSUER_ID" \
|
||||
"$ASC_API_KEY_ID" \
|
||||
"$ASC_API_KEY_PATH" \
|
||||
"$key_json"
|
||||
rcodesign notary-submit --api-key-file "$key_json" --wait --staple "$dmg"
|
||||
rm -f "$key_json"
|
||||
}
|
||||
|
||||
build_macos_kms_release() {
|
||||
local product_dir source_app app ext app_profile ext_profile app_entitlements ext_entitlements dmg
|
||||
xcodebuild build \
|
||||
"${xcode_common_args[@]}" \
|
||||
-destination "platform=macOS" \
|
||||
CODE_SIGNING_ALLOWED=NO \
|
||||
CODE_SIGNING_REQUIRED=NO \
|
||||
CODE_SIGN_IDENTITY=
|
||||
|
||||
product_dir="${derived_data}/Build/Products/Release"
|
||||
source_app="${product_dir}/Burrow.app"
|
||||
if [[ ! -d "$source_app" ]]; then
|
||||
echo "macOS build completed but did not produce Burrow.app" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
app="${apple_root}/macos-kms/Burrow.app"
|
||||
rm -rf "$app"
|
||||
mkdir -p "$(dirname "$app")"
|
||||
ditto "$source_app" "$app"
|
||||
ext="${app}/Contents/PlugIns/BurrowNetworkExtension.appex"
|
||||
|
||||
app_profile="$(profile_for "$bundle_id" "developerid")" || {
|
||||
echo "missing macOS Developer ID provisioning profile for ${bundle_id}" >&2
|
||||
exit 1
|
||||
}
|
||||
cp "$app_profile" "${app}/Contents/embedded.provisionprofile"
|
||||
app_entitlements="${apple_root}/macos-kms/app-entitlements.plist"
|
||||
generate_entitlements_from_profile "$app_profile" "$app_entitlements"
|
||||
|
||||
if [[ -d "$ext" ]]; then
|
||||
ext_profile="$(profile_for "$network_extension_bundle_id" "developerid")" || {
|
||||
echo "missing macOS Developer ID provisioning profile for ${network_extension_bundle_id}" >&2
|
||||
exit 1
|
||||
}
|
||||
cp "$ext_profile" "${ext}/Contents/embedded.provisionprofile"
|
||||
ext_entitlements="${apple_root}/macos-kms/extension-entitlements.plist"
|
||||
generate_entitlements_from_profile "$ext_profile" "$ext_entitlements"
|
||||
rm -rf "${ext}/Contents/_CodeSignature"
|
||||
kms_sign_bundle developer-id "$ext" "$ext_entitlements"
|
||||
fi
|
||||
|
||||
rm -rf "${app}/Contents/_CodeSignature"
|
||||
kms_sign_bundle developer-id "$app" "$app_entitlements"
|
||||
|
||||
dmg="${apple_root}/Burrow-macOS-${build_number}.dmg"
|
||||
rm -f "$dmg"
|
||||
hdiutil create -volname "Burrow ${build_number}" -srcfolder "$app" -ov -format UDZO "$dmg"
|
||||
kms_sign_file developer-id "$dmg"
|
||||
notarize_dmg_if_requested "$dmg"
|
||||
sha256_file "$dmg"
|
||||
write_sparkle_appcast "$dmg"
|
||||
}
|
||||
|
||||
require_xcodebuild
|
||||
write_version
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue