From c471efbfd6f7741e4aba6de403faf0be78874734 Mon Sep 17 00:00:00 2001 From: Adam Essenmacher Date: Fri, 17 Apr 2026 23:12:27 -0400 Subject: [PATCH 1/2] Fix Firebase version symbol lookups --- .github/workflows/firebase-e2e.yml | 64 +++++++++++++++++++++ docs/firebase-runtime-failure-backlog.md | 5 +- source/Firebase/Auth/Extension.cs | 6 +- source/Firebase/CloudFunctions/Extension.cs | 6 +- 4 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/firebase-e2e.yml diff --git a/.github/workflows/firebase-e2e.yml b/.github/workflows/firebase-e2e.yml new file mode 100644 index 00000000..751df1c5 --- /dev/null +++ b/.github/workflows/firebase-e2e.yml @@ -0,0 +1,64 @@ +name: Firebase E2E + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +jobs: + firebase-e2e: + runs-on: macos-15 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Toolchain versions + run: | + xcodebuild -version + swift --version + xcode-select -p + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Restore .NET workloads + run: dotnet workload restore Xamarin.Google.sln + + - name: Install CocoaPods + run: | + if ! command -v pod >/dev/null 2>&1; then + sudo gem install cocoapods + fi + pod --version + + - name: Restore tools + run: dotnet tool restore + + - name: Build + pack Firebase Analytics slice + run: dotnet tool run dotnet-cake -- --target=nuget --names="Firebase.Analytics" + + - name: Build Mac Catalyst consumer app + run: | + dotnet build tests/E2E/Firebase.Foundation/FirebaseFoundationE2E/FirebaseFoundationE2E.csproj \ + --configuration Release \ + --framework net9.0-maccatalyst \ + --configfile tests/E2E/Firebase.Foundation/NuGet.config \ + -p:RuntimeIdentifier=maccatalyst-arm64 \ + -p:EnableCodeSigning=false + + - name: Run iOS simulator E2E smoke test + run: tools/e2e/run-firebase-foundation.sh --package-dir output --configuration Debug + + - name: Upload E2E artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: firebase-e2e-artifacts + path: tests/E2E/Firebase.Foundation/artifacts/** diff --git a/docs/firebase-runtime-failure-backlog.md b/docs/firebase-runtime-failure-backlog.md index 66ed7fa4..91bd87aa 100644 --- a/docs/firebase-runtime-failure-backlog.md +++ b/docs/firebase-runtime-failure-backlog.md @@ -4,9 +4,7 @@ This backlog tracks binding drifts that are concrete candidates for the runtime- ## Ready -| Case id | Target/member | Audit finding reference | Expected runtime failure mechanism | Proof status | Fix PR | Merged commit | -| --- | --- | --- | --- | --- | --- | --- | -| `abtesting-validaterunningexperiments` | `Firebase.ABTesting.ExperimentController.ValidateRunningExperiments` | `output/firebase-binding-audit/report.json` -> `ABTesting` -> `ValidateRunningExperiments` (`signature-drift`) | The old binding exports `validateRunningExperimentsForServiceOrigin:runningExperimentPayloads:` as `NSObject[]` instead of `ABTExperimentPayload[]`, so callers can send arbitrary objects and native ABTesting immediately raises `ObjCRuntime.ObjCException` when it invokes `ABTExperimentPayload` selectors on those objects. | Proved locally on the unfixed binding. Evidence artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-validaterunningexperiments-failure.json`. Regression artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-validaterunningexperiments-success.json`. | - | - | +No runtime-failure candidates are currently promoted. ## Investigating @@ -17,5 +15,6 @@ No additional runtime-failure candidates are currently promoted. | Case id | Target/member | Audit finding reference | Runtime failure mechanism | Proof status | Fix PR | Merged commit | | --- | --- | --- | --- | --- | --- | --- | | `abtesting-activateexperiment` | `Firebase.ABTesting.ExperimentController.ActivateExperiment` | `output/firebase-binding-audit/report.json` -> `ABTesting` -> `ActivateExperiment` (`signature-drift`) | The old binding exported `activateExperiment:forServiceOrigin:` as `NSObject` instead of `ABTExperimentPayload`, so callers could send an arbitrary object and native ABTesting immediately raised `ObjCRuntime.ObjCException` when it invoked `ABTExperimentPayload` selectors on that object. | Proved and fixed. Evidence artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-activateexperiment-failure.json`. Regression artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-activateexperiment-success.json`. | [#114](https://github.com/AdamEssenmacher/GoogleApisForiOSComponents/pull/114) | `f77b1c57eff15cf6c1b5ca0df47d8195b46f0f40` | +| `abtesting-validaterunningexperiments` | `Firebase.ABTesting.ExperimentController.ValidateRunningExperiments` | `output/firebase-binding-audit/report.json` -> `ABTesting` -> `ValidateRunningExperiments` (`signature-drift`) | The old binding exported `validateRunningExperimentsForServiceOrigin:runningExperimentPayloads:` as `NSObject[]` instead of `ABTExperimentPayload[]`, so callers could send arbitrary objects and native ABTesting immediately raised `ObjCRuntime.ObjCException` when it invoked `ABTExperimentPayload` selectors on those objects. | Proved and fixed. Evidence artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-validaterunningexperiments-failure.json`. Regression artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-abtesting-validaterunningexperiments-success.json`. | [#115](https://github.com/AdamEssenmacher/GoogleApisForiOSComponents/pull/115) | `6973085307d474247b19639ef7fde074a3eece9f` | | `cloudfunctions-usefunctionsemulatororigin` | `Firebase.CloudFunctions.CloudFunctions.UseFunctionsEmulatorOrigin` | Manual runtime candidate from the current binding surface and native `FirebaseFunctions` Swift header | The binding exported `useFunctionsEmulatorOrigin:` even though the current framework only exposes `useEmulatorWithHost:port:`. Calling the stale selector raised `ObjCRuntime.ObjCException` with an unrecognized-selector native exception. | Proved and fixed. Evidence artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-cloudfunctions-usefunctionsemulatororigin-failure.json`. Regression artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-cloudfunctions-usefunctionsemulatororigin-success.json`. | [#113](https://github.com/AdamEssenmacher/GoogleApisForiOSComponents/pull/113) | `b6a6c82c74e0cf3645edb9dc5519d4a628f7ed36` | | `cloudfirestore-getquerynamed` | `Firebase.CloudFirestore.Firestore.GetQueryNamed` | `output/firebase-binding-audit/report.json` -> `CloudFirestore` -> `GetQueryNamed` (`signature-drift`) | The old binding exported `getQueryNamed:completion:` as `NSInputStream` instead of `NSString`, so native Firestore received `__NSCFInputStream` and threw an Objective-C exception when it treated the argument like a string. | Proved and fixed. Evidence artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-cloudfirestore-getquerynamed-failure.json`. Regression artifact: `tests/E2E/Firebase.Foundation/artifacts/firebase-foundation-result-cloudfirestore-getquerynamed-success.json`. | [#112](https://github.com/AdamEssenmacher/GoogleApisForiOSComponents/pull/112) | `3077a538a892de0db3350f0a459bf8620729f4db` | diff --git a/source/Firebase/Auth/Extension.cs b/source/Firebase/Auth/Extension.cs index ca22c54d..222b85ac 100644 --- a/source/Firebase/Auth/Extension.cs +++ b/source/Firebase/Auth/Extension.cs @@ -13,12 +13,12 @@ public static string CurrentVersion { throw new InvalidOperationException ("Unable to open the main program handle."); try { - IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "FirebaseAuthVersionStr"); + IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "FirebaseAuthVersionString"); if (ptr == IntPtr.Zero) - throw new InvalidOperationException ("Unable to resolve FirebaseAuthVersionStr."); + throw new InvalidOperationException ("Unable to resolve FirebaseAuthVersionString."); currentVersion = Marshal.PtrToStringAnsi (ptr) - ?? throw new InvalidOperationException ("Unable to read FirebaseAuthVersionStr."); + ?? throw new InvalidOperationException ("Unable to read FirebaseAuthVersionString."); } finally { Dlfcn.dlclose (RTLD_MAIN_ONLY); } diff --git a/source/Firebase/CloudFunctions/Extension.cs b/source/Firebase/CloudFunctions/Extension.cs index f9f44ca0..b21d5b85 100644 --- a/source/Firebase/CloudFunctions/Extension.cs +++ b/source/Firebase/CloudFunctions/Extension.cs @@ -12,12 +12,12 @@ public static string CurrentVersion { throw new InvalidOperationException ("Unable to open the main program handle."); try { - IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "FirebaseCloudFunctionsVersionStr"); + IntPtr ptr = Dlfcn.dlsym (RTLD_MAIN_ONLY, "FirebaseFunctionsVersionString"); if (ptr == IntPtr.Zero) - throw new InvalidOperationException ("Unable to resolve FirebaseCloudFunctionsVersionStr."); + throw new InvalidOperationException ("Unable to resolve FirebaseFunctionsVersionString."); currentVersion = Marshal.PtrToStringAnsi (ptr) - ?? throw new InvalidOperationException ("Unable to read FirebaseCloudFunctionsVersionStr."); + ?? throw new InvalidOperationException ("Unable to read FirebaseFunctionsVersionString."); } finally { Dlfcn.dlclose (RTLD_MAIN_ONLY); } From 844d311165a625216cb30c847b4c46fadf320859 Mon Sep 17 00:00:00 2001 From: Adam Essenmacher Date: Fri, 17 Apr 2026 23:30:40 -0400 Subject: [PATCH 2/2] Remove Firebase E2E workflow from symbol fix PR --- .github/workflows/firebase-e2e.yml | 64 ------------------------------ 1 file changed, 64 deletions(-) delete mode 100644 .github/workflows/firebase-e2e.yml diff --git a/.github/workflows/firebase-e2e.yml b/.github/workflows/firebase-e2e.yml deleted file mode 100644 index 751df1c5..00000000 --- a/.github/workflows/firebase-e2e.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Firebase E2E - -on: - pull_request: - push: - branches: - - main - workflow_dispatch: - -permissions: - contents: read - -jobs: - firebase-e2e: - runs-on: macos-15 - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Toolchain versions - run: | - xcodebuild -version - swift --version - xcode-select -p - - - name: Setup .NET SDK - uses: actions/setup-dotnet@v4 - with: - global-json-file: global.json - - - name: Restore .NET workloads - run: dotnet workload restore Xamarin.Google.sln - - - name: Install CocoaPods - run: | - if ! command -v pod >/dev/null 2>&1; then - sudo gem install cocoapods - fi - pod --version - - - name: Restore tools - run: dotnet tool restore - - - name: Build + pack Firebase Analytics slice - run: dotnet tool run dotnet-cake -- --target=nuget --names="Firebase.Analytics" - - - name: Build Mac Catalyst consumer app - run: | - dotnet build tests/E2E/Firebase.Foundation/FirebaseFoundationE2E/FirebaseFoundationE2E.csproj \ - --configuration Release \ - --framework net9.0-maccatalyst \ - --configfile tests/E2E/Firebase.Foundation/NuGet.config \ - -p:RuntimeIdentifier=maccatalyst-arm64 \ - -p:EnableCodeSigning=false - - - name: Run iOS simulator E2E smoke test - run: tools/e2e/run-firebase-foundation.sh --package-dir output --configuration Debug - - - name: Upload E2E artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: firebase-e2e-artifacts - path: tests/E2E/Firebase.Foundation/artifacts/**