Repository: getsentry/sentry-cocoa
Pull request #5271: ci: build and sign xcframework
Author: login: itaybre
Created: 2025-05-21T01:18:24Z | Merged: 2025-05-26T13:41:22Z

## :scroll: Description

Sign xcframework when building it

## :bulb: Motivation and Context

<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->

## :green_heart: How did you test it?

## :pencil: Checklist

You have to check all boxes before merging:

- [ ] I added tests to verify the changes.
- [ ] No new PII added or SDK only sends newly added PII if `sendDefaultPII` is enabled.
- [ ] I updated the docs if needed.
- [ ] I updated the wizard if needed.
- [ ] Review from the native team if needed.
- [ ] No breaking change or entry added to the changelog.
- [ ] No breaking change for hybrid SDKs or communicated to hybrid SDKs.



Diff:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 99b64ff4990..c6e68483b4f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,6 +21,22 @@ jobs:
     steps:
       - uses: actions/checkout@v4
 
+      - uses: ruby/setup-ruby@v1
+        with:
+          bundler-cache: true
+
+      - name: "Download Fastlane Certificate"
+        run: bundle exec fastlane prepare_signed_xcframework
+        env:
+          APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
+          APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
+          APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }}
+          FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
+          MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
+          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+          MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
+        shell: sh
+
       - name: "Generate XCFramework"
         run: |
           ./scripts/ci-select-xcode.sh 15.2
@@ -28,7 +44,7 @@ jobs:
           # We need to build the framework during release to get it's SHA value
           # the framework will be saved as an artefact and we will use the same
           # binary for the entire release process to avoid the SHA to change
-          make build-xcframework
+          make build-signed-xcframework
 
       - uses: actions/upload-artifact@v4
         with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7eeebddd4f4..5f085ed5267 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## Unreleased
