Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions .github/workflows/circuits.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
name: Circuits CI
on:
push:
branches:
- dev
- main
- openpassportv2
paths:
- "circuits/**"
- "common/**"
pull_request:
branches:
- dev
- staging
- main
- openpassportv2
paths:
- "circuits/**"
- "common/**"
jobs:
Comment on lines 8 to 10
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Path filter may miss changes in shared code used by circuits

This workflow only triggers on changes under circuits/. If circuits depend on code in common/ (typical in monorepos), changes there won’t run circuit tests. That’s a blind spot that can let breaking changes slip through.

Consider adding common/** back to the paths, or split the job condition with a more precise dependency map. Example:

 on:
   pull_request:
     branches:
       - dev
       - staging
       - main
     paths:
-      - "circuits/**"
+      - "circuits/**"
+      - "common/**"

If dependency is unidirectional and truly isolated now, ignore this; otherwise, I recommend restoring the coverage.


🏁 Script executed:

#!/bin/bash
# List top-level directories to check for a shared “common” folder
echo "Top-level directories:"
ls -1

# Verify if common/ exists
if [ -d common ]; then
  echo "common/ directory exists"
else
  echo "common/ directory does not exist"
fi

# Search circuits/ for imports that reference common/ via relative paths
echo -e "\nSearching for relative imports from common in circuits/:"
rg -nP --type ts --type tsx "from ['\"](?:\.\.\/)+common" -C3 circuits || echo "No relative TS/TSX imports from common found"
rg -nP --type js --type jsx "from ['\"](?:\.\.\/)+common" -C3 circuits || echo "No relative JS/JSX imports from common found"

# Search circuits/ for path-alias imports (e.g. '@common/...')
echo -e "\nSearching for alias imports from common in circuits/:"
rg -nP "from ['\"][\@]?common" -C3 circuits || echo "No alias imports from common found"

Length of output: 1105


🏁 Script executed:

#!/bin/bash
# Thoroughly search for any reference to "common" within circuits/
echo "Searching for literal 'common/' references in circuits/:"
rg -n "common/" -C3 circuits || echo "No literal 'common/' references found in circuits"

echo -e "\nSearching for ES module imports referencing 'common':"
rg -n "import .* from ['\"].*common" -C3 circuits || echo "No ES module imports referencing 'common' found in circuits"

echo -e "\nSearching for CommonJS requires referencing 'common':"
rg -n "require\s*\(['\"].*common" -C3 circuits || echo "No CommonJS require() calls referencing 'common' found in circuits"

Length of output: 32539


CI trigger must include shared common/

The circuits workflow is currently scoped to changes under circuits/**, but the circuits tests import and rely on code from common/** (e.g., path aliases in circuits/tsconfig.spec.json and numerous @selfxyz/common/... imports in the test files). Without adding common/** to the paths filter, updates to shared utilities won’t trigger the circuits job, risking undetected breaking changes.

Changes required:

• In .github/workflows/circuits.yml, update the paths section:

 on:
   pull_request:
     branches:
       - dev
       - staging
       - main
     paths:
-      - "circuits/**"
+      - "circuits/**"
+      - "common/**"

This ensures any edits to the shared common code will rerun the circuits tests.

📝 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
paths:
- "circuits/**"
- "common/**"
jobs:
on:
pull_request:
branches:
- dev
- staging
- main
paths:
- "circuits/**"
- "common/**"
jobs:
#
🤖 Prompt for AI Agents
In .github/workflows/circuits.yml around lines 8 to 10 the paths filter only
includes "circuits/**" which means changes to shared code under common/** won’t
trigger the circuits workflow; update the paths list to include "common/**"
alongside "circuits/**" so that edits to the shared utilities will run the
circuits CI job (i.e., add an entry "common/**" under the paths key).

run_circuit_tests:
if: github.event.pull_request.draft == false
Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/contracts.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
name: Contracts CI
on:
push:
branches:
- dev
- main
paths:
- "contracts/**"
- "common/**"
pull_request:
branches:
- dev
- staging
- main
paths:
- "contracts/**"
Expand Down
183 changes: 97 additions & 86 deletions .github/workflows/mobile-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ env:
permissions:
contents: write
pull-requests: write
id-token: write
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Scope OIDC permissions to least privilege

id-token: write is set at the workflow level, granting all jobs the ability to request OIDC tokens. Only the iOS job uses Google Workload Identity. Move this permission to the iOS job to reduce blast radius.

Apply this diff to remove the top-level grant:

 permissions:
   contents: write
   pull-requests: write
-  id-token: write

Then add job-scoped permissions under build-ios:

# under jobs.build-ios:
permissions:
  contents: write
  pull-requests: write
  id-token: write
🤖 Prompt for AI Agents
.github/workflows/mobile-deploy.yml around line 33: the workflow grants
id-token: write at the top-level which should be scoped to the iOS job only;
remove the top-level id-token: write entry and add job-scoped permissions under
jobs.build-ios instead, setting permissions to include contents: write,
pull-requests: write, and id-token: write so only the iOS job can request OIDC
tokens.


on:
workflow_dispatch:
Expand Down Expand Up @@ -116,6 +117,8 @@ jobs:
echo "NODE_VERSION=$VERSION" >> "$GITHUB_ENV"
echo "NODE_VERSION_SANITIZED=${VERSION//\//-}" >> "$GITHUB_ENV"



- name: Set up Xcode
if: inputs.platform != 'android'
uses: maxim-lobanov/setup-xcode@v1
Expand Down Expand Up @@ -520,12 +523,17 @@ jobs:
with:
app_path: ${{ env.APP_PATH }}

- name: Commit updated build number
- name: Open PR for iOS build number bump
if: ${{ !env.ACT && success() }}
uses: ./.github/actions/push-changes
uses: peter-evans/create-pull-request@v6
with:
commit_message: "incrementing ios build number for version ${{ env.VERSION }}"
commit_paths: "./app/version.json"
title: "chore: bump iOS build for ${{ env.VERSION }}"
body: "Automated bump of iOS build number by CI"
commit-message: "chore: incrementing ios build number for version ${{ env.VERSION }} [github action]"
branch: ci/bump-ios-build-${{ github.run_id }}
base: staging
add-paths: |
app/version.json

- name: Monitor cache usage
if: always()
Expand Down Expand Up @@ -564,6 +572,68 @@ jobs:

- uses: actions/checkout@v4
if: inputs.platform != 'ios'
- uses: 'google-github-actions/auth@v2'
with:
project_id: 'plucky-tempo-454713-r0'
workload_identity_provider: 'projects/852920390127/locations/global/workloadIdentityPools/gh-self/providers/github-by-repos'
service_account: "[email protected]"
# Fail fast: set up JDK for keytool and verify Android secrets early
Comment on lines +575 to +580
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Pin third‑party actions to immutable SHAs; optionally set OIDC audience

Supply-chain hardening: avoid floating tags for third‑party actions. Pin to the release commit SHAs for reproducibility and tamper resistance. For OIDC, consider setting audience: if a relying party validates aud.

Pin these occurrences (replace PLACEHOLDER_SHA with the official release commit SHAs):

-      - uses: 'google-github-actions/auth@v2'
+      - uses: google-github-actions/auth@PLACEHOLDER_SHA
         with:
           project_id: 'plucky-tempo-454713-r0'
           workload_identity_provider: 'projects/852920390127/locations/global/workloadIdentityPools/gh-self/providers/github-by-repos'
           service_account: "[email protected]"
+          # audience: 'https://sts.googleapis.com' # optional, if enforced downstream
-        uses: peter-evans/create-pull-request@v6
+        uses: peter-evans/create-pull-request@PLACEHOLDER_SHA

(repeat for lines 796-806 and 898-912)

-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@PLACEHOLDER_SHA
-        uses: android-actions/setup-android@v3
+        uses: android-actions/setup-android@PLACEHOLDER_SHA
-        uses: maxim-lobanov/setup-xcode@v1
+        uses: maxim-lobanov/setup-xcode@PLACEHOLDER_SHA

Note: You can keep GitHub-maintained actions (e.g., actions/checkout, actions/cache, actions/setup-node, actions/setup-java) on major tags if your policy allows, but pinning them too is even stronger. If you want, I can prepare a patch with the exact SHAs you’re targeting.

Also applies to: 526-536, 796-806, 898-912, 1000-1008, 712-716, 122-127

🤖 Prompt for AI Agents
.github/workflows/mobile-deploy.yml lines 575-580: the workflow uses
google-github-actions/auth@v2 with a floating tag—pin the action to its
immutable release commit SHA (replace the tag with the corresponding commit SHA
for that release) and optionally add an audience: field under with: if your OIDC
relying party checks aud; apply the same change to the other occurrences listed
(lines 122-127, 526-536, 712-716, 796-806, 898-912, 1000-1008) to harden the
supply chain and ensure reproducible deployments.

- name: Setup Java environment
if: inputs.platform != 'ios'
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: ${{ env.JAVA_VERSION }}

- name: Decode Android Secrets
if: inputs.platform != 'ios'
run: |
echo "${{ secrets.ANDROID_KEYSTORE }}" | base64 --decode > ${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}

- name: Verify Android Secrets
if: inputs.platform != 'ios'
run: |
# Verify Google Cloud auth via Workload Identity Federation (ADC)
if [ -z "$GOOGLE_APPLICATION_CREDENTIALS" ] || [ ! -f "$GOOGLE_APPLICATION_CREDENTIALS" ]; then
echo "❌ Error: GOOGLE_APPLICATION_CREDENTIALS not set or file missing. Ensure google-github-actions/auth ran."
exit 1
fi
# Verify keystore file exists and is valid
if [ ! -f "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" ]; then
echo "❌ Error: Keystore file was not created successfully"
exit 1
fi
# Try to verify the keystore with the provided password
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" >/dev/null 2>&1; then
echo "❌ Error: Invalid keystore password"
exit 1
fi
# Verify the key alias exists
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" -alias "${{ secrets.ANDROID_KEY_ALIAS }}" >/dev/null 2>&1; then
echo "❌ Error: Key alias '${{ secrets.ANDROID_KEY_ALIAS }}' not found in keystore"
exit 1
fi
# Verify the key password
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" -alias "${{ secrets.ANDROID_KEY_ALIAS }}" -keypass "${{ secrets.ANDROID_KEY_PASSWORD }}" >/dev/null 2>&1; then
echo "❌ Error: Invalid key password"
exit 1
fi

# Detect keystore type and export for later steps
KEYSTORE_TYPE=$(keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" 2>/dev/null | awk -F': ' '/Keystore type:/ {print $2; exit}')
if [ -z "$KEYSTORE_TYPE" ]; then
echo "❌ Error: Unable to determine keystore type"
exit 1
fi
echo "ANDROID_KEYSTORE_TYPE=$KEYSTORE_TYPE" >> "$GITHUB_ENV"
echo "Detected keystore type: $KEYSTORE_TYPE"

# Ensure the alias holds a PrivateKeyEntry (required for signing)
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" -alias "${{ secrets.ANDROID_KEY_ALIAS }}" -keypass "${{ secrets.ANDROID_KEY_PASSWORD }}" | grep -q "Entry type: PrivateKeyEntry"; then
echo "❌ Error: Alias '${{ secrets.ANDROID_KEY_ALIAS }}' is not a PrivateKeyEntry"
exit 1
fi
echo "✅ All Android secrets verified successfully!"
- name: Read and sanitize Node.js version
shell: bash
run: |
Expand Down Expand Up @@ -652,12 +722,6 @@ jobs:
workspace: ${{ env.WORKSPACE }}

# android specific steps
- name: Setup Java environment
if: inputs.platform != 'ios'
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: ${{ env.JAVA_VERSION }}

- name: Setup Android SDK
if: inputs.platform != 'ios'
Expand Down Expand Up @@ -693,47 +757,7 @@ jobs:
run: |
echo "org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8" >> ${{ env.APP_PATH }}/android/gradle.properties

- name: Decode Android Secrets
if: inputs.platform != 'ios'
run: |
echo "${{ secrets.ANDROID_KEYSTORE }}" | base64 --decode > ${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}
echo "${{ secrets.ANDROID_PLAY_STORE_JSON_KEY_BASE64 }}" | base64 --decode > ${{ env.APP_PATH }}${{ env.ANDROID_PLAY_STORE_JSON_KEY_PATH }}

# run secrets check after keytool has been setup
- name: Verify Android Secrets
if: inputs.platform != 'ios'
run: |
# Verify Play Store JSON key base64 secret exists and is valid
if [ -z "${{ secrets.ANDROID_PLAY_STORE_JSON_KEY_BASE64 }}" ]; then
echo "❌ Error: Play Store JSON key base64 secret cannot be empty"
exit 1
fi
# Verify the base64 can be decoded
if ! echo "${{ secrets.ANDROID_PLAY_STORE_JSON_KEY_BASE64 }}" | base64 --decode >/dev/null 2>&1; then
echo "❌ Error: Invalid Play Store JSON key base64 format"
exit 1
fi
# Verify keystore file exists and is valid
if [ ! -f "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" ]; then
echo "❌ Error: Keystore file was not created successfully"
exit 1
fi
# Try to verify the keystore with the provided password
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" >/dev/null 2>&1; then
echo "❌ Error: Invalid keystore password"
exit 1
fi
# Verify the key alias exists
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" -alias "${{ secrets.ANDROID_KEY_ALIAS }}" >/dev/null 2>&1; then
echo "❌ Error: Key alias '${{ secrets.ANDROID_KEY_ALIAS }}' not found in keystore"
exit 1
fi
# Verify the key password
if ! keytool -list -v -keystore "${{ env.APP_PATH }}${{ env.ANDROID_KEYSTORE_PATH }}" -storepass "${{ secrets.ANDROID_KEYSTORE_PASSWORD }}" -alias "${{ secrets.ANDROID_KEY_ALIAS }}" -keypass "${{ secrets.ANDROID_KEY_PASSWORD }}" >/dev/null 2>&1; then
echo "❌ Error: Invalid key password"
exit 1
fi
echo "✅ All Android secrets verified successfully!"

- name: Build and upload to Google Play Internal Testing
if: inputs.platform != 'ios'
Expand All @@ -744,7 +768,6 @@ jobs:
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
ANDROID_PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME }}
ANDROID_PLAY_STORE_JSON_KEY_PATH: ${{ env.APP_PATH }}${{ env.ANDROID_PLAY_STORE_JSON_KEY_PATH }}
NODE_OPTIONS: "--max-old-space-size=8192"
SLACK_API_TOKEN: ${{ secrets.SLACK_API_TOKEN }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
Expand Down Expand Up @@ -785,12 +808,17 @@ jobs:
with:
app_path: ${{ env.APP_PATH }}

- name: Commit updated build version
- name: Open PR for Android build number bump
if: ${{ !env.ACT && success() }}
uses: ./.github/actions/push-changes
uses: peter-evans/create-pull-request@v6
with:
commit_message: "incrementing android build version for version ${{ env.VERSION }}"
commit_paths: "./app/version.json"
title: "chore: bump Android build for ${{ env.VERSION }}"
body: "Automated bump of Android build number by CI"
commit-message: "chore: incrementing android build version for version ${{ env.VERSION }} [github action]"
branch: ci/bump-android-build-${{ github.run_id }}
base: staging
add-paths: |
app/version.json

- name: Monitor cache usage
if: always()
Expand Down Expand Up @@ -882,37 +910,20 @@ jobs:
echo "ℹ️ Version already up to date or no version field in version.json"
fi

- name: Commit and push version files
run: |
cd ${{ github.workspace }}

# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Check if there are any changes to commit
if git diff --quiet app/version.json app/package.json yarn.lock 2>/dev/null; then
echo "No changes to version files, skipping commit"
else
# Stage the changes
git add app/version.json app/package.json yarn.lock 2>/dev/null || true

# Create commit message based on which platforms were deployed
COMMIT_MSG="chore: update version files after"
if [ "${{ needs.build-ios.result }}" = "success" ] && [ "${{ needs.build-android.result }}" = "success" ]; then
COMMIT_MSG="$COMMIT_MSG iOS and Android deployment"
elif [ "${{ needs.build-ios.result }}" = "success" ]; then
COMMIT_MSG="$COMMIT_MSG iOS deployment"
else
COMMIT_MSG="$COMMIT_MSG Android deployment"
fi
COMMIT_MSG="$COMMIT_MSG [skip ci]"

# Commit and push
git commit -m "$COMMIT_MSG"
git push
echo "✅ Committed version file changes"
fi
- name: Open PR to update version files
uses: peter-evans/create-pull-request@v6
with:
title: "chore: update version files after deployment"
body: |
Automated update of version files after successful deployment.
Includes updates to `app/version.json`, `app/package.json`, and `yarn.lock`.
commit-message: "chore: update version files after deployment [skip ci]"
branch: ci/update-version-${{ github.run_id }}
base: staging
add-paths: |
app/version.json
app/package.json
yarn.lock

# Create git tags after successful deployment
create-release-tags:
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ These guides provide comprehensive context for AI-assisted development with Chat

We are actively looking for contributors. Please check the [open issues](https://github.com/selfxyz/self/issues) if you don't know were to start! We offer bounties for significant contributions.

> **Important:** Please open your pull request from the `staging` branch. Pull requests from other branches will be automatically closed.

Comment on lines +89 to +90
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Clarify PR policy: “to staging” vs “from staging” and ensure enforcement

The sentence suggests opening PRs “from the staging branch,” which is atypical and likely means “to the staging branch.” Also, the claim that PRs from other branches are auto-closed isn’t enforced by any workflow in this PR. Recommend rewording and, if desired, adding a small workflow to enforce it.

Apply this wording fix:

- > **Important:** Please open your pull request from the `staging` branch. Pull requests from other branches will be automatically closed.
+ > **Important:** Please open your pull request to the `staging` branch. Pull requests targeting other base branches may be closed per our workflow policy.

If you want auto-closure, I can add a lightweight workflow that comments and closes PRs whose base != staging. Want me to open a follow-up PR?

📝 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
> **Important:** Please open your pull request from the `staging` branch. Pull requests from other branches will be automatically closed.
> **Important:** Please open your pull request to the `staging` branch. Pull requests targeting other base branches may be closed per our workflow policy.
🤖 Prompt for AI Agents
In README.md around lines 89 to 90, the sentence wrongly instructs opening PRs
"from the staging branch" and asserts auto-closure of PRs from other branches
without an enforcing workflow; update the wording to say "open your pull request
to the staging branch" and remove or soften the claim about automatic closure
(e.g., "PRs not targeting staging may be closed"). If you want enforcement, add
a lightweight GitHub Actions workflow that checks pull_request.base.ref !=
'staging' and posts a comment then closes the PR; otherwise omit the enforcement
claim from the README.


## Contact us

[Contact us](https://t.me/selfprotocolbuilder) on telegram for feedback or questions.
Expand Down
48 changes: 37 additions & 11 deletions app/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,9 @@ platform :android do
"ANDROID_KEY_ALIAS",
"ANDROID_KEY_PASSWORD",
"ANDROID_PACKAGE_NAME",
"ANDROID_PLAY_STORE_JSON_KEY_PATH",
]
# Only require JSON key path when not running in CI (local development)
required_env_vars << "ANDROID_PLAY_STORE_JSON_KEY_PATH" if local_development

Comment on lines +359 to 361
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

ADC in CI: good direction; verify GitHub Actions OIDC wiring to avoid silent auth falls-backs

Requiring ANDROID_PLAY_STORE_JSON_KEY_PATH only for local development is aligned with minimizing long‑lived secrets in CI. To ensure uploads don’t fail due to misconfigured Workload Identity Federation, please verify the workflow contains the google-github-actions/auth step with id-token: write and the required WIF fields.

Run this script to confirm the workflow is correctly configured:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the mobile deploy workflow(s)
fd -t f -a --glob ".github/workflows/*mobile*deploy*.y?(a)ml"

# Show the auth step(s) and nearby config
rg -nC3 -e 'google-github-actions/auth@' -e 'id-token:\s*write' -e 'workload_identity_provider' -e 'service_account' .github/workflows | sed -n '1,200p'

Length of output: 291


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# List all workflow files under .github/workflows (including hidden)
echo "Workflow files found in .github/workflows:"
fd -H -t f --glob ".github/workflows/*.y?(a)ml"

# For each workflow file, display any GitHub OIDC auth configuration
for wf in $(fd -H -t f --glob ".github/workflows/*.y?(a)ml"); do
  echo
  echo "=== Inspecting $wf ==="
  rg -nC3 -e 'google-github-actions/auth@' \
           -e 'id-token:\s*write' \
           -e 'workload_identity_provider' \
           -e 'service_account' \
           "$wf" || echo "(no OIDC auth configuration found in $wf)"
done

Length of output: 215


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Top-level contents:"
ls -a .

echo
echo "Locating any .github directories:"
find . -type d -name ".github" -print || echo "(none found)"

echo
echo "Locating workflow files under .github/workflows:"
find . -type f \( -path "*/.github/workflows/*.yml" -o -path "*/.github/workflows/*.yaml" \) -print || echo "(none found)"

Length of output: 1500


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect OIDC auth configuration in mobile deploy workflows
for wf in .github/workflows/mobile-deploy.yml .github/workflows/mobile-deploy-auto.yml; do
  echo "=== Inspecting $wf ==="
  rg -nC3 -e 'google-github-actions/auth@' \
           -e 'id-token:\s*write' \
           -e 'workload_identity_provider' \
           -e 'service_account:' \
           "$wf" || echo "(no OIDC auth config found in $wf)"
done

Length of output: 1617


Ensure OIDC Authentication Is Configured in All Mobile Deploy Workflows

The primary deploy workflow (mobile-deploy.yml) correctly declares permissions.id-token: write and an auth@v2 step, but the automatic release workflow (mobile-deploy-auto.yml) has no OIDC wiring. Without it, CI will either silently fall back to long-lived JSON keys (which we’re avoiding) or fail outright, undermining our security posture and deployment reliability.

Please add the following to .github/workflows/mobile-deploy-auto.yml:

• Top-level permissions block (if not present)

permissions:
  contents: write
  pull-requests: write
  id-token: write

• An OIDC auth step before any gcloud/upload actions

- name: Authenticate to Google Cloud
  uses: google-github-actions/auth@v2
  with:
    workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
    service_account:        ${{ secrets.GCP_SA_EMAIL }}

• Verify that the workload_identity_provider and service_account values match your GCP setup.

Once added, both manual and automatic deploy workflows will rely solely on Workload Identity Federation and no long-lived secrets.

🤖 Prompt for AI Agents
In app/fastlane/Fastfile around lines 359 to 361, the CI workflows lack OIDC
wiring for automatic releases; update .github/workflows/mobile-deploy-auto.yml
to add a top-level permissions block including id-token: write (and contents:
write, pull-requests: write if needed), and insert an OIDC auth step
(google-github-actions/auth@v2) before any gcloud/upload actions using
workload_identity_provider and service_account values from secrets
(GCP_WIF_PROVIDER and GCP_SA_EMAIL), and verify those secret names match your
GCP Workload Identity Federation configuration.

Fastlane::Helpers.verify_env_vars(required_env_vars)

Expand All @@ -375,19 +376,22 @@ platform :android do
target_platform = options[:track] == "production" ? "Google Play" : "Internal Testing"
should_upload = Fastlane::Helpers.should_upload_app(target_platform)

validate_play_store_json_key(
json_key: ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"],
)
# Validate JSON key only in local development; CI uses Workload Identity Federation (ADC)
if local_development
validate_play_store_json_key(
json_key: ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"],
)
end

Fastlane::Helpers.with_retry(max_retries: 3, delay: 10) do
gradle(
task: "clean bundleRelease --stacktrace --info",
project_dir: "android/",
properties: {
"android.injected.signing.store.file" => ENV["ANDROID_KEYSTORE_PATH"],
"android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["ANDROID_KEY_ALIAS"],
"android.injected.signing.key.password" => ENV["ANDROID_KEY_PASSWORD"],
"MYAPP_UPLOAD_STORE_FILE" => ENV["ANDROID_KEYSTORE_PATH"],
"MYAPP_UPLOAD_STORE_PASSWORD" => ENV["ANDROID_KEYSTORE_PASSWORD"],
"MYAPP_UPLOAD_KEY_ALIAS" => ENV["ANDROID_KEY_ALIAS"],
"MYAPP_UPLOAD_KEY_PASSWORD" => ENV["ANDROID_KEY_PASSWORD"] == "EMPTY" ? "" : ENV["ANDROID_KEY_PASSWORD"],
},
Comment on lines 387 to 395
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reduce risk of leaking signing secrets in CI logs; avoid --info for Gradle in CI

Because keystore credentials are passed via -P properties, running Gradle with --info can echo property usage and increase exposure risk in CI logs. Recommendation: only keep --info locally.

Apply this diff:

-      gradle(
-        task: "clean bundleRelease --stacktrace --info",
+      gradle(
+        task: "clean bundleRelease --stacktrace#{local_development ? ' --info' : ''}",
         project_dir: "android/",
         properties: {
           "MYAPP_UPLOAD_STORE_FILE" => ENV["ANDROID_KEYSTORE_PATH"],
           "MYAPP_UPLOAD_STORE_PASSWORD" => ENV["ANDROID_KEYSTORE_PASSWORD"],
           "MYAPP_UPLOAD_KEY_ALIAS" => ENV["ANDROID_KEY_ALIAS"],
           "MYAPP_UPLOAD_KEY_PASSWORD" => ENV["ANDROID_KEY_PASSWORD"] == "EMPTY" ? "" : ENV["ANDROID_KEY_PASSWORD"],
         },
       )

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 RuboCop (1.76.1)

[convention] 395-395: Avoid comma after the last parameter of a method call.

(Style/TrailingCommaInArguments)

🤖 Prompt for AI Agents
In app/fastlane/Fastfile around lines 387 to 395, the gradle invocation includes
the --info flag which can cause keystore properties passed via -P to be echoed
in CI logs; remove the --info flag (or conditionally omit it when ENV["CI"] is
true) so secrets are not exposed, keeping only --stacktrace for CI runs and
preserve --info only for local/debug runs.

)
end
Expand All @@ -399,16 +403,38 @@ platform :android do
else
if should_upload
begin
upload_to_play_store(
upload_options = {
track: options[:track],
json_key: ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"],
package_name: ENV["ANDROID_PACKAGE_NAME"],
skip_upload_changelogs: true,
skip_upload_images: true,
skip_upload_screenshots: true,
track_promote_release_status: "completed",
aab: android_aab_path,
)
}
Comment on lines +406 to +414
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use release_status (not track_promote_release_status) for direct uploads; add GHA creds fallback

For direct AAB uploads, supply expects release_status. Also accept GOOGLE_GHA_CREDS_PATH as a fallback when the auth action sets that instead of GOOGLE_APPLICATION_CREDENTIALS.

Apply this diff:

           upload_options = {
             track: options[:track],
             package_name: ENV["ANDROID_PACKAGE_NAME"],
             skip_upload_changelogs: true,
             skip_upload_images: true,
             skip_upload_screenshots: true,
-            track_promote_release_status: "completed",
+            release_status: "completed",
             aab: android_aab_path,
           }
           # In local development, use the JSON key file; in CI use ADC credentials
           if local_development
             upload_options[:json_key] = ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"]
           elsif ENV["GOOGLE_APPLICATION_CREDENTIALS"]
             upload_options[:json_key] = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
+          elsif ENV["GOOGLE_GHA_CREDS_PATH"]
+            upload_options[:json_key] = ENV["GOOGLE_GHA_CREDS_PATH"]
           end

Also applies to: 415-421

🤖 Prompt for AI Agents
In app/fastlane/Fastfile around lines 406-414 (and also apply same change to
lines 415-421), the upload_options for direct AAB uploads incorrectly use
track_promote_release_status and do not accept the GHA creds fallback; replace
track_promote_release_status with release_status set to "completed", and ensure
the code accepts GOOGLE_GHA_CREDS_PATH as a fallback by setting
ENV["GOOGLE_APPLICATION_CREDENTIALS"] ||= ENV["GOOGLE_GHA_CREDS_PATH"] (or
otherwise reading GOOGLE_GHA_CREDS_PATH when GOOGLE_APPLICATION_CREDENTIALS is
unset) before performing the upload so the auth path works for both env variable
names.

# In local development, use the JSON key file; in CI rely on ADC
if local_development
upload_options[:json_key] = ENV["ANDROID_PLAY_STORE_JSON_KEY_PATH"]
else
# In CI, try to use ADC credentials file directly
adc_creds_path = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
if adc_creds_path && File.exist?(adc_creds_path)
UI.message("🔑 Using ADC credentials file: #{adc_creds_path}")
begin
# Try passing the credentials file content as json_key_data
creds_content = File.read(adc_creds_path)
upload_options[:json_key_data] = creds_content
rescue => e
UI.error("Failed to read ADC credentials: #{e.message}")
# Fallback: let supply try to use ADC automatically
UI.message("🔄 Falling back to automatic ADC detection")
end
else
UI.error("❌ ADC credentials not found at: #{adc_creds_path}")
end
end

upload_to_play_store(upload_options)
rescue => e
if e.message.include?("forbidden") || e.message.include?("403") || e.message.include?("insufficientPermissions")
UI.error("❌ Play Store upload failed: Insufficient permissions")
Expand Down
6 changes: 3 additions & 3 deletions app/version.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"ios": {
"build": 163,
"build": 165,
"lastDeployed": "2025-08-08T22:35:10Z"
},
"android": {
"build": 85,
"lastDeployed": "2025-08-08T15:13:41Z"
"build": 86,
"lastDeployed": "2025-08-20T21:30:05Z"
}
}
Loading