251 lines
4.9 KiB
Bash
Executable File
251 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
APP_NAME="SonarDesk"
|
|
PROJECT="SonarDesk.xcodeproj"
|
|
SCHEME="SonarDesk"
|
|
CONFIGURATION="Release"
|
|
|
|
TEAM_ID="39R6U3437D"
|
|
SIGN_IDENTITY="B99D353C88996866C49E4389B375645F76870A3F"
|
|
PROFILE_NAME="SonarDesk"
|
|
NOTARY_PROFILE="sonardesk-notary"
|
|
|
|
BUILD_DIR="$PROJECT_ROOT/build"
|
|
ARCHIVE="$BUILD_DIR/SonarDesk.xcarchive"
|
|
APP="$ARCHIVE/Products/Applications/SonarDesk.app"
|
|
STAGE="$BUILD_DIR/dmg-stage"
|
|
RELEASE_DIR="$PROJECT_ROOT/release"
|
|
|
|
echo
|
|
echo "========================================"
|
|
echo " SonarDesk Release Build"
|
|
echo "========================================"
|
|
|
|
echo
|
|
echo "===== CLEAN ====="
|
|
rm -rf "$ARCHIVE" "$STAGE"
|
|
mkdir -p "$BUILD_DIR" "$RELEASE_DIR"
|
|
|
|
echo
|
|
echo "===== ARCHIVE ====="
|
|
xcodebuild \
|
|
-project "$PROJECT" \
|
|
-scheme "$SCHEME" \
|
|
-configuration "$CONFIGURATION" \
|
|
-archivePath "$ARCHIVE" \
|
|
-destination 'generic/platform=macOS' \
|
|
CODE_SIGN_STYLE=Manual \
|
|
CODE_SIGN_IDENTITY="$SIGN_IDENTITY" \
|
|
DEVELOPMENT_TEAM="$TEAM_ID" \
|
|
PROVISIONING_PROFILE_SPECIFIER="$PROFILE_NAME" \
|
|
ENABLE_HARDENED_RUNTIME=YES \
|
|
clean archive
|
|
|
|
echo
|
|
echo "===== VERIFY APP SIGNATURE ====="
|
|
codesign --verify --deep --strict --verbose=2 "$APP"
|
|
|
|
SIGN_INFO="$(codesign -dv --verbose=4 "$APP" 2>&1)"
|
|
|
|
echo "$SIGN_INFO" | grep \
|
|
"Authority=Developer ID Application: Mark Gregory (39R6U3437D)"
|
|
|
|
echo "$SIGN_INFO" | grep \
|
|
"TeamIdentifier=$TEAM_ID"
|
|
|
|
echo "$SIGN_INFO" | grep \
|
|
"Runtime Version="
|
|
|
|
echo
|
|
echo "===== VERIFY EMBEDDED PROFILE ====="
|
|
|
|
PROFILE_PLIST="$(mktemp)"
|
|
trap 'rm -f "$PROFILE_PLIST"' EXIT
|
|
|
|
security cms -D \
|
|
-i "$APP/Contents/embedded.provisionprofile" \
|
|
> "$PROFILE_PLIST"
|
|
|
|
PROFILE_NAME_ACTUAL=$(
|
|
/usr/libexec/PlistBuddy \
|
|
-c 'Print :Name' \
|
|
"$PROFILE_PLIST"
|
|
)
|
|
|
|
PROFILE_UUID=$(
|
|
/usr/libexec/PlistBuddy \
|
|
-c 'Print :UUID' \
|
|
"$PROFILE_PLIST"
|
|
)
|
|
|
|
ICLOUD_ENV=$(
|
|
/usr/libexec/PlistBuddy \
|
|
-c 'Print :Entitlements:com.apple.developer.icloud-container-environment' \
|
|
"$PROFILE_PLIST"
|
|
)
|
|
|
|
echo "Profile: $PROFILE_NAME_ACTUAL"
|
|
echo "UUID: $PROFILE_UUID"
|
|
echo "iCloud Environment: $ICLOUD_ENV"
|
|
|
|
if [[ "$ICLOUD_ENV" != "Production" ]]; then
|
|
echo "ERROR: iCloud environment is not Production."
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "===== VERIFY SIGNED ENTITLEMENTS ====="
|
|
|
|
ENTITLEMENTS="$(codesign -d --entitlements :- "$APP" 2>/dev/null)"
|
|
|
|
echo "$ENTITLEMENTS" | grep -q \
|
|
'iCloud.net.absdev.SonarDesk'
|
|
|
|
echo "$ENTITLEMENTS" | grep -q \
|
|
'CloudDocuments'
|
|
|
|
echo "$ENTITLEMENTS" | grep -q \
|
|
'39R6U3437D.net.absdev.SonarDesk'
|
|
|
|
echo "iCloud entitlements verified."
|
|
|
|
echo
|
|
echo "===== DETERMINE VERSION ====="
|
|
|
|
VERSION=$(
|
|
/usr/libexec/PlistBuddy \
|
|
-c 'Print :CFBundleShortVersionString' \
|
|
"$APP/Contents/Info.plist"
|
|
)
|
|
|
|
BUILD=$(
|
|
/usr/libexec/PlistBuddy \
|
|
-c 'Print :CFBundleVersion' \
|
|
"$APP/Contents/Info.plist"
|
|
)
|
|
|
|
DMG="$RELEASE_DIR/SonarDesk-${VERSION}.dmg"
|
|
|
|
echo "Version: $VERSION"
|
|
echo "Build: $BUILD"
|
|
echo "DMG: $DMG"
|
|
|
|
echo
|
|
echo "===== PREPARE DMG ====="
|
|
|
|
rm -rf "$STAGE"
|
|
rm -f "$DMG"
|
|
|
|
mkdir -p "$STAGE"
|
|
|
|
ditto "$APP" "$STAGE/SonarDesk.app"
|
|
ln -s /Applications "$STAGE/Applications"
|
|
|
|
echo
|
|
echo "===== CREATE DMG ====="
|
|
|
|
hdiutil create \
|
|
-volname "SonarDesk" \
|
|
-srcfolder "$STAGE" \
|
|
-ov \
|
|
-format UDZO \
|
|
"$DMG"
|
|
|
|
echo
|
|
echo "===== SIGN DMG ====="
|
|
|
|
codesign \
|
|
--force \
|
|
--timestamp \
|
|
--sign "$SIGN_IDENTITY" \
|
|
"$DMG"
|
|
|
|
echo
|
|
echo "===== VERIFY DMG SIGNATURE ====="
|
|
|
|
codesign --verify --verbose=2 "$DMG"
|
|
|
|
echo
|
|
echo "===== NOTARIZE ====="
|
|
|
|
xcrun notarytool submit "$DMG" \
|
|
--keychain-profile "$NOTARY_PROFILE" \
|
|
--wait
|
|
|
|
echo
|
|
echo "===== STAPLE ====="
|
|
|
|
xcrun stapler staple "$DMG"
|
|
|
|
echo
|
|
echo "===== VALIDATE STAPLE ====="
|
|
|
|
xcrun stapler validate "$DMG"
|
|
|
|
echo
|
|
echo "===== GATEKEEPER CHECK ====="
|
|
|
|
spctl \
|
|
--assess \
|
|
--type open \
|
|
--context context:primary-signature \
|
|
--verbose=4 \
|
|
"$DMG"
|
|
|
|
echo
|
|
echo "===== VERIFY APP INSIDE DMG ====="
|
|
|
|
MOUNT_DIR="$(mktemp -d)"
|
|
|
|
cleanup_mount() {
|
|
hdiutil detach "$MOUNT_DIR" >/dev/null 2>&1 || true
|
|
rmdir "$MOUNT_DIR" >/dev/null 2>&1 || true
|
|
}
|
|
|
|
trap 'cleanup_mount; rm -f "$PROFILE_PLIST"' EXIT
|
|
|
|
hdiutil attach "$DMG" \
|
|
-nobrowse \
|
|
-readonly \
|
|
-mountpoint "$MOUNT_DIR" \
|
|
>/dev/null
|
|
|
|
codesign \
|
|
--verify \
|
|
--deep \
|
|
--strict \
|
|
--verbose=2 \
|
|
"$MOUNT_DIR/SonarDesk.app"
|
|
|
|
spctl \
|
|
--assess \
|
|
--type execute \
|
|
--verbose=4 \
|
|
"$MOUNT_DIR/SonarDesk.app"
|
|
|
|
cleanup_mount
|
|
|
|
rm -rf "$STAGE"
|
|
|
|
echo
|
|
echo "========================================"
|
|
echo " RELEASE COMPLETE"
|
|
echo "========================================"
|
|
echo
|
|
echo "Application: SonarDesk"
|
|
echo "Version: $VERSION"
|
|
echo "Build: $BUILD"
|
|
echo "DMG: $DMG"
|
|
echo
|
|
echo "Signed: YES"
|
|
echo "Notarized: YES"
|
|
echo "Stapled: YES"
|
|
echo "Gatekeeper: PASSED"
|
|
echo
|
|
echo "========================================"
|