diff --git a/.github/workflows/create-release-prs.yml b/.github/workflows/create-release-prs.yml index 1e740dcd8..be72e6b50 100644 --- a/.github/workflows/create-release-prs.yml +++ b/.github/workflows/create-release-prs.yml @@ -44,6 +44,20 @@ jobs: BASE_BRANCH: ${{ github.event.inputs.base_branch }} RELEASE_BRANCH: ${{ needs.prep.outputs.release_branch }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Single source of truth for the XCFrameworks the Code Sign and Verify steps + # operate on (paths relative to iOS_SDK/OneSignalSDK). Keep in sync with the + # frameworks built by build_all_frameworks.sh. + XCFRAMEWORKS: >- + OneSignal_Core/OneSignalCore.xcframework + OneSignal_OSCore/OneSignalOSCore.xcframework + OneSignal_Outcomes/OneSignalOutcomes.xcframework + OneSignal_Extension/OneSignalExtension.xcframework + OneSignal_Notifications/OneSignalNotifications.xcframework + OneSignal_User/OneSignalUser.xcframework + OneSignal_LiveActivities/OneSignalLiveActivities.xcframework + OneSignal_Location/OneSignalLocation.xcframework + OneSignal_InAppMessages/OneSignalInAppMessages.xcframework + OneSignal_XCFramework/OneSignalFramework.xcframework steps: - name: 📋 Display Configuration @@ -75,21 +89,13 @@ jobs: with: xcode-version: "15.2" - - name: Install the Apple distribution certificate and provisioning profile (OneSignal) + - name: Install the Apple distribution certificate (OneSignal) uses: apple-actions/import-codesign-certs@v2 with: keychain-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }} p12-file-base64: ${{ secrets.CERTIFICATES_P12 }} p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }} - - name: Install the Apple distribution certificate and provisioning profile (Lilomi) - uses: apple-actions/import-codesign-certs@v2 - with: - create-keychain: false # do not create a new keychain for this value - keychain-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }} - p12-file-base64: ${{ secrets.DEV_CERTIFICATES_P12 }} - p12-password: ${{ secrets.DEV_CERTIFICATES_P12_PASSWORD }} - - name: Update Version in SDK and Podspec Files run: | cd iOS_SDK/OneSignalSDK @@ -112,16 +118,41 @@ jobs: - name: Code Sign run: | cd iOS_SDK/OneSignalSDK - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Core/OneSignalCore.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Extension/OneSignalExtension.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_InAppMessages/OneSignalInAppMessages.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Location/OneSignalLocation.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Notifications/OneSignalNotifications.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_OSCore/OneSignalOSCore.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_Outcomes/OneSignalOutcomes.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_User/OneSignalUser.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_XCFramework/OneSignalFramework.xcframework - codesign --timestamp -v --sign "Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" OneSignal_LiveActivities/OneSignalLiveActivities.xcframework + set -e + IDENTITY="Apple Distribution: OneSignal, Inc. (J3J28YJX9L)" + for XCF in $XCFRAMEWORKS; do + # Sign inside-out: each slice's .framework binary first, then the + # .xcframework wrapper. -f replaces the linker's ad-hoc signature left + # by the unsigned archive build, so both inner and outer end up signed + # with the official OneSignal Apple Distribution identity. + while IFS= read -r FW; do + echo "Signing inner framework: $FW" + codesign --timestamp -f -v --sign "$IDENTITY" "$FW" + done < <(find "$XCF" -type d -name "*.framework") + echo "Signing wrapper: $XCF" + codesign --timestamp -f -v --sign "$IDENTITY" "$XCF" + done + shell: bash + + - name: Verify Code Signing + run: | + cd iOS_SDK/OneSignalSDK + set -e + # Fail the release if any slice or wrapper is tampered/unsigned or not + # signed by the OneSignal team. --deep is unreliable across xcframework + # slices, so each inner .framework is verified explicitly. + REQUIREMENT="anchor apple generic and certificate leaf[subject.OU] = J3J28YJX9L" + for XCF in $XCFRAMEWORKS; do + while IFS= read -r FW; do + echo "Verifying inner framework: $FW" + codesign --verify --strict --verbose=2 "$FW" + codesign --verify -R="$REQUIREMENT" "$FW" + done < <(find "$XCF" -type d -name "*.framework") + echo "Verifying wrapper: $XCF" + codesign --verify --strict --verbose=2 "$XCF" + codesign --verify -R="$REQUIREMENT" "$XCF" + done + echo "All XCFrameworks verified: intact and signed by OneSignal (J3J28YJX9L)." shell: bash - name: Commit Build and Push Changes diff --git a/iOS_SDK/OneSignalSDK/build_all_frameworks.sh b/iOS_SDK/OneSignalSDK/build_all_frameworks.sh index c9b7804ed..936c78d1c 100755 --- a/iOS_SDK/OneSignalSDK/build_all_frameworks.sh +++ b/iOS_SDK/OneSignalSDK/build_all_frameworks.sh @@ -26,11 +26,17 @@ create_xcframework() { xcodebuild -list - xcodebuild archive ONLY_ACTIVE_ARCH=NO -scheme ${BUILD_SCHEME} -destination="generic/platform=iOS Simulator" -archivePath "${SIMULATOR_ARCHIVE_PATH}" -sdk iphonesimulator SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES + # Note: code signing is disabled here. These are distribution XCFrameworks + # that are signed afterward with the Apple Distribution cert in the workflow's + # "Code Sign" step, so the archive itself does not need to be signed. This also + # avoids depending on the project's baked-in DEVELOPMENT_TEAM / dev certificate. + CODE_SIGN_FLAGS="CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO" - xcodebuild archive -scheme ${BUILD_SCHEME} -destination="generic/platform=iOS" -archivePath "${IOS_DEVICE_ARCHIVE_PATH}" -sdk iphoneos SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES + xcodebuild archive ONLY_ACTIVE_ARCH=NO -scheme ${BUILD_SCHEME} -destination="generic/platform=iOS Simulator" -archivePath "${SIMULATOR_ARCHIVE_PATH}" -sdk iphonesimulator SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES ${CODE_SIGN_FLAGS} - xcodebuild archive -scheme ${BUILD_SCHEME} -destination='generic/platform=macOS,variant=Mac Catalyst' -archivePath "${CATALYST_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES + xcodebuild archive -scheme ${BUILD_SCHEME} -destination="generic/platform=iOS" -archivePath "${IOS_DEVICE_ARCHIVE_PATH}" -sdk iphoneos SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES ${CODE_SIGN_FLAGS} + + xcodebuild archive -scheme ${BUILD_SCHEME} -destination='generic/platform=macOS,variant=Mac Catalyst' -archivePath "${CATALYST_ARCHIVE_PATH}" SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES ${CODE_SIGN_FLAGS} xcodebuild -create-xcframework -framework ${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework -debug-symbols ${SIMULATOR_ARCHIVE_PATH}/dSYMs/${FRAMEWORK_NAME}.framework.dSYM -framework ${IOS_DEVICE_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework -debug-symbols ${IOS_DEVICE_ARCHIVE_PATH}/dSYMs/${FRAMEWORK_NAME}.framework.dSYM -framework ${CATALYST_ARCHIVE_PATH}/Products/Library/Frameworks/${FRAMEWORK_NAME}.framework -debug-symbols ${CATALYST_ARCHIVE_PATH}/dSYMs/${FRAMEWORK_NAME}.framework.dSYM -output "${FRAMEWORK_PATH}" rm -rf "${SIMULATOR_ARCHIVE_PATH}" diff --git a/iOS_SDK/OneSignalSDK/update_swift_package.sh b/iOS_SDK/OneSignalSDK/update_swift_package.sh index b62ca7913..cc135a3d5 100755 --- a/iOS_SDK/OneSignalSDK/update_swift_package.sh +++ b/iOS_SDK/OneSignalSDK/update_swift_package.sh @@ -8,6 +8,11 @@ WORKING_DIR=$(pwd) # read VERSION_NUMBER VERSION_NUMBER=$1 +if [ -z "${VERSION_NUMBER}" ]; then + echo "ERROR: release version argument is required (usage: $0 )" >&2 + exit 1 +fi + update_framework() { FRAMEWORK_FOLDER_NAME=$1 @@ -36,43 +41,80 @@ update_framework() { # Compute the checksum for the Zipped framework echo "Computing package checksum and updating Package.swift ${SWIFT_PACKAGE_PATH}" CHECKSUM=$(swift package compute-checksum "${FRAMEWORK_ZIP_PATH}") - SWIFT_PM_CHECKSUM_LINE=" checksum: \"${CHECKSUM}\"" - - # Use sed to remove line from the Swift.package and replace it with the new checksum - sed -i '' "$3s/.*/$SWIFT_PM_CHECKSUM_LINE/" "${SWIFT_PACKAGE_PATH}" - SWIFT_PM_URL_LINE=" url: \"https:\/\/github.com\/OneSignal\/OneSignal-iOS-SDK\/releases\/download\/${VERSION_NUMBER}\/${FRAMEWORK_NAME}.xcframework.zip\"," - #Use sed to remove line from the Swift.package and replace it with the new URL for the new release - sed -i '' "$4s/.*/$SWIFT_PM_URL_LINE/" "${SWIFT_PACKAGE_PATH}" + if [ -z "${CHECKSUM}" ]; then + echo "ERROR: empty checksum computed for ${FRAMEWORK_NAME}" >&2 + exit 1 + fi + # Update this framework's .binaryTarget in place, located by the framework + # name in its url line (NOT by hardcoded line number). Only the version in the + # url and the hash in the following checksum line are rewritten; surrounding + # structure/formatting is preserved. Matching by name keeps this correct even + # when the manifest layout shifts -- the previous line-number approach silently + # corrupted Package.swift once unrelated lines moved (broke 5.5.2 SPM). + awk -v fw="${FRAMEWORK_NAME}" -v ver="${VERSION_NUMBER}" -v chk="${CHECKSUM}" ' + # This framework'"'"'s url line: bump only the version path segment. + $0 ~ ("url: \"https://github.com/OneSignal/OneSignal-iOS-SDK/releases/download/[^/]*/" fw "\\.xcframework\\.zip\"") { + sub("download/[^/]*/", "download/" ver "/") + print + expect_checksum = 1 + next + } + # The checksum must sit on the line IMMEDIATELY after that url (the + # well-formed .binaryTarget layout). Only that one line is eligible, so a + # reordered/stray/renamed checksum line can never be clobbered: if it is not + # a checksum line nothing is rewritten and the post-run guard fails loudly. + expect_checksum { + expect_checksum = 0 + if ($0 ~ /^[[:space:]]*checksum: "[0-9a-fA-F]*"[[:space:]]*$/) { + sub("checksum: \"[0-9a-fA-F]*\"", "checksum: \"" chk "\"") + } + print + next + } + { print } + ' "${SWIFT_PACKAGE_PATH}" > "${SWIFT_PACKAGE_PATH}.tmp" + mv "${SWIFT_PACKAGE_PATH}.tmp" "${SWIFT_PACKAGE_PATH}" + + # Fail loudly if the entry was not found/updated, instead of silently leaving + # the manifest stale or malformed. + if ! grep -q "releases/download/${VERSION_NUMBER}/${FRAMEWORK_NAME}.xcframework.zip" "${SWIFT_PACKAGE_PATH}"; then + echo "ERROR: could not find/update url for ${FRAMEWORK_NAME} in Package.swift" >&2 + exit 1 + fi + if ! grep -q "checksum: \"${CHECKSUM}\"" "${SWIFT_PACKAGE_PATH}"; then + echo "ERROR: could not update checksum for ${FRAMEWORK_NAME} in Package.swift" >&2 + exit 1 + fi #Open XCFramework folder to drag zip into new release open "${WORKING_DIR}/${FRAMEWORK_FOLDER_NAME}" } ## OneSignal LiveActivities ## -update_framework "OneSignal_LiveActivities" "OneSignalLiveActivities" "163" "162" +update_framework "OneSignal_LiveActivities" "OneSignalLiveActivities" ## OneSignal Core ## -update_framework "OneSignal_Core" "OneSignalCore" "158" "157" +update_framework "OneSignal_Core" "OneSignalCore" ## OneSignal OSCore ## -update_framework "OneSignal_OSCore" "OneSignalOSCore" "153" "152" +update_framework "OneSignal_OSCore" "OneSignalOSCore" ## OneSignal Outcomes ## -update_framework "OneSignal_Outcomes" "OneSignalOutcomes" "148" "147" +update_framework "OneSignal_Outcomes" "OneSignalOutcomes" ## OneSignal Extension ## -update_framework "OneSignal_Extension" "OneSignalExtension" "143" "142" +update_framework "OneSignal_Extension" "OneSignalExtension" ## OneSignal Notifications ## -update_framework "OneSignal_Notifications" "OneSignalNotifications" "138" "137" +update_framework "OneSignal_Notifications" "OneSignalNotifications" ## OneSignal User ## -update_framework "OneSignal_User" "OneSignalUser" "133" "132" +update_framework "OneSignal_User" "OneSignalUser" ## OneSignal Location ## -update_framework "OneSignal_Location" "OneSignalLocation" "128" "127" +update_framework "OneSignal_Location" "OneSignalLocation" ## OneSignal InAppMessages ## -update_framework "OneSignal_InAppMessages" "OneSignalInAppMessages" "123" "122" +update_framework "OneSignal_InAppMessages" "OneSignalInAppMessages" ## OneSignal ## -update_framework "OneSignal_XCFramework" "OneSignalFramework" "118" "117" +update_framework "OneSignal_XCFramework" "OneSignalFramework"