fix(ios): make the RNSentry SPEC CHECKSUM in Podfile.lock machine-independent - #6534
fix(ios): make the RNSentry SPEC CHECKSUM in Podfile.lock machine-independent#6534alwx wants to merge 4 commits into
Conversation
…ependent CocoaPods stores external-source pods as an evaluated podspec JSON in Pods/Local Podspecs/ and derives the pod's SPEC CHECKSUM from that file, so the absolute ~/Library/Caches/... path we wrote into FRAMEWORK_SEARCH_PATHS leaked $HOME into Podfile.lock and made the RNSentry checksum differ per machine. Stage the cached Sentry.xcframework behind a symlink at Pods/sentry-xcframeworks/<version>/Sentry.xcframework and reference it as $(PODS_ROOT)/... instead. $(PODS_ROOT) is defined in both the per-pod and the user/aggregate xcconfigs and the link lives inside Pods/, so no Podfile-layout detection is needed and the string is identical on every machine — including machines overriding SENTRY_XCFRAMEWORK_CACHE_DIR. Fixes #6467
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
🤖 This preview updates automatically when you update the PR. |
antonis
left a comment
There was a problem hiding this comment.
LGTM once the CI is green and the changelog fixed 🙇
📲 Install BuildsAndroid
|
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1d3572b+dirty | 435.35 ms | 487.32 ms | 51.96 ms |
| d2eadf8+dirty | 414.64 ms | 454.56 ms | 39.92 ms |
| 7d8c8bd+dirty | 417.45 ms | 462.10 ms | 44.65 ms |
| bf168a4+dirty | 418.21 ms | 489.74 ms | 71.53 ms |
| 890d145+dirty | 504.54 ms | 491.55 ms | -12.99 ms |
| ad66da3+dirty | 468.46 ms | 533.56 ms | 65.10 ms |
| 15d4514+dirty | 406.77 ms | 428.06 ms | 21.29 ms |
| a0a3177+dirty | 441.27 ms | 499.86 ms | 58.59 ms |
| 6acdf1d+dirty | 513.58 ms | 608.31 ms | 94.72 ms |
| 038a6d7+dirty | 524.82 ms | 531.92 ms | 7.10 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1d3572b+dirty | 49.74 MiB | 55.38 MiB | 5.63 MiB |
| d2eadf8+dirty | 48.30 MiB | 53.48 MiB | 5.18 MiB |
| 7d8c8bd+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| bf168a4+dirty | 49.74 MiB | 55.09 MiB | 5.35 MiB |
| 890d145+dirty | 43.75 MiB | 48.14 MiB | 4.39 MiB |
| ad66da3+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
| 15d4514+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
| a0a3177+dirty | 49.74 MiB | 55.37 MiB | 5.63 MiB |
| 6acdf1d+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 038a6d7+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 2cac31b+dirty | 3854.43 ms | 1212.35 ms | -2642.08 ms |
| 244f6e8+dirty | 3825.51 ms | 1217.76 ms | -2607.75 ms |
| 9474ead+dirty | 3823.33 ms | 1208.31 ms | -2615.03 ms |
| 44c8b3f+dirty | 3849.24 ms | 1209.94 ms | -2639.31 ms |
| 61cc206+dirty | 3822.60 ms | 1206.17 ms | -2616.43 ms |
| acd838e+dirty | 3835.94 ms | 1215.87 ms | -2620.07 ms |
| b0d3373+dirty | 3842.49 ms | 1218.49 ms | -2624.00 ms |
| fa21fca+dirty | 3845.12 ms | 1215.89 ms | -2629.24 ms |
| 0d9949d+dirty | 1203.94 ms | 1202.27 ms | -1.67 ms |
| a5d243c+dirty | 3827.92 ms | 1220.10 ms | -2607.81 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 2cac31b+dirty | 4.98 MiB | 6.55 MiB | 1.58 MiB |
| 244f6e8+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
| 9474ead+dirty | 5.15 MiB | 6.71 MiB | 1.55 MiB |
| 44c8b3f+dirty | 5.15 MiB | 6.66 MiB | 1.51 MiB |
| 61cc206+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| acd838e+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| b0d3373+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| fa21fca+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| 0d9949d+dirty | 3.38 MiB | 4.76 MiB | 1.38 MiB |
| a5d243c+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1d3572b+dirty | 444.48 ms | 478.42 ms | 33.94 ms |
| 6177334+dirty | 404.80 ms | 456.74 ms | 51.94 ms |
| 5a23c47+dirty | 406.83 ms | 451.47 ms | 44.64 ms |
| a3265b6+dirty | 410.96 ms | 444.76 ms | 33.80 ms |
| bf168a4+dirty | 430.60 ms | 459.31 ms | 28.71 ms |
| ca9d079+dirty | 460.67 ms | 512.54 ms | 51.87 ms |
| ef27341+dirty | 519.02 ms | 553.42 ms | 34.40 ms |
| 23598c3+dirty | 371.92 ms | 420.65 ms | 48.74 ms |
| 7d6fd3a+dirty | 435.06 ms | 458.78 ms | 23.72 ms |
| a50b33d+dirty | 353.21 ms | 398.48 ms | 45.27 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 1d3572b+dirty | 49.74 MiB | 55.38 MiB | 5.63 MiB |
| 6177334+dirty | 48.30 MiB | 53.54 MiB | 5.23 MiB |
| 5a23c47+dirty | 49.74 MiB | 54.82 MiB | 5.07 MiB |
| a3265b6+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| bf168a4+dirty | 49.74 MiB | 55.09 MiB | 5.35 MiB |
| ca9d079+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| ef27341+dirty | 48.30 MiB | 53.54 MiB | 5.24 MiB |
| 23598c3+dirty | 43.94 MiB | 49.02 MiB | 5.08 MiB |
| 7d6fd3a+dirty | 43.94 MiB | 49.00 MiB | 5.06 MiB |
| a50b33d+dirty | 43.94 MiB | 48.94 MiB | 5.00 MiB |
The 8.21.0 release was cut while this PR was open, so the merge from main landed the entry inside the released section and reordered an unrelated Session Replay item. Restore 8.21.0 verbatim from main and add a fresh Unreleased section.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit dc4206f. Configure here.
| "(#{e.class}: #{e.message}). Falling back to the absolute cache path; " \ | ||
| "the RNSentry checksum in Podfile.lock will be machine-specific." | ||
| end | ||
| nil |
There was a problem hiding this comment.
Prune errors force checksum fallback
Medium Severity
In stage_sentry_xcframework_in_pods, a failure while pruning older sentry-xcframeworks version directories is handled by the same rescue that covers symlink staging. After the current symlink is created successfully, that cleanup error makes the method return nil, so the podspec falls back to absolute cache paths in FRAMEWORK_SEARCH_PATHS and the RNSentry lockfile checksum becomes machine-specific again.
Reviewed by Cursor Bugbot for commit dc4206f. Configure here.
There was a problem hiding this comment.
@alwx The above looks valid 👍 Feel free to handle it in a follow up if the solution is complicated.
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 2cac31b+dirty | 3886.27 ms | 1230.85 ms | -2655.42 ms |
| 244f6e8+dirty | 3833.36 ms | 1212.96 ms | -2620.41 ms |
| 61cc206+dirty | 3849.70 ms | 1230.33 ms | -2619.38 ms |
| 04207c4+dirty | 1191.27 ms | 1189.78 ms | -1.48 ms |
| acd838e+dirty | 3849.78 ms | 1230.00 ms | -2619.78 ms |
| fa21fca+dirty | 3840.43 ms | 1224.42 ms | -2616.02 ms |
| 0d9949d+dirty | 1211.38 ms | 1219.67 ms | 8.29 ms |
| bc8f61e+dirty | 3819.00 ms | 1220.22 ms | -2598.78 ms |
| ca9d079+dirty | 3835.63 ms | 1218.68 ms | -2616.95 ms |
| 5a316ea+dirty | 3820.11 ms | 1211.28 ms | -2608.83 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 2cac31b+dirty | 4.98 MiB | 6.55 MiB | 1.58 MiB |
| 244f6e8+dirty | 4.98 MiB | 6.56 MiB | 1.58 MiB |
| 61cc206+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| 04207c4+dirty | 3.38 MiB | 4.76 MiB | 1.38 MiB |
| acd838e+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| fa21fca+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| 0d9949d+dirty | 3.38 MiB | 4.76 MiB | 1.38 MiB |
| bc8f61e+dirty | 4.98 MiB | 6.47 MiB | 1.49 MiB |
| ca9d079+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 5a316ea+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |


