EAS CI fails due to gitignore pattern preventing upload of bundle

The Context

Working on a React Native Expo project which uses the EAS build tools for CI whilst also using a custom native module for Mapbox turn-by-turn navigation which is not supported by the Expo Go app out of the box.
We have a /plugins/mapboxNavigation folder in our root directory which stores our plugin which can be installed in the EAS build process. Inside this we have android/ and ios/ directories for the native plugins.
We have an index.js file inside the plugin which dangerously alters the Gradle/Podfiles during the prebuild step to inject the native dependencies we require.

The Problem

Our CI started failing at the prebuild step after needing a new native build.
notion image
For iOS: [stderr] Error: [ios.xcodeproj]: withIosXcodeprojBaseMod: ENOENT: no such file or directory, open '/Users/expo/workingdir/build/plugins/mapboxNavigation/ios/MapboxNavigationManager.swift'
For Android:
[stderr] Error: [android.dangerous]: withAndroidDangerousBaseMod: ENOENT: no such file or directory, open '/home/expo/workingdir/build/plugins/mapboxNavigation/android/NavigationViewActivity.java'
withIosXcodeprojBaseMod and withAndroidDangerousBaseMod were being called from withDangerousMod from '@expo/config-plugins'. So our index.js which was injecting the native dependencies was throwing an error.

The Solution

We reran the build with a clear cache - but the error was the same:
notion image
We checked the git history between the last commit that built successfully, but couldn’t find any changes to index.js.
We tried reproducing locally, by running the exact command run in the CI: node_modules/.bin/expo prebuild --no-install --platform android but this succeeded.
This, plus the no such file or directory error, suggested that our directory structure was different to the one remotely. It would have helped if there was an SSH agent we could have attached to investigate the local files of the machine.
Interestingly, checking out to the last commit where a remote build succeeded and running npx eas build again failed. I would have expected this to succeed (as we’re running on identical code).
notion image
Interestingly, the prebuild step is skipped here (whereas in the last succeeding run it was not skipped) with the message: Skipped running "expo prebuild" because the "android" directory already exists. Learn more about the build process: https://docs.expo.dev/build-reference/android-builds/.
The Run gradlew step fails and as I inspect the error I see that it fails with some compilation errors which has some local code I’m working on inside the /android directory. I wasn’t expecting the CI to have any access to my local code.
This suggested to me that something was happening with the upload process that I didn’t understand which meant that files I didn’t expect to be sent to EAS were.
The answer was explained to me after I read these docs!
It turns out that the upload process that happens in eas build respects the .gitignore file. This prevents any secrets in the .env file being uploaded for example (makes sense!).
Each build creates an /android and /ios folder that we never want to commit to source control - because it’s generated code. Since the last build, these directories had been added to the .gitignore to prevent them ever being committed accidentally, however the pattern that was used actually excluded all directories named android or ios. This meant that during the upload phase, /plugins/mapboxNavigation/android and /plugins/mapboxNavigation/ios were both excluded from the upload, which explains why we get the error no such file or directory!

The Code

// .gitignore causing the error // ignores all files in directories call 'android' or 'ios' android/ ios/
// .gitignore fixed // only ignores 'android'|'ios' directories in the project root /android/ /ios/