From 14b8cac77c6d7ccfc7b0ae992517873b72aafe43 Mon Sep 17 00:00:00 2001 From: HiLleywyn Date: Sat, 9 May 2026 05:42:13 +0000 Subject: [PATCH 1/2] Android: stable debug keystore for repeatable assetlinks SHA Each CI run regenerates ~/.android/debug.keystore so the APK signing cert SHA-256 changes every build, which means ANDROID_ASSETLINKS_SHA256 on tempest-web has to be rotated for every debug install. Add a workflow step that decodes ANDROID_DEBUG_KEYSTORE_BASE64 (when set) into ~/.android/debug.keystore before gradle runs, so the signing cert is fixed across runs and the asset links env var only has to be set once. scripts/gen-debug-keystore.sh creates a fresh debug keystore with the standard alias and passwords gradle expects, base64 encodes it for the secret, and prints the SHA-256 fingerprint to paste into the web env var. --- .github/workflows/android.yml | 27 +++++++++++++++++ scripts/gen-debug-keystore.sh | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100755 scripts/gen-debug-keystore.sh diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index a595ffc..e873b7f 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -109,6 +109,33 @@ jobs: mkdir -p apps/mobile/android/app echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > apps/mobile/android/app/release.keystore + - name: Restore debug keystore + # Without this, gradle generates a fresh ~/.android/debug.keystore on + # every CI run, so the APK signing cert (and its SHA-256) changes + # every build. Storing a stable keystore as a secret keeps the + # SHA-256 stable so ANDROID_ASSETLINKS_SHA256 on tempest-web does + # not need updating every build. Generate the secret value with + # scripts/gen-debug-keystore.sh. + env: + ANDROID_DEBUG_KEYSTORE_BASE64: ${{ secrets.ANDROID_DEBUG_KEYSTORE_BASE64 }} + run: | + if [ "$BUILD_TYPE" != "debug" ]; then + exit 0 + fi + if [ -z "$ANDROID_DEBUG_KEYSTORE_BASE64" ]; then + echo "::warning::ANDROID_DEBUG_KEYSTORE_BASE64 secret is unset;" \ + "this debug APK will be signed by a fresh per-runner" \ + "keystore, so the SHA-256 changes every run. Run" \ + "scripts/gen-debug-keystore.sh, base64 the output, and add" \ + "it as the ANDROID_DEBUG_KEYSTORE_BASE64 repo secret to" \ + "stabilize it." + exit 0 + fi + mkdir -p "$HOME/.android" + echo "$ANDROID_DEBUG_KEYSTORE_BASE64" | base64 -d > "$HOME/.android/debug.keystore" + chmod 600 "$HOME/.android/debug.keystore" + echo "Restored stable debug keystore from secret." + - name: Assemble APK working-directory: apps/mobile/android env: diff --git a/scripts/gen-debug-keystore.sh b/scripts/gen-debug-keystore.sh new file mode 100755 index 0000000..3c4b3c2 --- /dev/null +++ b/scripts/gen-debug-keystore.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# Creates a stable Android debug keystore so CI debug builds produce a +# fixed signing cert (and therefore a fixed SHA-256 for asset links). +# +# Output: +# ./debug.keystore - the keystore itself +# ./debug.keystore.b64 - base64 of the keystore, ready to +# paste into the +# ANDROID_DEBUG_KEYSTORE_BASE64 +# repo secret +# prints the SHA-256 fingerprint to stdout for use in +# ANDROID_ASSETLINKS_SHA256. +# +# Uses the standard Android debug-build credentials (alias +# androiddebugkey, storepass/keypass "android") so gradle's default +# debug signing config picks it up without further configuration. + +set -eu + +OUT="${1:-debug.keystore}" + +if [ -f "$OUT" ]; then + echo "$OUT already exists, refusing to overwrite. Pass a different path or remove it first." >&2 + exit 1 +fi + +keytool -genkeypair -v \ + -keystore "$OUT" \ + -storetype PKCS12 \ + -storepass android \ + -alias androiddebugkey \ + -keypass android \ + -keyalg RSA \ + -keysize 2048 \ + -validity 10000 \ + -dname "CN=Android Debug,O=Android,C=US" >/dev/null + +base64 < "$OUT" > "$OUT.b64" + +SHA=$(keytool -list -v -keystore "$OUT" -alias androiddebugkey \ + -storepass android -keypass android 2>/dev/null \ + | awk -F': ' '/SHA256:/{print $2; exit}') + +echo +echo "Generated $OUT and $OUT.b64." +echo +echo "1. Add the contents of $OUT.b64 as a GitHub Actions repo secret:" +echo " name: ANDROID_DEBUG_KEYSTORE_BASE64" +echo " value: (paste the entire contents of $OUT.b64)" +echo +echo "2. Add this SHA-256 to the ANDROID_ASSETLINKS_SHA256 env var on the" +echo " tempest-web Railway service, then redeploy:" +echo " $SHA" +echo +echo "3. Rebuild the Android app. The signing cert SHA-256 will now stay" +echo " the same across runs." From 12c775f4a4ca560ec277ebbc49ce6a855717f456 Mon Sep 17 00:00:00 2001 From: HiLleywyn Date: Sat, 9 May 2026 05:47:53 +0000 Subject: [PATCH 2/2] Android: workflow to generate the debug keystore from the GitHub UI Lets the keystore + base64 + SHA-256 be produced from Actions without a local terminal. The run uploads everything as a 1-day artifact and prints the SHA-256 as a workflow notice so it can be copied straight into the tempest-web ANDROID_ASSETLINKS_SHA256 env var. --- .github/workflows/gen-debug-keystore.yml | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/gen-debug-keystore.yml diff --git a/.github/workflows/gen-debug-keystore.yml b/.github/workflows/gen-debug-keystore.yml new file mode 100644 index 0000000..08eca78 --- /dev/null +++ b/.github/workflows/gen-debug-keystore.yml @@ -0,0 +1,52 @@ +name: gen-debug-keystore + +# One-shot helper that generates a stable Android debug keystore so the +# main android workflow can sign every debug APK with the same cert. +# Run from GitHub: Actions tab > "gen-debug-keystore" > Run workflow. +# The run uploads two files as a downloadable artifact and prints the +# SHA-256 fingerprint as a notice. From there you can: +# 1. Copy the SHA-256 from the run log into the +# ANDROID_ASSETLINKS_SHA256 env var on the tempest-web service. +# 2. Download the artifact, open debug.keystore.b64 in a text editor, +# copy the contents into a new repo secret named +# ANDROID_DEBUG_KEYSTORE_BASE64. +# After that the android workflow uses this stable keystore for every +# debug build, so the SHA-256 stops changing. + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + generate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + + - name: Generate keystore + run: | + chmod +x scripts/gen-debug-keystore.sh + mkdir -p out + scripts/gen-debug-keystore.sh out/debug.keystore | tee out/README.txt + + - name: Print SHA-256 prominently + run: | + SHA=$(keytool -list -v -keystore out/debug.keystore \ + -alias androiddebugkey -storepass android -keypass android 2>/dev/null \ + | awk -F': ' '/SHA256:/{print $2; exit}') + echo "::notice::SHA-256 for ANDROID_ASSETLINKS_SHA256: $SHA" + echo "$SHA" > out/sha256.txt + + - uses: actions/upload-artifact@v4 + with: + name: tempest-debug-keystore + path: out/ + if-no-files-found: error + retention-days: 1