+
+### Features
+
+- XCFrameworks are now signed (#5271)
+
 ## 8.51.1
 
 ### Fixes
diff --git a/Makefile b/Makefile
index 5741c46bd37..3129bbe0872 100644
--- a/Makefile
+++ b/Makefile
@@ -105,11 +105,12 @@ analyze:
 build-xcframework:
 	@echo "--> Carthage: creating Sentry xcframework"
 	./scripts/build-xcframework.sh | tee build-xcframework.log
-# use ditto here to avoid clobbering symlinks which exist in macOS frameworks
-	ditto -c -k -X --rsrc --keepParent Carthage/Sentry.xcframework Carthage/Sentry.xcframework.zip
-	ditto -c -k -X --rsrc --keepParent Carthage/Sentry-Dynamic.xcframework Carthage/Sentry-Dynamic.xcframework.zip
-	ditto -c -k -X --rsrc --keepParent Carthage/SentrySwiftUI.xcframework Carthage/SentrySwiftUI.xcframework.zip
-	ditto -c -k -X --rsrc --keepParent Carthage/Sentry-WithoutUIKitOrAppKit.xcframework Carthage/Sentry-WithoutUIKitOrAppKit.zip
+	./scripts/zip_built_sdks.sh
+
+build-signed-xcframework:
+	@echo "--> Carthage: creating Signed Sentry xcframework"
+	./scripts/build-xcframework.sh | tee build-xcframework.log
+	./scripts/zip_built_sdks.sh --sign
 
 build-xcframework-sample:
 	./scripts/create-carthage-json.sh
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 7b69bbdf682..b3bf6c49202 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -9,6 +9,16 @@ platform :ios do
   ios_swift_clip_infoplist_path = "./Samples/iOS-Swift/iOS-SwiftClip/Info.plist"
   configuration = if is_ci then 'TestCI' else 'Test' end
 
+  lane :prepare_signed_xcframework do
+    setup_ci
+
+    match(
+      type: "appstore",
+      readonly: true,
+      app_identifier: ["io.sentry.sample.iOS-Swift"], # Any app identifier will do
+    )
+  end
+
   lane :bump_build_number do
     increment_build_number(
       build_number: ENV["FASTLANE_BUILD_NUMBER"],
diff --git a/scripts/zip_built_sdks.sh b/scripts/zip_built_sdks.sh
new file mode 100755
index 00000000000..ca09109ce12
--- /dev/null
+++ b/scripts/zip_built_sdks.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -eou pipefail
+
+args="${1:-}"
+
+frameworks=( Sentry Sentry-Dynamic SentrySwiftUI Sentry-WithoutUIKitOrAppKit )
+
+should_sign=false
+[[ "$args" == "--sign" ]] && should_sign=true
+
+sentry_certificate="Apple Distribution: GetSentry LLC (97JCY7859U)"
+
+for framework in "${frameworks[@]}"; do
+    framework_path="Carthage/$framework.xcframework"
+
+    if [[ "$should_sign" == true ]]; then
+        echo "Signing $framework"
+        # This is Sentry's certificate name, and should not change
+        codesign --sign "$sentry_certificate" --timestamp --options runtime --deep --force "$framework_path"
+    fi
+
+    echo "Zipping $framework"
+    # use ditto here to avoid clobbering symlinks which exist in macOS frameworks
+    ditto -c -k -X --rsrc --keepParent "$framework_path" "$framework_path.zip"
+done
\ No newline at end of file


Reviews:
user: login: philprime
body: Thanks for looking into this.

1. How long are frameworks signed?
2. What happens when frameworks are not signed anymore?
3. What happens if a certificate is revoked?

We should make sure that older versions of the framework can still be used.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T07:41:15Z
user: login: philipphofmann
body: Thanks for doing this. I added a few comments.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-21T14:07:49Z
user: login: itaybre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T14:25:07Z
user: login: itaybre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T14:26:01Z
user: login: itaybre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T14:50:51Z
user: login: itaybre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T15:39:51Z
user: login: philprime
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T08:44:36Z
user: login: philipphofmann
body: Thanks for doing this. After merging this, I think a beta release and manually including the signed XCFramwork via SPM in a sample project is mandatory. We also must communicate this change to the Hybrid SDKs and let them try it with this beta release. Only when all this succeeds, I'm confident enough to ship a normal release.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-23T09:19:53Z

Review comments:
diff_hunk: @@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -eou pipefail
+
+args="${1:-}"
+
+if [ -z "$args" ]; then
+    echo "Usage: $0 <path-to-xcframework>"
+    exit 1
+fi
+
+codesign --sign "Apple Distribution: GetSentry LLC (97JCY7859U)" \
+         --timestamp \
+         --options runtime \
+         --deep \
+         --force \
+         "$args"
+
+ditto -c -k -X --rsrc --keepParent "$args" "$args.zip"
path: scripts/sign_and_zip.sh
user: login: philipphofmann
body: `m`: I think we should add the same comment as in the makefile to explain why we use ditto 
```suggestion
# use ditto here to avoid clobbering symlinks which exist in macOS frameworks
ditto -c -k -X --rsrc --keepParent "$args" "$args.zip"
```
created_at: 2025-05-21T13:59:20Z
author_association: MEMBER
diff_hunk: @@ -111,6 +111,14 @@ build-xcframework:
 	ditto -c -k -X --rsrc --keepParent Carthage/SentrySwiftUI.xcframework Carthage/SentrySwiftUI.xcframework.zip
 	ditto -c -k -X --rsrc --keepParent Carthage/Sentry-WithoutUIKitOrAppKit.xcframework Carthage/Sentry-WithoutUIKitOrAppKit.zip
 
+build-xcframework-sign:
+	@echo "--> Carthage: creating Signed Sentry xcframework"
+	./scripts/build-xcframework.sh | tee build-xcframework.log
+	./scripts/sign_and_zip.sh Carthage/Sentry.xcframework
+	./scripts/sign_and_zip.sh Carthage/Sentry-Dynamic.xcframework
+	./scripts/sign_and_zip.sh Carthage/SentrySwiftUI.xcframework
+	./scripts/sign_and_zip.sh Carthage/Sentry-WithoutUIKitOrAppKit.xcframework
path: Makefile
user: login: philipphofmann
body: `m`: We could modify the bash script so it takes a parameter that specifies if you want to sign it or not. Then both `build-xcframework` and `build-xcframework-sign` would use the same script and we have less duplication of the code.
created_at: 2025-05-21T14:00:40Z
author_association: MEMBER
diff_hunk: @@ -111,6 +111,14 @@ build-xcframework:
 	ditto -c -k -X --rsrc --keepParent Carthage/SentrySwiftUI.xcframework Carthage/SentrySwiftUI.xcframework.zip
 	ditto -c -k -X --rsrc --keepParent Carthage/Sentry-WithoutUIKitOrAppKit.xcframework Carthage/Sentry-WithoutUIKitOrAppKit.zip
 
+build-xcframework-sign:
path: Makefile
user: login: philipphofmann
body: `l`: Maybe a bit clearer:
```suggestion
build-signed-xcframework:
```
created_at: 2025-05-21T14:01:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
+
+jobs:
+  prepare_framework:
+    runs-on: macos-13-xlarge
+    name: "Create XCFramework"
+    steps:
+      - uses: actions/checkout@v4
+      - uses: ruby/setup-ruby@v1
+        with:
+          bundler-cache: true
+
+      - name: "Download Fastlane Certificate"
+        run: bundle exec fastlane prepare_sign_xcframework
+        env:
+          APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
+          APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
+          APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }}
+          FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
+          MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
+          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+          MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
+        shell: sh
+
+      - name: "Generate XCFramework"
+        run: |
+          ./scripts/ci-select-xcode.sh 15.2
+          # make bump-version TO=${{ github.event.inputs.version }}
+          # We need to build the framework during release to get it's SHA value
+          # the framework will be saved as an artefact and we will use the same
+          # binary for the entire release process to avoid the SHA to change
path: .github/workflows/test_sign_xcframework.yml
user: login: philipphofmann
body: `l`: I think that comment is irrelevant here.
```suggestion
```
created_at: 2025-05-21T14:02:26Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
path: .github/workflows/test_sign_xcframework.yml
user: login: philipphofmann
body: `m`: What about also running it on main? Maybe only main is OK. I'm unsure what the benefit is for running this for every PR.
created_at: 2025-05-21T14:03:36Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
+
+jobs:
+  prepare_framework:
+    runs-on: macos-13-xlarge
path: .github/workflows/test_sign_xcframework.yml
user: login: philipphofmann
body: `h`: Please don't use an xlarge runner. Running this on every PR costs easily around 2k $ a month or most likely more. We obviously can spend 2k a month, but only if it makes sense. Let's use a `macos-14` please. We can't use macos-13 as mentioned here
https://github.com/getsentry/sentry-cocoa/blob/aa48954db865ed82e38feb313885dc6cb372cc8b/.github/workflows/build.yml#L101-L105

