ci(android): never ship a debug-signed APK; check the signer (#5116)
release / govulncheck (push) Successful in 26s
release / go (push) Successful in 2m5s
release / web (push) Successful in 1m24s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m57s
release / Build signed APK (releases and dev) (push) Successful in 5m54s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m26s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 26s
release / go (push) Successful in 2m5s
release / web (push) Successful in 1m24s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m57s
release / Build signed APK (releases and dev) (push) Successful in 5m54s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m26s
release / Verify release artifacts (tag releases only) (push) Skipped
Adopts the rest of family idea #5103 (distributing your own APK): - Practice 2: build.gradle.kts no longer falls back to the debug key when ANDROID_KEYSTORE_PATH is unset; the release build is signed with the release key or left unsigned. Main no longer builds and uploads a debug-signed app-debug.apk, which no install could ever update. - Practice 3: android-release runs apksigner on the built APK, prints the signer's DN and SHA-256 digest, and fails on a debug signer. An unsigned build fails the same step, since there is no app-release.apk to verify. - Practice 9: debug builds offer no server update. The banner does not poll and the About card says updates come from Android Studio, since the release-signed APK cannot install over a debug-signed app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -356,22 +356,11 @@ jobs:
|
||||
- name: Unit tests
|
||||
run: ./gradlew testDebugUnitTest
|
||||
|
||||
- name: Assemble debug
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
run: ./gradlew assembleDebug
|
||||
|
||||
- name: Upload debug APK
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
# Stock action: it works on this forge since the runner moved to
|
||||
# gitea/runner 3.x, which edits upload-artifact's client-side GHES refusal
|
||||
# out of the action bundle (Scribe snippet #2271). Never @v3 — it reports
|
||||
# success while Gitea serves artifacts back only through the v4 API, and
|
||||
# it is what left 72 unreachable artifacts on this repo (Scribe 2270).
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: minstrel-android-debug-${{ github.sha }}
|
||||
path: android/app/build/outputs/apk/debug/app-debug.apk
|
||||
if-no-files-found: error
|
||||
# No debug APK is built or uploaded here. Main used to upload a
|
||||
# debug-signed app-debug.apk: a build signed by a key regenerated in
|
||||
# every container, which no install can update (family idea #5103,
|
||||
# practice 2). Phones get builds from android-release, signed with
|
||||
# the one release key, on dev and on tags.
|
||||
|
||||
# Known vulnerabilities in the Go code and the standard library it is built
|
||||
# with. Runs in the SAME image the Dockerfile's builder stage uses, so the
|
||||
@@ -534,6 +523,26 @@ jobs:
|
||||
-PMINSTREL_VERSION_NAME=${{ steps.ver.outputs.name }} \
|
||||
-PMINSTREL_VERSION_CODE=${{ steps.ver.outputs.code }}
|
||||
|
||||
# The APK every phone updates from must carry the release key: Android
|
||||
# updates an app in place only when the signer matches. Gradle signs
|
||||
# with the release key or leaves the APK unsigned, so this catches a
|
||||
# wrong key, an unsigned build and a debug signer before anything
|
||||
# publishes (family idea #5103, practice 3). apksigner, not keytool:
|
||||
# keytool prints nothing for a v2-only APK.
|
||||
- name: The APK carries the release key
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
sdk="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
|
||||
signer="$(ls "$sdk"/build-tools/*/apksigner 2>/dev/null | sort -V | tail -1 || true)"
|
||||
test -n "$signer" || { echo "::error::no apksigner under '$sdk/build-tools'"; exit 1; }
|
||||
certs="$("$signer" verify --print-certs app/build/outputs/apk/release/app-release.apk)"
|
||||
printf '%s\n' "$certs" | grep -E 'Signer #1 certificate (DN|SHA-256 digest)'
|
||||
if printf '%s' "$certs" | grep -q 'CN=Android Debug'; then
|
||||
echo "::error::the release APK is signed with a debug key"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload APK as workflow artifact
|
||||
# Stock action (snippet #2271) — never @v3, which uploads something Gitea
|
||||
# will never serve back. This is the producing half of a pair:
|
||||
|
||||
Reference in New Issue
Block a user