📢 Type of change
📜 Description
Since #6413,
RNSentry.podspecpointsFRAMEWORK_SEARCH_PATHSat the absolute pod-install-time path of the cachedSentry.xcframework(~/Library/Caches/sentry-react-native/xcframeworks/…), which leaks$HOMEinto theRNSentrySPEC CHECKSUMwritten toPodfile.lock.This stages the cached bundle behind a machine-independent reference instead:
stage_sentry_xcframework_in_pods(new,sentry_utils.rb) symlinksPods/sentry-xcframeworks/<sentry-cocoa version>/Sentry.xcframework→ the cached bundle, recreating the link when it's missing or stale (e.g.SENTRY_XCFRAMEWORK_CACHE_DIRchanged between installs) and pruning links left behind by earlier SDK versions."$(PODS_ROOT)/sentry-xcframeworks/<version>/Sentry.xcframework/<slice>"intoFRAMEWORK_SEARCH_PATHS— the same string on every machine, so the checksum is deterministic.$(PODS_ROOT)is defined in both per-pod and user/aggregate xcconfigs (unlike$(PODS_TARGET_SRCROOT)), and because the link lives insidePods/there is no Podfile-layout detection needed.pod install(gated onPod::Config.instance.podfile_path). Anywhere else —pod ipc spec,pod lib lint, a plainSpecification.from_file—$(PODS_ROOT)would point at an unrelated sandbox, so we fall back to the absolute cache path. Same fallback if the symlink can't be created: functional, just with a machine-specific checksum.The download/cache/SHA256-verification flow is unchanged; the cache stays in
~/Library/Caches(still shared across projects, still safe under pnpm's read-only store and Yarn PnP).Note: existing projects will see a one-time
RNSentrychecksum change inPodfile.lockon their nextpod install; after that the value is stable across developers and CI. Teams that adopted theSENTRY_XCFRAMEWORK_CACHE_DIR=/tmp/…workaround from #6467 can drop it — and mixed setups (some machines with the override, some without) now converge on the same checksum, since the override no longer appears in the spec.💡 Motivation and Context
Fixes #6467.
CocoaPods persists external-source pods as an evaluated podspec JSON in
Pods/Local Podspecs/RNSentry.podspec.json(ExternalSources::AbstractExternalSource#store_podspecalways callssandbox.store_podspec(name, spec, true, true)), andSpecification#checksumis the SHA1 of that file. The evaluatedpod_target_xcconfig/user_target_xcconfigtherefore carried the$HOME-dependent path straight intoPodfile.lock.Consequence: two developers (or a developer and CI) installing the exact same
@sentry/react-nativeversion get differentRNSentrychecksums, so a committedPodfile.lockflips on everypod installand teams gating CI on a clean lockfile get repeated failures. Same class of problem as facebook/react-native#31193.Supersedes #6474, with two fixes on top of it:
<cwd>/PodswhenPod::Configwas unavailable and still returned a$(PODS_ROOT)path. CocoaPods evaluates podspecs with the CWD set to the podspec's own directory, so that would have staged the link insidenode_modules/@sentry/react-native/while handing back a search path that dangles at build time — a hardmodule 'Sentry' not foundinstead of the safe absolute-path fallback.Pods/.💚 How did you test it?
All on macOS with CocoaPods 1.16.2 / Xcode 26.1.
Checksum determinism — reproduced CocoaPods' exact computation (
Digest::SHA1.hexdigest(spec.to_pretty_json)) while evaluating the podspec under two different$HOMEvalues:origin/main:842e4309…vs8b743fb4…— bug reproduced.43ccbce8…both times, and the two evaluated specs are byte-identical.Pods/Local Podspecs/RNSentry.podspec.jsonafter a real install contains zero/Users/…strings (down from the leaking path).SENTRY_XCFRAMEWORK_CACHE_DIR=/tmp/sentry-xcf-alt pod installyields the same checksum as without the override, and re-points the stale symlink.Real
pod installinsamples/react-native/iosandpackages/core/RNSentryCocoaTester(different Podfile depths):$(PODS_ROOT)resolves correctly in both the per-pod xcconfig (PODS_ROOT = ${SRCROOT}) and the aggregate/user xcconfig (PODS_ROOT = ${SRCROOT}/Pods). Repeated installs keep the checksum stable and the symlink survives —Installer::SandboxDirCleaneronly removes.xcodeprojchildren, target-support and header directories, so the staging dir is untouched.Builds:
xcodebuild -scheme RNSentry -sdk iphonesimulator→ BUILD SUCCEEDED (@import Sentryresolves through the symlink).xcodebuild -workspace sentryreactnativesample.xcworkspace→ BUILD SUCCEEDED;nmon the resulting debug dylib shows 168 Sentry symbols. NoSentryCocoaPod exists inPodfile.lock, so linking necessarily went through the staged path.-showBuildSettingsconfirmsFRAMEWORK_SEARCH_PATHSexpands to…/ios/Pods/sentry-xcframeworks/9.19.1/Sentry.xcframework/ios-arm64_x86_64-simulator.Edge cases:
SENTRY_USE_XCFRAMEWORK=0stages nothing and keeps theSentrypod dependency; stale/wrong symlinks and leftover version directories are recreated/pruned;rm_rfunlinks the symlink without following it (shared cache verified intact afterwards); evaluation without a Podfile falls back to the absolute path and creates no stray directories.ruby -cpasses on both files.📝 Checklist
sendDefaultPIIis enabled.Note on tests: the repo has no Ruby test infrastructure, so this is covered by the manual verification above plus the
pod installjobs insample-application.yml/native-tests.yml, which exercise the new staging path end-to-end.🔮 Next steps
Add the
ready-to-mergelabel to run the native/E2E/sample-build jobs before merging — those are the ones that exercisepod installacross RN versions and theuse_frameworks!variants.