created_at: 2025-05-21T14:05:33Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
+
+jobs:
+  prepare_framework:
+    runs-on: macos-13-xlarge
path: .github/workflows/test_sign_xcframework.yml
user: login: itaybre
body: I copied an existing workflow, and didn't notice that.
Either way this is not a PR ready to merge (should have created it as draft). I wanted to make sure the xcframework signing was working on CI.
I will delete this workflow before merging
created_at: 2025-05-21T14:25:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
path: .github/workflows/test_sign_xcframework.yml
user: login: itaybre
body: As mentioned on the other comment, this workflow was only to make sure this worked.
I will delete it and update the release one to generate signed releases before merging
created_at: 2025-05-21T14:26:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
+
+jobs:
+  prepare_framework:
+    runs-on: macos-13-xlarge
+    name: "Create XCFramework"
+    steps:
+      - uses: actions/checkout@v4
+      - uses: ruby/setup-ruby@v1
+        with:
+          bundler-cache: true
+
+      - name: "Download Fastlane Certificate"
+        run: bundle exec fastlane prepare_sign_xcframework
+        env:
+          APP_STORE_CONNECT_KEY_ID: ${{ secrets.APP_STORE_CONNECT_KEY_ID }}
+          APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
+          APP_STORE_CONNECT_KEY: ${{ secrets.APP_STORE_CONNECT_KEY }}
+          FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
+          MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
+          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+          MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}
+        shell: sh
+
+      - name: "Generate XCFramework"
+        run: |
+          ./scripts/ci-select-xcode.sh 15.2
+          # make bump-version TO=${{ github.event.inputs.version }}
+          # We need to build the framework during release to get it's SHA value
+          # the framework will be saved as an artefact and we will use the same
+          # binary for the entire release process to avoid the SHA to change
path: .github/workflows/test_sign_xcframework.yml
user: login: itaybre
body: Same as above, this is not a relevant workflow and will be deleted
created_at: 2025-05-21T14:50:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -eou pipefail
+
+args="${1:-}"
+
+frameworks=( Sentry Sentry-Dynamic SentrySwiftUI Sentry-WithoutUIKitOrAppKit )
+
+should_sign=false
+[[ "$args" == "--sign" ]] && should_sign=true
+
+sentry_certificate="Apple Distribution: GetSentry LLC (97JCY7859U)"
+
+for framework in "${frameworks[@]}"; do
+    framework_path="Carthage/$framework.xcframework"
+
+    if [[ "$should_sign" == true ]]; then
+        echo "Signing $framework"
+        # This is Sentry's certificate name, and should not change
+        codesign --sign "$sentry_certificate" --timestamp --options runtime --deep --force "$framework_path"
+    fi
+
+    echo "Zipping $framework"
+    ditto -c -k -X --rsrc --keepParent "$framework_path" "$framework_path.zip"
path: scripts/zip_built_sdks.sh
user: login: itaybre
body: ```suggestion
    # use ditto here to avoid clobbering symlinks which exist in macOS frameworks
    ditto -c -k -X --rsrc --keepParent "$framework_path" "$framework_path.zip"
```
created_at: 2025-05-21T15:39:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,46 @@
+name: Test Build Signed XCFramework
+run-name: Test Build Signed XCFramework
+
+on:
+  pull_request:
+
+jobs:
+  prepare_framework:
+    runs-on: macos-13-xlarge
path: .github/workflows/test_sign_xcframework.yml
user: login: philprime
body: @itaybre you can convert it back to draft
created_at: 2025-05-22T08:44:35Z
author_association: MEMBER
diff_hunk: @@ -9,6 +9,16 @@ platform :ios do
   ios_swift_clip_infoplist_path = "./Samples/iOS-Swift/iOS-SwiftClip/Info.plist"
   configuration = if is_ci then 'TestCI' else 'Test' end
 
