From cbde9e3c0042e675d022c95ed120751bbcc22f15 Mon Sep 17 00:00:00 2001 From: David Berrios Date: Fri, 8 May 2026 10:41:12 -0700 Subject: [PATCH 1/2] ci: harden android-leap-chat-test workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Top-level permissions: contents: read (was inheriting org default). - actions/checkout@v4 → @v6 with persist-credentials: false. - runs-on: ubuntu-latest → ubuntu-24.04. - Firebase SA JSON now lands in $RUNNER_TEMP under umask 077 with a trap cleanup; use printf (not echo) to preserve backslash sequences in the JSON. Removes the world-readable mode 644 file that the previous flow left in /tmp. --- .github/workflows/android-leap-chat-test.yml | 26 ++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/.github/workflows/android-leap-chat-test.yml b/.github/workflows/android-leap-chat-test.yml index d84c26f..4aa3fea 100644 --- a/.github/workflows/android-leap-chat-test.yml +++ b/.github/workflows/android-leap-chat-test.yml @@ -1,5 +1,5 @@ name: Android LeapChat Build -on: +on: push: branches: [ main ] paths: @@ -12,11 +12,18 @@ on: - '.github/workflows/android-leap-chat-test.yml' workflow_dispatch: +# Least-privilege default. The job authenticates with gcloud against Firebase +# Test Lab via a service-account JSON; no GitHub API access needed. +permissions: + contents: read + jobs: build-and-e2e-test: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Set up JDK 21 uses: actions/setup-java@v5 with: @@ -28,14 +35,19 @@ jobs: - name: Build E2E test run: cd Android/LeapChat && ./gradlew :app:assembleAndroidTest - name: Run E2E test on Firebase Test Lab + env: + SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }} run: | - echo "$SERVICE_ACCOUNT" > /tmp/service_account.json - gcloud auth activate-service-account --key-file=/tmp/service_account.json + # Land the SA JSON under $RUNNER_TEMP, mode 600, with a trap cleanup + # so a job failure or cancellation doesn't leave the key on disk. + # printf (not echo) preserves backslash sequences in the JSON. + SA_FILE="${RUNNER_TEMP:-/tmp}/service_account.json" + trap 'rm -f "$SA_FILE"' EXIT + ( umask 077 && printf '%s' "$SERVICE_ACCOUNT" > "$SA_FILE" ) + gcloud auth activate-service-account --key-file="$SA_FILE" gcloud firebase test android run --type instrumentation \ --app Android/LeapChat/app/build/outputs/apk/debug/app-debug.apk \ --test Android/LeapChat/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \ --device model=MediumPhone.arm,version=36,locale=en,orientation=portrait \ --project liquid-leap - env: - SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }} From b5019df3c413d05aa4e2cc6c90578fa33f9815c0 Mon Sep 17 00:00:00 2001 From: David Berrios Date: Fri, 8 May 2026 11:01:51 -0700 Subject: [PATCH 2/2] ci: switch from setup-java cache to gradle/actions/setup-gradle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address PR #49 review. Copilot reviewer flagged that setup-java's cache: 'gradle' uses the Actions cache API and the "no GitHub API access needed" comment was imprecise. Empirically the cache works under contents: read (cache save succeeded on the prior run), but gradle/actions/setup-gradle is the proper modern path — matches the desktop-examples worktree (PR #48) and cleanly separates JDK setup from build-cache wiring. - Drop `cache: 'gradle'` from actions/setup-java. - Add gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e (v6.1.0, SHA-pinned). - Refine the permissions-block comment: the Actions cache is gated by the ACTIONS_RUNTIME_TOKEN, not GITHUB_TOKEN, so contents: read is sufficient. --- .github/workflows/android-leap-chat-test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android-leap-chat-test.yml b/.github/workflows/android-leap-chat-test.yml index 4aa3fea..6d709f7 100644 --- a/.github/workflows/android-leap-chat-test.yml +++ b/.github/workflows/android-leap-chat-test.yml @@ -13,7 +13,9 @@ on: workflow_dispatch: # Least-privilege default. The job authenticates with gcloud against Firebase -# Test Lab via a service-account JSON; no GitHub API access needed. +# Test Lab via a service-account JSON; nothing here needs GITHUB_TOKEN write +# scope. The Actions cache (used by gradle/actions/setup-gradle below) is gated +# by the runtime token, not GITHUB_TOKEN, so contents: read is sufficient. permissions: contents: read @@ -29,7 +31,8 @@ jobs: with: java-version: '21' distribution: 'temurin' - cache: 'gradle' + - name: Set up Gradle + uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0 - name: Build LeapChat run: cd Android/LeapChat && ./gradlew :app:assemble - name: Build E2E test