Skip to content

fix(ci): sign debug builds with a committed keystore so debug-latest updates in place - #155

Merged
SMK1705 merged 2 commits into
mainfrom
fix/ci-stable-apk-signing
Jul 3, 2026
Merged

fix(ci): sign debug builds with a committed keystore so debug-latest updates in place#155
SMK1705 merged 2 commits into
mainfrom
fix/ci-stable-apk-signing

Conversation

@SMK1705

@SMK1705 SMK1705 commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Closes #154. Second (and final) half of batch 1 — the CI-signing fix from the whole-repo review's #1 finding.

The bug

release-apk.yml runs ./gradlew :apps:taskmind:assembleDebug on a fresh GitHub runner, which auto-generates a throwaway ~/.android/debug.keystore per run. So every debug-latest build is signed with a different key, and installing a newer one over an older one fails with INSTALL_FAILED_UPDATE_INCOMPATIBLE → the user must uninstall, wiping all their data — the exact opposite of the release notes' "updates in place and keeps your data".

The fix

Give every debug build one stable, reproducible signature:

  • Committed fixed debug keystore at apps/taskmind/debug.keystore — standard non-secret debug credentials (android / androiddebugkey), PKCS12, backdated per the Android debug-key convention (defends against device clock-skew). The default Android debug key is globally shared, so this is not a secret.
  • .gitignore keeps *.keystore ignored but un-ignores only this one debug key (!apps/taskmind/debug.keystore). Real release keys / keystore.properties stay ignored.
  • build.gradle.kts overrides the built-in debug signingConfig to point at the committed keystore and assigns it to buildTypes.debug.

Verified

./gradlew :apps:taskmind:signingReport → the debug (and debugAndroidTest) variants now resolve Store: apps/taskmind/debug.keystore, alias androiddebugkey, with a stable SHA1 — that stability is exactly what lets debug-latest update in place.

Scope / caveats

  • Debug signing only — release signing is untouched (adversarial review confirmed no leak into release or exposure of a real key; 0 findings).
  • Fixes updates going forward. The first stably-signed build still can't update over a previously differently-signed install — that one requires a single manual reinstall (unavoidable).

Adversarially reviewed across build-correctness / security-scope / CI-path dimensions: 0 confirmed findings.

…updates in place

The Publish-debug-APK workflow runs assembleDebug on a fresh runner, which
auto-generates a throwaway ~/.android/debug.keystore per run — so every
debug-latest build was signed with a different key and could not update an
existing install (INSTALL_FAILED_UPDATE_INCOMPATIBLE → uninstall + data wipe),
contradicting the release notes.

Commit a fixed debug keystore (standard non-secret creds: android /
androiddebugkey, backdated per the Android debug-key convention) and point the
debug signingConfig at it, so every debug build — local and on every CI runner —
shares one stable signature. `signingReport` confirms the debug variant now
resolves apps/taskmind/debug.keystore with a stable fingerprint.

.gitignore keeps *.keystore ignored and un-ignores only this one debug key;
release signing is untouched.

Closes #154
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Rolling debug-latest APK is re-signed per CI run — updates force an uninstall + wipe on-device data

1 participant