+  lane :prepare_sign_xcframework do
path: fastlane/Fastfile
user: login: philipphofmann
body: ``l`: o align the naming with the make file
```suggestion
  lane :prepare_signed_xcframework do
```
created_at: 2025-05-23T09:16:48Z
author_association: MEMBER

PR comments:
user: login: codecov[bot]
created_at: 2025-05-21T01:34:06Z
body: ## [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 92.897%. Comparing base [(`87e12d9`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/87e12d94c6f53b05f67c7d399cf82f2cd6322aef?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry) to head [(`16c45fd`)](https://app.codecov.io/gh/getsentry/sentry-cocoa/commit/16c45fd925f73a0b52e2376ca387eb7993434a3a?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> Report is 6 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271/graphs/tree.svg?width=650&height=150&src=pr&token=PTZKtOJlrs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

```diff
@@              Coverage Diff              @@
##              main     #5271       +/-   ##
=============================================
+ Coverage   92.806%   92.897%   +0.091%     
=============================================
  Files          688       688               
  Lines        86297     86306        +9     
  Branches     30104     31209     +1105     
=============================================
+ Hits         80089     80176       +87     
+ Misses        6113      6029       -84     
- Partials        95       101        +6     
```

[see 21 files with indirect coverage changes](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)

------

[Continue to review full report in Codecov by Sentry](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271?dropdown=coverage&src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Last update [87e12d9...16c45fd](https://app.codecov.io/gh/getsentry/sentry-cocoa/pull/5271?dropdown=coverage&src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=getsentry).

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-21T01:42:08Z
body: ##  Performance metrics :rocket:
<table>
  <tr>
    <th>&nbsp;</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr>
  <tr>
    <th align="left">Startup time</th>
    <td align="right">1231.54 ms</td>
    <td align="right">1259.08 ms</td>
    <td align="right"><strong>27.54 ms</strong></td>
  </tr>
  <tr>
    <th align="left">Size</th>
    <td align="right">23.76 KiB</td>
    <td align="right">821.43 KiB</td>
    <td align="right"><strong>797.67 KiB</strong></td>
  </tr>
</table>
<details><summary><h3>Baseline results on branch: main</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">0dfdaaa56bcc987ef5cf30a9e5e173cf127fa81d</th>
  <td align="right">1226.88 ms</td>
  <td align="right">1248.82 ms</td>
  <td align="right"><strong>21.94 ms</strong></td>
</tr><tr>
  <th align="left">216bdf9e7829593fd30a282fef734663f9b17d99</th>
  <td align="right">1196.29 ms</td>
  <td align="right">1209.80 ms</td>
  <td align="right"><strong>13.51 ms</strong></td>
</tr><tr>
  <th align="left">27f970b87b06526e39b759311d9e1512598ae0f7</th>
  <td align="right">1223.48 ms</td>
  <td align="right">1239.51 ms</td>
  <td align="right"><strong>16.03 ms</strong></td>
</tr><tr>
  <th align="left">39b1c353b26407f787556148d2c9ef35d6a394f5</th>
  <td align="right">1244.71 ms</td>
  <td align="right">1248.60 ms</td>
  <td align="right"><strong>3.89 ms</strong></td>
</tr><tr>
  <th align="left">2719ce6ca7647b6d87f0e3e16f47e16de0a483a1</th>
  <td align="right">1211.75 ms</td>
  <td align="right">1237.16 ms</td>
  <td align="right"><strong>25.41 ms</strong></td>
</tr><tr>
  <th align="left">716a5b0ea1d64474b2285f5799a81ff0faac918f</th>
  <td align="right">1240.21 ms</td>
  <td align="right">1265.81 ms</td>
  <td align="right"><strong>25.60 ms</strong></td>
</tr><tr>
  <th align="left">2b19b824dceb9cfbc46e41c29829d188161043d8</th>
  <td align="right">1226.73 ms</td>
  <td align="right">1243.27 ms</td>
  <td align="right"><strong>16.53 ms</strong></td>
</tr><tr>
  <th align="left">dea0b008afa2895ed6ba9f036692b0dc480e1d40</th>
  <td align="right">1229.94 ms</td>
  <td align="right">1250.43 ms</td>
  <td align="right"><strong>20.49 ms</strong></td>
</tr><tr>
  <th align="left">8e76be4558a9e15fe63841bbb98faec7d921f24e</th>
  <td align="right">1272.67 ms</td>
  <td align="right">1286.38 ms</td>
  <td align="right"><strong>13.71 ms</strong></td>
</tr><tr>
  <th align="left">0204c7276ae7a4e0d8a528c7ef2f35eacf8050f8</th>
  <td align="right">1230.35 ms</td>
  <td align="right">1242.04 ms</td>
  <td align="right"><strong>11.69 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">0dfdaaa56bcc987ef5cf30a9e5e173cf127fa81d</th>
  <td align="right">20.76 KiB</td>
  <td align="right">434.56 KiB</td>
  <td align="right"><strong>413.79 KiB</strong></td>
</tr><tr>
  <th align="left">216bdf9e7829593fd30a282fef734663f9b17d99</th>
  <td align="right">21.58 KiB</td>
  <td align="right">418.13 KiB</td>
  <td align="right"><strong>396.54 KiB</strong></td>
</tr><tr>
  <th align="left">27f970b87b06526e39b759311d9e1512598ae0f7</th>
  <td align="right">21.58 KiB</td>
  <td align="right">706.97 KiB</td>
  <td align="right"><strong>685.39 KiB</strong></td>
</tr><tr>
  <th align="left">39b1c353b26407f787556148d2c9ef35d6a394f5</th>
  <td align="right">22.85 KiB</td>
  <td align="right">408.88 KiB</td>
  <td align="right"><strong>386.03 KiB</strong></td>
</tr><tr>
  <th align="left">2719ce6ca7647b6d87f0e3e16f47e16de0a483a1</th>
  <td align="right">20.76 KiB</td>
  <td align="right">435.13 KiB</td>
  <td align="right"><strong>414.37 KiB</strong></td>
</tr><tr>
  <th align="left">716a5b0ea1d64474b2285f5799a81ff0faac918f</th>
  <td align="right">22.31 KiB</td>
  <td align="right">756.95 KiB</td>
  <td align="right"><strong>734.64 KiB</strong></td>
</tr><tr>
  <th align="left">2b19b824dceb9cfbc46e41c29829d188161043d8</th>
  <td align="right">21.58 KiB</td>
  <td align="right">542.18 KiB</td>
  <td align="right"><strong>520.60 KiB</strong></td>
</tr><tr>
  <th align="left">dea0b008afa2895ed6ba9f036692b0dc480e1d40</th>
  <td align="right">22.31 KiB</td>
  <td align="right">821.41 KiB</td>
  <td align="right"><strong>799.10 KiB</strong></td>
</tr><tr>
  <th align="left">8e76be4558a9e15fe63841bbb98faec7d921f24e</th>
  <td align="right">20.76 KiB</td>
  <td align="right">427.66 KiB</td>
  <td align="right"><strong>406.89 KiB</strong></td>
</tr><tr>
  <th align="left">0204c7276ae7a4e0d8a528c7ef2f35eacf8050f8</th>
  <td align="right">21.58 KiB</td>
  <td align="right">540.04 KiB</td>
  <td align="right"><strong>518.46 KiB</strong></td>
</tr></table>
</details>
<details><summary><h3>Previous results on branch: feature/sign_xcframework</h3></summary>
<h3>Startup times</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">c1019a7422e1ccccc96fcd1ca0764038271a0253</th>
  <td align="right">1223.35 ms</td>
  <td align="right">1245.58 ms</td>
  <td align="right"><strong>22.24 ms</strong></td>
</tr><tr>
  <th align="left">e32e41e404040f28d97ed014f86ea2af726b57e0</th>
  <td align="right">1226.69 ms</td>
  <td align="right">1242.50 ms</td>
  <td align="right"><strong>15.81 ms</strong></td>
</tr><tr>
  <th align="left">2cab324f1ef81f00522259312178872f7d1edbed</th>
  <td align="right">1234.12 ms</td>
  <td align="right">1251.43 ms</td>
  <td align="right"><strong>17.30 ms</strong></td>
</tr></table>
<h3>App size</h3>
<table>
  <tr>
    <th>Revision</th>
    <th align="right">Plain</th>
    <th align="right">With Sentry</th>
    <th align="right">Diff</th>
  </tr><tr>
  <th align="left">c1019a7422e1ccccc96fcd1ca0764038271a0253</th>
  <td align="right">23.76 KiB</td>
  <td align="right">821.30 KiB</td>
  <td align="right"><strong>797.54 KiB</strong></td>
</tr><tr>
  <th align="left">e32e41e404040f28d97ed014f86ea2af726b57e0</th>
  <td align="right">23.76 KiB</td>
  <td align="right">821.30 KiB</td>
  <td align="right"><strong>797.54 KiB</strong></td>
</tr><tr>
  <th align="left">2cab324f1ef81f00522259312178872f7d1edbed</th>
  <td align="right">23.76 KiB</td>
  <td align="right">821.30 KiB</td>
  <td align="right"><strong>797.54 KiB</strong></td>
</tr></table>
</details>

author_association: CONTRIBUTOR
user: login: philipphofmann
created_at: 2025-05-21T14:08:36Z
body: > Thanks for looking into this.
> 
> 1. How long are frameworks signed?
> 2. What happens when frameworks are not signed anymore?
> 3. What happens if a certificate is revoked?
> 
> We should make sure that older versions of the framework can still be used.

We can also answer these questions after merging this PR. We must answer them before using the signed XCFramework in releases.
author_association: MEMBER
user: login: philipphofmann
created_at: 2025-06-03T12:20:29Z
body: Smoke test. I manually included the XCFrameworks from this release https://github.com/getsentry/sentry-cocoa/releases/tag/8.52.0-beta into a sample project and Xcode says the signature is valid


![image](https://github.com/user-attachments/assets/c9616900-6d09-4eba-a6d6-e6c3fb530993)

![image](https://github.com/user-attachments/assets/36fd5402-9012-4553-b976-560380059bbe)

For reference
author_association: MEMBER