Skip to content

Commit d3ea8c5

Browse files
Enhance: Add SSH support to Firebase iOS publish action (#4)
1 parent 848de26 commit d3ea8c5

File tree

2 files changed

+180
-16
lines changed

2 files changed

+180
-16
lines changed

README.md

Lines changed: 114 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This GitHub Action automates the process of building and publishing iOS applicat
99
- Build artifact archiving
1010
- Gradle and Ruby dependency caching
1111
- Firebase tester group management
12+
- SSH key authentication via base64 secrets
1213

1314
## Prerequisites
1415

@@ -18,9 +19,61 @@ Before using this action, ensure you have:
1819
2. Firebase service account credentials
1920
3. An iOS app set up in Firebase
2021
4. Xcode project configured with proper signing
22+
5. A private GitHub repo with certificates and provisioning profiles for Fastlane Match
23+
6. SSH key added as a deploy key to the certificates repo
2124

2225
## Setup
2326

27+
### SSH Key Setup
28+
1. Generate SSH Key Locally<br>
29+
In your terminal, run:
30+
```yaml
31+
ssh-keygen -t ed25519 -C "your_email@example.com"
32+
```
33+
It will ask for a file path. Press enter a custom path like:
34+
```yaml
35+
~/.ssh/match_ci_key
36+
```
37+
You can skip setting a passphrase when prompted (just hit enter twice).
38+
39+
This generates two files:
40+
41+
- `~/.ssh/match_ci_key` → Private key
42+
43+
- `~/.ssh/match_ci_key.pub` → Public key
44+
45+
2. Add the Private Key to the SSH Agent (optional but helpful)
46+
This step ensures the key is used during local development.
47+
```yaml
48+
eval "$(ssh-agent -s)"
49+
ssh-add ~/.ssh/match_ci_key
50+
```
51+
3. Add the Public Key to Your Certificates Repo (GitHub)
52+
- Go to your certificates repo on GitHub (e.g., openMF/ios-provisioning-profile).
53+
- Go to Settings → Deploy Keys.
54+
- Click “Add deploy key”.
55+
- Set title as `CI Match SSH Key` and paste the content of:
56+
57+
```yaml
58+
cat ~/.ssh/match_ci_key.pub
59+
```
60+
- Check **Allow write access**.
61+
- Click Add key.
62+
63+
4. Convert the Private Key to Base64
64+
This is how we pass it to GitHub Actions securely.
65+
```yaml
66+
base64 -i ~/.ssh/match_ci_key | pbcopy
67+
```
68+
This command copies the base64-encoded private key to your clipboard (macOS).
69+
70+
5. Save the Private Key as a GitHub Secret
71+
- Go to the repo with your Fastfile (the project repo, not the certs repo).
72+
- Navigate to Settings → Secrets and variables → Actions → New repository secret.
73+
- Add the following:
74+
- Name: MATCH_SSH_PRIVATE_KEY
75+
- Value: Paste the base64-encoded private key
76+
2477
### Fastlane Setup
2578

2679
Create a `Gemfile` in your project root:
@@ -40,16 +93,56 @@ default_platform(:ios)
4093
platform :ios do
4194
desc "Deploy to Firebase App Distribution"
4295
lane :deploy_on_firebase do |options|
96+
97+
firebase_app_id = options[:firebase_app_id] || ENV["FIREBASE_APP_ID"]
98+
match_type = options[:match_type] || ENV["MATCH_TYPE"]
99+
app_identifier = options[:app_identifier] || ENV["APP_IDENTIFIER"]
100+
git_url = options[:git_url] || ENV["GIT_URL"]
101+
git_branch = options[:git_branch] || ENV["GIT_BRANCH"]
102+
match_password = options[:match_password] || ENV["MATCH_PASSWORD"]
103+
git_private_key = options[:git_private_key] || ENV["GIT_PRIVATE_KEY"] || "./secrets/match_ci_key"
104+
groups = options[:groups] || ENV["GROUPS"]
105+
serviceCredsFile = options[:serviceCredsFile] || ENV["SERVICE_CREDS_FILE"]
106+
107+
setup_ci(
108+
provider: "circleci"
109+
)
110+
111+
latest_release = firebase_app_distribution_get_latest_release(
112+
app: firebase_app_id,
113+
service_credentials_file: options[:serviceCredsFile] || firebase_config[:serviceCredsFile]
114+
)
115+
116+
if latest_release
117+
increment_build_number(
118+
xcodeproj: iosApp/iosApp.xcodeproj,
119+
build_number: latest_release[:buildVersion].to_i + 1
120+
)
121+
else
122+
UI.important("⚠️ No existing Firebase release found. Skipping build number increment.")
123+
end
124+
125+
match(
126+
type: match_type,
127+
app_identifier: app_identifier,,
128+
readonly: true,
129+
git_url: git_url,
130+
git_branch: git_branch,
131+
git_private_key: git_private_key
132+
)
133+
43134
build_ios_app(
44-
scheme: ENV["IOS_PACKAGE_NAME"],
45-
export_method: "ad-hoc"
135+
scheme: "iosApp",
136+
project: "iosApp/iosApp.xcodeproj",
137+
output_name: "DeployIosApp.ipa",
138+
output_directory: "iosApp/build",
46139
)
47140

48141
firebase_app_distribution(
49-
app: ENV["FIREBASE_APP_ID"],
50-
groups: options[:groups],
51-
service_credentials_file: options[:serviceCredsFile],
52-
release_notes: "New build from GitHub Actions"
142+
app: firebase_app_id,
143+
service_credentials_file: serviceCredsFile,
144+
release_notes: r"New build from GitHub Actions",
145+
groups: groups
53146
)
54147
end
55148
end
@@ -78,18 +171,28 @@ jobs:
78171
- name: Deploy to Firebase
79172
uses: openMF/kmp-publish-ios-on-firebase-action@v1.0.0
80173
with:
81-
ios_package_name: 'YourAppName'
82-
firebase_creds: ${{ secrets.FIREBASE_CREDS }}
83-
tester_groups: 'qa-team,beta-testers'
174+
app_identifier: 'org.mifos.kmp.template'
175+
git_url: 'git@github.com:openMF/ios-provisioning-profile.git'
176+
git_branch: 'master'
177+
match_type: 'adhoc'
178+
provisioning_profile_name: 'match AdHoc org.mifos.kmp.template'
179+
match_password: ${{ secrets.MATCH_PASSWORD }}
180+
match_ssh_private_key: ${{ secrets.MATCH_SSH_PRIVATE_KEY }}
181+
ios_package_name: 'YourAppName'
182+
firebase_creds: ${{ secrets.FIREBASE_CREDS }}
183+
firebase_app_id: '1:xxxx:ios:xxxxxxxx'
184+
tester_groups: 'qa-team,beta-testers'
84185
```
85186
86-
## Inputs
187+
## Inputs and Secrets
87188
88189
| Input | Description | Required |
89190
|--------------------|-----------------------------------------------------|----------|
90191
| `ios_package_name` | Name of your iOS app/scheme | Yes |
91192
| `firebase_creds` | Base64 encoded Firebase service account credentials | Yes |
92193
| `tester_groups` | Comma-separated list of Firebase tester groups | Yes |
194+
| `MATCH_PASSWORD` | Used to encrypt/decrypt match certs | Yes |
195+
| `MATCH_SSH_PRIVATE_KEY` | base64 encoded private SSH key used by Fastlane Match | Yes |
93196

94197
## Setting up Secrets
95198

@@ -132,4 +235,4 @@ Common issues and solutions:
132235
2. Firebase deployment fails
133236
- Check if the service account has sufficient permissions
134237
- Verify the Firebase app ID is correct
135-
- Ensure tester groups exist in Firebase console
238+
- Ensure tester groups exist in Firebase console

action.yaml

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,46 @@ branding:
66
color: 'blue'
77

88
inputs:
9+
app_identifier:
10+
required: true
11+
description: 'The unique bundle identifier for the iOS application'
12+
13+
git_url:
14+
required: true
15+
description: 'Git URL to the private repository containing certificates and provisioning profiles for code signing (used by Fastlane Match)'
16+
17+
git_branch:
18+
required: true
19+
description: 'Branch name inside the certificates repository that Fastlane Match should use to fetch signing assets'
20+
21+
match_type:
22+
required: true
23+
description: 'Type of provisioning profile to fetch using Match (e.g., adhoc, appstore, development)'
24+
25+
provisioning_profile_name:
26+
required: true
27+
description: 'Name of the provisioning profile to use for code signing (e.g., match AdHoc com.example.app or match AppStore com.example.app)'
28+
29+
match_password:
30+
required: true
31+
description: 'Password used to encrypt/decrypt the certificates repository used by match'
32+
33+
match_ssh_private_key:
34+
required: true
35+
description: 'SSH private key for accessing the certificates repository'
36+
937
ios_package_name:
1038
description: 'Name of the Android project module'
1139
required: true
40+
41+
firebase_app_id:
42+
description: 'Firebase App ID'
43+
required: true
44+
1245
firebase_creds:
1346
description: 'Firebase credentials'
1447
required: true
48+
1549
tester_groups:
1650
description: 'Firebase Tester Group'
1751
required: true
@@ -42,28 +76,55 @@ runs:
4276
bundle exec fastlane add_plugin firebase_app_distribution
4377
bundle exec fastlane add_plugin increment_build_number
4478
79+
- name: Set up SSH for Match
80+
shell: bash
81+
env:
82+
MATCH_SSH_PRIVATE_KEY: ${{ inputs.match_ssh_private_key }}
83+
run: |
84+
mkdir -p ~/.ssh
85+
echo "$MATCH_SSH_PRIVATE_KEY" | base64 --decode > ~/.ssh/match_ci_key
86+
chmod 600 ~/.ssh/match_ci_key
87+
ssh-keyscan github.com >> ~/.ssh/known_hosts
88+
echo -e "Host github.com\n IdentityFile ~/.ssh/match_ci_key\n StrictHostKeyChecking no" >> ~/.ssh/config
89+
90+
# Inflate Firebase credentials
4591
- name: Inflate Secrets
4692
shell: bash
4793
env:
48-
GOOGLE_SERVICES: ${{ inputs.google_services }}
4994
FIREBASE_CREDS: ${{ inputs.firebase_creds }}
5095
run: |
5196
mkdir -p secrets
52-
53-
# Inflate Firebase credentials
5497
touch secrets/firebaseAppDistributionServiceCredentialsFile.json
5598
echo $FIREBASE_CREDS | base64 --decode > secrets/firebaseAppDistributionServiceCredentialsFile.json
5699
57100
- name: Upload iOS App to Firebase Distribution
58101
shell: bash
102+
env:
103+
APP_IDENTIFIER: ${{ inputs.app_identifier }}
104+
GIT_URL: ${{ inputs.git_url }}
105+
GIT_BRANCH: ${{ inputs.git_branch }}
106+
MATCH_TYPE: ${{ inputs.match_type }}
107+
PROVISIONING_PROFILE_NAME: ${{ inputs.provisioning_profile_name }}
108+
MATCH_PASSWORD: ${{ inputs.match_password }}
109+
FIREBASE_APP_ID: ${{ inputs.firebase_app_id }}
110+
GROUPS: ${{ inputs.tester_groups }}
111+
59112
run: bundle exec fastlane ios deploy_on_firebase \
113+
app_identifier:"$APP_IDENTIFIER" \
114+
git_url:"$GIT_URL" \
115+
git_branch:"$GIT_BRANCH" \
116+
match_type:"$MATCH_TYPE" \
117+
provisioning_profile_name:"$PROVISIONING_PROFILE_NAME" \
118+
match_password:"$MATCH_PASSWORD" \
119+
git_private_key:~/.ssh/match_ci_key \
120+
firebase_app_id:"$FIREBASE_APP_ID" \
60121
serviceCredsFile:secrets/firebaseAppDistributionServiceCredentialsFile.json \
61-
groups:${{ inputs.tester_groups }}
122+
groups:"$GROUPS"
62123

63124
- name: Upload iOS Artifact
64125
uses: actions/upload-artifact@v4
65126
with:
66127
name: ios-app
67128
retention-days: 1
68129
compression-level: 9
69-
path: '**/*.ipa'
130+
path: '**/*.ipa'

0 commit comments

Comments
 (0)