Skip to content

feat(ci): Add iOS GitHub Actions workflows for automated builds and d…#3108

Closed
taymournajy wants to merge 1 commit intoopenMF:developmentfrom
taymournajy:feature/ios-github-actions-workflows
Closed

feat(ci): Add iOS GitHub Actions workflows for automated builds and d…#3108
taymournajy wants to merge 1 commit intoopenMF:developmentfrom
taymournajy:feature/ios-github-actions-workflows

Conversation

@taymournajy
Copy link
Copy Markdown

@taymournajy taymournajy commented Feb 10, 2026

…istribution

  • Add ios-build.yml workflow for development builds with Debug/Release configs
  • Add ios-release.yml workflow with Firebase, TestFlight, and App Store distribution
  • Add comprehensive README-iOS-Builds.md documentation
  • Add exportOptions.plist for IPA export configuration
  • Support manual dispatch and automated builds on push/PR
  • Include code signing setup for production releases

Fixes - Jira-#Issue_Number

Didn't create a Jira ticket, click here to create new.

Please Add Screenshots If there are any UI changes.

Before After

Please make sure these boxes are checked before submitting your pull request - thanks!

  • Run the static analysis check ./gradlew check or ci-prepush.sh to make sure you didn't break anything

  • If you have multiple commits please combine them into one commit by squashing them.

Summary by CodeRabbit

  • Documentation

    • Added comprehensive guide for iOS build workflows and setup instructions.
  • Chores

    • Implemented automated iOS build workflow with configurable debug and release options.
    • Implemented automated iOS release workflow supporting Firebase, TestFlight, and App Store distribution.
    • Added iOS export configuration for development builds.

…istribution

- Add ios-build.yml workflow for development builds with Debug/Release configs
- Add ios-release.yml workflow with Firebase, TestFlight, and App Store distribution
- Add comprehensive README-iOS-Builds.md documentation
- Add exportOptions.plist for IPA export configuration
- Support manual dispatch and automated builds on push/PR
- Include code signing setup for production releases
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

The PR adds iOS build infrastructure including two GitHub Actions workflows for development and release builds, comprehensive documentation outlining workflows and setup, and iOS export configuration settings. Total: 4 new files with 579 lines of changes.

Changes

Cohort / File(s) Summary
iOS Build & Release Workflows
.github/workflows/ios-build.yml, .github/workflows/ios-release.yml
New GitHub Actions workflows for building iOS apps on macOS runners. ios-build.yml supports debug/release configurations with optional IPA creation. ios-release.yml adds distribution methods (Firebase, TestFlight, AppStore) with conditional signing and Fastlane integration for release distribution.
iOS Build Documentation
.github/workflows/README-iOS-Builds.md
Comprehensive documentation detailing three iOS workflows, their triggers, configuration options, secrets requirements (code signing, Apple Developer, Firebase), quick-start guides, local development setup, troubleshooting, and workflow diagram.
iOS Export Configuration
cmp-ios/exportOptions.plist
New Xcode export configuration specifying development provisioning, disabling bitcode/symbol uploading, and enabling automatic signing for iOS builds.

Sequence Diagrams

sequenceDiagram
    participant GitHub as GitHub Actions
    participant macOS as macOS Runner
    participant Xcode as Xcode
    participant CocoaPods as CocoaPods
    participant Gradle as Gradle
    participant Artifact as Artifact Storage

    GitHub->>macOS: Trigger build workflow
    macOS->>macOS: Checkout code
    macOS->>Gradle: Setup JDK 21 & build<br/>shared KMP XCFramework
    Gradle-->>macOS: XCFramework ready
    macOS->>CocoaPods: Install dependencies
    CocoaPods-->>macOS: Pods installed
    macOS->>Xcode: Build iOS app<br/>(Debug/Release)
    Xcode-->>macOS: App binary created
    alt create_ipa = true
        macOS->>Xcode: Create & export IPA
        Xcode-->>Artifact: Upload IPA artifact
    end
    macOS->>GitHub: Post build summary
Loading
sequenceDiagram
    participant GitHub as GitHub Actions
    participant macOS as macOS Runner
    participant Xcode as Xcode
    participant Certs as Code Signing
    participant Fastlane as Fastlane
    participant Firebase as Firebase
    participant AppStore as App Store/TestFlight
    participant Artifact as Artifact Storage

    GitHub->>macOS: Trigger release workflow
    macOS->>macOS: Checkout & setup<br/>(JDK, Xcode, CocoaPods)
    alt distribution != firebase
        macOS->>Certs: Import signing certificates
        Certs-->>macOS: Certificates ready
    end
    macOS->>Fastlane: Install Fastlane
    macOS->>Xcode: Build & sign iOS app
    Xcode-->>macOS: Signed app ready
    
    alt distribution_method = firebase
        macOS->>Fastlane: Run Firebase lane
        Fastlane->>Firebase: Upload to Firebase
        Firebase-->>macOS: Distribution complete
    else distribution_method = testflight
        macOS->>Fastlane: Run TestFlight lane
        Fastlane->>AppStore: Upload to TestFlight
        AppStore-->>macOS: Upload complete
    else distribution_method = appstore
        macOS->>Fastlane: Run AppStore lane
        Fastlane->>AppStore: Submit to App Store
        AppStore-->>macOS: Submission complete
    end
    
    macOS->>Artifact: Upload IPA artifact
    macOS->>GitHub: Post distribution summary
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 New workflows hop into place,
iOS builds now set a faster pace,
Xcode, CocoaPods, Fastlane aligned,
From code to App Store, smoothly designed,
Our infrastructure stands—now iOS shines! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding iOS GitHub Actions workflows for automated builds and distribution, which is the core focus of all file additions in the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In @.github/workflows/ios-build.yml:
- Around line 31-40: The pull_request trigger's path filter is missing the
workflow file so PRs that only modify the workflow won't run; update the
pull_request block (the pull_request trigger and its paths array) to include
".github/workflows/ios-build.yml" alongside the other path entries so
workflow-only PRs will trigger the job.
- Around line 114-135: The Create IPA Archive step hardcodes -configuration
Release and disables code signing which conflicts with exportOptions.plist
(method=development); update the archive xcodebuild invocation to use the
user-selected configuration (replace -configuration Release with -configuration
${{ inputs.build_configuration }} or the equivalent BUILD_CONFIGURATION variable
used earlier) and align code signing flags with the export method (either enable
signing by setting CODE_SIGNING_ALLOWED=YES and supply
CODE_SIGN_IDENTITY/PROVISIONING_PROFILE variables when using method=development,
or change exportOptions.plist to a method that doesn't require signing); ensure
the same configuration and signing settings are used in both the earlier build
step and the archive/export steps so the IPA matches the chosen
build_configuration and the export will succeed.

In @.github/workflows/ios-release.yml:
- Around line 63-80: The workflow sets CERTIFICATES_P12 to the wrong secret (it
uses secrets.CERTIFICATES_PASSWORD) so the base64 P12 will be the password and
security import will fail; change the env mapping to set CERTIFICATES_P12 to the
base64 certificate secret (e.g., secrets.CERTIFICATES_P12) while keeping
CERTIFICATE_PASSWORD mapped to secrets.CERTIFICATES_PASSWORD, then ensure the
decode/import steps that use CERTIFICATES_P12 and the security import commands
(security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD"
...) remain unchanged; also update the README Required Secrets section to
document the CERTIFICATES_P12 secret as the base64-encoded distribution
certificate.
- Around line 41-57: Add a Gradle cache step immediately after the "Cache
CocoaPods" step to avoid re-downloading dependencies for the ./gradlew
:cmp-shared:assembleXCFramework run; use actions/cache@v4 targeting Gradle
folders (e.g., ~/.gradle/caches and ~/.gradle/wrapper) with a key like ${{
runner.os }}-gradle-${{ hashFiles('**/*.gradle*','**/gradle-wrapper.properties')
}} and a suitable restore-keys fallback so the Gradle wrapper and dependency
caches persist across macOS runs and speed up the gradle invocation in the
"Build KMP Shared Framework" step.
- Around line 122-131: The Distribution Summary step currently echoes `${{
inputs.release_notes }}` directly into the shell which is a script-injection
risk; change the job/step to map `inputs.release_notes` into an environment
variable (e.g., RELEASE_NOTES) and use that env var in the step instead of
interpolating the input directly; update the step that writes to
GITHUB_STEP_SUMMARY (the "Distribution Summary" step) to reference
$RELEASE_NOTES when echoing Release Notes and ensure the env var is declared in
the step's env block so GITHUB Actions passes the value safely.
- Around line 103-113: The "Distribute to Firebase" step uses the firebase CLI
and interpolates inputs.release_notes directly into the shell; add a preceding
step to install the CLI (e.g., run npm install -g firebase-tools) so the
firebase command is available, and change the distribute step to pass release
notes via an environment variable (e.g., set RELEASE_NOTES from
inputs.release_notes and use "$RELEASE_NOTES" in the script) to avoid shell
injection; keep existing env vars FIREBASE_APP_ID and FIREBASE_TOKEN and ensure
the install step runs before the firebase appdistribution:distribute invocation.

In `@cmp-ios/exportOptions.plist`:
- Around line 1-14: The exportOptions.plist currently forces method=development
and signingStyle=automatic while your CI sets CODE_SIGNING_ALLOWED=NO, which
will cause xcodebuild -exportArchive to fail when create_ipa is true; either
enable signing in the archive step or stop exporting an IPA for unsigned
archives. Fix by making the behavior conditional: when the pipeline flag
create_ipa is true and CODE_SIGNING_ALLOWED is not NO, keep <key>method</key>
value "development" and <key>signingStyle</key> "automatic" and ensure
provisioning is provided; otherwise, change the workflow to skip IPA export and
produce an unsigned .app (or remove/replace method/signingStyle from
exportOptions.plist) so xcodebuild -exportArchive is not invoked with an
unsigned archive. Ensure you update references to exportOptions.plist (method
and signingStyle) and the ios-build.yml create_ipa/CODE_SIGNING_ALLOWED logic
accordingly.
🧹 Nitpick comments (2)
.github/workflows/ios-build.yml (1)

50-80: Duplicate Gradle caching.

actions/setup-java with cache: 'gradle' (line 55) already caches Gradle dependencies. The separate Cache Gradle step (lines 72–80) is redundant. Pick one approach — using setup-java's built-in cache is simpler and sufficient. Note that ios-release.yml uses setup-java with cache: 'gradle' but has no separate Gradle cache step, so removing lines 72–80 would also improve consistency.

.github/workflows/README-iOS-Builds.md (1)

71-92: Add language specifiers to fenced code blocks.

Static analysis (markdownlint MD040) flags multiple fenced code blocks without a language identifier. Use ```text for plain-text blocks like secret lists and UI navigation paths (lines 71, 79, 89, 101, 121, 208).

Comment on lines +31 to +40
pull_request:
branches:
- development
- main
paths:
- 'cmp-ios/**'
- 'cmp-shared/**'
- 'core/**'
- 'feature/**'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

PR path filter missing the workflow file itself.

The push trigger (line 29) includes .github/workflows/ios-build.yml in its path filter, but the pull_request trigger (lines 36–39) does not. This means PRs that only modify this workflow file won't trigger it, making it impossible to test workflow changes via PR builds.

♻️ Proposed fix
     paths:
       - 'cmp-ios/**'
       - 'cmp-shared/**'
       - 'core/**'
       - 'feature/**'
+      - '.github/workflows/ios-build.yml'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pull_request:
branches:
- development
- main
paths:
- 'cmp-ios/**'
- 'cmp-shared/**'
- 'core/**'
- 'feature/**'
pull_request:
branches:
- development
- main
paths:
- 'cmp-ios/**'
- 'cmp-shared/**'
- 'core/**'
- 'feature/**'
- '.github/workflows/ios-build.yml'
🤖 Prompt for AI Agents
In @.github/workflows/ios-build.yml around lines 31 - 40, The pull_request
trigger's path filter is missing the workflow file so PRs that only modify the
workflow won't run; update the pull_request block (the pull_request trigger and
its paths array) to include ".github/workflows/ios-build.yml" alongside the
other path entries so workflow-only PRs will trigger the job.

Comment on lines +114 to +135
- name: Create IPA Archive
if: inputs.create_ipa == true
working-directory: cmp-ios
run: |
echo "Creating IPA archive..."

xcodebuild \
-workspace iosApp.xcworkspace \
-scheme iosApp \
-configuration Release \
-archivePath ./build/iosApp.xcarchive \
archive \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO

# Export archive to IPA
xcodebuild \
-exportArchive \
-archivePath ./build/iosApp.xcarchive \
-exportPath ./build/ipa \
-exportOptionsPlist ./exportOptions.plist
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

IPA archive hardcodes Release configuration, ignoring the user-selected build_configuration.

Line 123 hardcodes -configuration Release for the archive step, but the preceding build step (line 99) uses the user-selected configuration. If a user selects Debug and enables create_ipa, the app is built in Debug mode first, then archived again in Release mode — doubling the build time and producing an IPA that doesn't match the configuration they selected.

Additionally, as noted in the exportOptions.plist review, the archive is built without code signing (CODE_SIGNING_ALLOWED=NO) but the export step uses method=development which requires a signed archive — this will fail at export time.

♻️ Proposed fix for configuration consistency
           xcodebuild \
             -workspace iosApp.xcworkspace \
             -scheme iosApp \
-            -configuration Release \
+            -configuration ${{ inputs.build_configuration || 'Release' }} \
             -archivePath ./build/iosApp.xcarchive \
             archive \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Create IPA Archive
if: inputs.create_ipa == true
working-directory: cmp-ios
run: |
echo "Creating IPA archive..."
xcodebuild \
-workspace iosApp.xcworkspace \
-scheme iosApp \
-configuration Release \
-archivePath ./build/iosApp.xcarchive \
archive \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO
# Export archive to IPA
xcodebuild \
-exportArchive \
-archivePath ./build/iosApp.xcarchive \
-exportPath ./build/ipa \
-exportOptionsPlist ./exportOptions.plist
- name: Create IPA Archive
if: inputs.create_ipa == true
working-directory: cmp-ios
run: |
echo "Creating IPA archive..."
xcodebuild \
-workspace iosApp.xcworkspace \
-scheme iosApp \
-configuration ${{ inputs.build_configuration || 'Release' }} \
-archivePath ./build/iosApp.xcarchive \
archive \
CODE_SIGN_IDENTITY="" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO
# Export archive to IPA
xcodebuild \
-exportArchive \
-archivePath ./build/iosApp.xcarchive \
-exportPath ./build/ipa \
-exportOptionsPlist ./exportOptions.plist
🤖 Prompt for AI Agents
In @.github/workflows/ios-build.yml around lines 114 - 135, The Create IPA
Archive step hardcodes -configuration Release and disables code signing which
conflicts with exportOptions.plist (method=development); update the archive
xcodebuild invocation to use the user-selected configuration (replace
-configuration Release with -configuration ${{ inputs.build_configuration }} or
the equivalent BUILD_CONFIGURATION variable used earlier) and align code signing
flags with the export method (either enable signing by setting
CODE_SIGNING_ALLOWED=YES and supply CODE_SIGN_IDENTITY/PROVISIONING_PROFILE
variables when using method=development, or change exportOptions.plist to a
method that doesn't require signing); ensure the same configuration and signing
settings are used in both the earlier build step and the archive/export steps so
the IPA matches the chosen build_configuration and the export will succeed.

Comment on lines +41 to +57
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: |
cmp-ios/Pods
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-${{ hashFiles('cmp-ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build KMP Shared Framework
run: |
echo "Building shared framework for iOS..."
./gradlew :cmp-shared:assembleXCFramework
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Missing Gradle cache — adds unnecessary build time on macOS runners.

Unlike ios-build.yml which caches both CocoaPods and Gradle, this workflow only caches CocoaPods. The ./gradlew :cmp-shared:assembleXCFramework step (line 57) will re-download all Gradle dependencies on every run. macOS runners are more expensive, so caching matters here.

♻️ Proposed fix — add Gradle cache

Add after the CocoaPods cache step:

+      - name: Cache Gradle
+        uses: actions/cache@v4
+        with:
+          path: |
+            ~/.gradle/caches
+            ~/.gradle/wrapper
+          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
+          restore-keys: |
+            ${{ runner.os }}-gradle-
+
       - name: Grant execute permission for gradlew
         run: chmod +x gradlew
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: |
cmp-ios/Pods
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-${{ hashFiles('cmp-ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build KMP Shared Framework
run: |
echo "Building shared framework for iOS..."
./gradlew :cmp-shared:assembleXCFramework
- name: Cache CocoaPods
uses: actions/cache@v4
with:
path: |
cmp-ios/Pods
~/Library/Caches/CocoaPods
key: ${{ runner.os }}-pods-${{ hashFiles('cmp-ios/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build KMP Shared Framework
run: |
echo "Building shared framework for iOS..."
./gradlew :cmp-shared:assembleXCFramework
🤖 Prompt for AI Agents
In @.github/workflows/ios-release.yml around lines 41 - 57, Add a Gradle cache
step immediately after the "Cache CocoaPods" step to avoid re-downloading
dependencies for the ./gradlew :cmp-shared:assembleXCFramework run; use
actions/cache@v4 targeting Gradle folders (e.g., ~/.gradle/caches and
~/.gradle/wrapper) with a key like ${{ runner.os }}-gradle-${{
hashFiles('**/*.gradle*','**/gradle-wrapper.properties') }} and a suitable
restore-keys fallback so the Gradle wrapper and dependency caches persist across
macOS runs and speed up the gradle invocation in the "Build KMP Shared
Framework" step.

Comment on lines +63 to +80
- name: Import Code Signing Certificates
if: inputs.distribution_method != 'firebase'
env:
CERTIFICATES_P12: ${{ secrets.CERTIFICATES_PASSWORD }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# Create keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -t 3600 -u build.keychain

# Import certificate
echo "$CERTIFICATES_P12" | base64 --decode > certificate.p12
security import certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
rm certificate.p12
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

CERTIFICATES_P12 is mapped to the wrong secret — certificate import will fail.

Both CERTIFICATES_P12 (line 66) and CERTIFICATE_PASSWORD (line 67) reference secrets.CERTIFICATES_PASSWORD. The P12 environment variable should contain the base64-encoded certificate data, not the password. Line 77 decodes this value as a certificate file, which will produce an invalid .p12 and the security import will fail.

🐛 Proposed fix
       env:
-          CERTIFICATES_P12: ${{ secrets.CERTIFICATES_PASSWORD }}
+          CERTIFICATES_P12: ${{ secrets.CERTIFICATES_P12 }}
           CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATES_PASSWORD }}
           KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}

Also update the README's "Required Secrets" section to document the CERTIFICATES_P12 secret (the base64-encoded distribution certificate).

🤖 Prompt for AI Agents
In @.github/workflows/ios-release.yml around lines 63 - 80, The workflow sets
CERTIFICATES_P12 to the wrong secret (it uses secrets.CERTIFICATES_PASSWORD) so
the base64 P12 will be the password and security import will fail; change the
env mapping to set CERTIFICATES_P12 to the base64 certificate secret (e.g.,
secrets.CERTIFICATES_P12) while keeping CERTIFICATE_PASSWORD mapped to
secrets.CERTIFICATES_PASSWORD, then ensure the decode/import steps that use
CERTIFICATES_P12 and the security import commands (security import
certificate.p12 -k build.keychain -P "$CERTIFICATE_PASSWORD" ...) remain
unchanged; also update the README Required Secrets section to document the
CERTIFICATES_P12 secret as the base64-encoded distribution certificate.

Comment on lines +103 to +113
- name: Distribute to Firebase
if: inputs.distribution_method == 'firebase'
env:
FIREBASE_APP_ID: ${{ secrets.FIREBASE_IOS_APP_ID }}
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
run: |
firebase appdistribution:distribute \
cmp-ios/build/iosApp.ipa \
--app "$FIREBASE_APP_ID" \
--release-notes "${{ inputs.release_notes }}" \
--groups "mifos-mobile-apps"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Two issues: Firebase CLI not installed, and script injection risk via release_notes.

  1. Missing Firebase CLI installation: The firebase command (line 109) is used but never installed. Add a step to install it (e.g., npm install -g firebase-tools).

  2. Script injection via release_notes: On line 112, ${{ inputs.release_notes }} is directly interpolated into the shell script. Since this is a free-text input, a user could inject arbitrary shell commands. Use an environment variable instead.

🔒 Proposed fix

Add a Firebase CLI installation step before the distribute step:

+      - name: Install Firebase CLI
+        if: inputs.distribution_method == 'firebase'
+        run: npm install -g firebase-tools
+
       - name: Distribute to Firebase
         if: inputs.distribution_method == 'firebase'
         env:
           FIREBASE_APP_ID: ${{ secrets.FIREBASE_IOS_APP_ID }}
           FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
+          RELEASE_NOTES: ${{ inputs.release_notes }}
         run: |
           firebase appdistribution:distribute \
             cmp-ios/build/iosApp.ipa \
             --app "$FIREBASE_APP_ID" \
-            --release-notes "${{ inputs.release_notes }}" \
+            --release-notes "$RELEASE_NOTES" \
             --groups "mifos-mobile-apps"
🤖 Prompt for AI Agents
In @.github/workflows/ios-release.yml around lines 103 - 113, The "Distribute to
Firebase" step uses the firebase CLI and interpolates inputs.release_notes
directly into the shell; add a preceding step to install the CLI (e.g., run npm
install -g firebase-tools) so the firebase command is available, and change the
distribute step to pass release notes via an environment variable (e.g., set
RELEASE_NOTES from inputs.release_notes and use "$RELEASE_NOTES" in the script)
to avoid shell injection; keep existing env vars FIREBASE_APP_ID and
FIREBASE_TOKEN and ensure the install step runs before the firebase
appdistribution:distribute invocation.

Comment on lines +122 to +131
- name: Distribution Summary
if: success()
run: |
echo "### ✅ iOS Release Build Successful!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Distribution Method:** ${{ inputs.distribution_method }}" >> $GITHUB_STEP_SUMMARY
echo "**Configuration:** Release" >> $GITHUB_STEP_SUMMARY
echo "**Build Number:** #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Release Notes:** ${{ inputs.release_notes }}" >> $GITHUB_STEP_SUMMARY
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

release_notes should also use an env var in the summary step.

Line 131 directly interpolates ${{ inputs.release_notes }} into the shell script. While the risk here (writing to $GITHUB_STEP_SUMMARY) is lower than in the Firebase distribute step, it's still a script injection vector. For consistency and defense-in-depth, use an environment variable here as well.

🛡️ Proposed fix
       - name: Distribution Summary
         if: success()
+        env:
+          RELEASE_NOTES: ${{ inputs.release_notes }}
         run: |
           echo "### ✅ iOS Release Build Successful!" >> $GITHUB_STEP_SUMMARY
           echo "" >> $GITHUB_STEP_SUMMARY
           echo "**Distribution Method:** ${{ inputs.distribution_method }}" >> $GITHUB_STEP_SUMMARY
           echo "**Configuration:** Release" >> $GITHUB_STEP_SUMMARY
           echo "**Build Number:** #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY
           echo "" >> $GITHUB_STEP_SUMMARY
-          echo "**Release Notes:** ${{ inputs.release_notes }}" >> $GITHUB_STEP_SUMMARY
+          echo "**Release Notes:** $RELEASE_NOTES" >> $GITHUB_STEP_SUMMARY
🤖 Prompt for AI Agents
In @.github/workflows/ios-release.yml around lines 122 - 131, The Distribution
Summary step currently echoes `${{ inputs.release_notes }}` directly into the
shell which is a script-injection risk; change the job/step to map
`inputs.release_notes` into an environment variable (e.g., RELEASE_NOTES) and
use that env var in the step instead of interpolating the input directly; update
the step that writes to GITHUB_STEP_SUMMARY (the "Distribution Summary" step) to
reference $RELEASE_NOTES when echoing Release Notes and ensure the env var is
declared in the step's env block so GITHUB Actions passes the value safely.

Comment on lines +1 to +14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>development</string>
<key>compileBitcode</key>
<false/>
<key>uploadSymbols</key>
<false/>
<key>signingStyle</key>
<string>automatic</string>
</dict>
</plist>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unsigned archive + method=development export will likely fail.

In ios-build.yml (lines 120–135), the archive is created with CODE_SIGNING_ALLOWED=NO, but this plist specifies method=development with signingStyle=automatic. The xcodebuild -exportArchive step requires a signed archive when method is set to development—it needs a valid provisioning profile to produce the IPA. Since the archive is unsigned, the export will fail with a signing error.

Either:

  1. Sign the archive properly when create_ipa is true (provide provisioning for dev builds), or
  2. Change the approach to produce a .app bundle instead of an IPA for unsigned dev builds.
🤖 Prompt for AI Agents
In `@cmp-ios/exportOptions.plist` around lines 1 - 14, The exportOptions.plist
currently forces method=development and signingStyle=automatic while your CI
sets CODE_SIGNING_ALLOWED=NO, which will cause xcodebuild -exportArchive to fail
when create_ipa is true; either enable signing in the archive step or stop
exporting an IPA for unsigned archives. Fix by making the behavior conditional:
when the pipeline flag create_ipa is true and CODE_SIGNING_ALLOWED is not NO,
keep <key>method</key> value "development" and <key>signingStyle</key>
"automatic" and ensure provisioning is provided; otherwise, change the workflow
to skip IPA export and produce an unsigned .app (or remove/replace
method/signingStyle from exportOptions.plist) so xcodebuild -exportArchive is
not invoked with an unsigned archive. Ensure you update references to
exportOptions.plist (method and signingStyle) and the ios-build.yml
create_ipa/CODE_SIGNING_ALLOWED logic accordingly.

@niyajali
Copy link
Copy Markdown
Collaborator

niyajali commented Mar 5, 2026

Closing this on behalf of #3122

@niyajali niyajali closed this Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants