fix(ci): migrate Android signing to base64 secrets, pin cert SHA-256, fail closed - #212
fix(ci): migrate Android signing to base64 secrets, pin cert SHA-256, fail closed#212TimeToBuildBob wants to merge 2 commits into
Conversation
…osed Aligns with gptme/gptme Android release signing (tauri.yml release-android). Closes ActivityWatch#208. Changes: - build.yml build-apk: drop adnsio/setup-age-action; decode keystore from KEY_ANDROID_JKS_B64 (base64) instead of age-decrypting android.jks.age; add fail-closed check on release tags (requires KEY_ANDROID_JKS_B64, KEY_ANDROID_JKS_STOREPASS, KEY_ANDROID_JKS_KEYPASS, ANDROID_CERT_SHA256); verify APK signer cert SHA-256 after each build when ANDROID_CERT_SHA256 repo variable is set. - build.yml release-fastlane: drop adnsio/setup-age-action; decode Fastlane API JSON from KEY_FASTLANE_API_B64 (base64) instead of age-decryption. - release.yml: same Fastlane API migration. - scripts/sign_apk.sh: add cert SHA-256 verification when ANDROID_CERT_SHA256 is set; use newest build-tools version (sort -V | tail -1). - Remove android.jks.age and fastlane/...json.age (superseded by secrets). Operator steps before next release tag: 1. base64-encode keystore: base64 < android.jks Add as KEY_ANDROID_JKS_B64 secret in repo Settings → Secrets → Actions. 2. base64-encode Fastlane API JSON: base64 < fastlane/api-8546008605074111507-287154-450dc77b365f.json Add as KEY_FASTLANE_API_B64 secret. 3. Get signer cert SHA-256: apksigner verify --print-certs dist/aw-android.apk | grep 'SHA-256' Add as ANDROID_CERT_SHA256 repo variable (Settings → Variables → Actions). 4. Keep KEY_ANDROID_JKS_STOREPASS and KEY_ANDROID_JKS_KEYPASS unchanged. 5. Remove old KEY_ANDROID_JKS and KEY_FASTLANE_API secrets.
Greptile SummaryThe PR migrates Android signing and Fastlane credentials from repository-hosted age-encrypted files to base64-encoded GitHub secrets.
Confidence Score: 5/5The PR appears safe to merge, with release signing failures handled before artifacts are published. The changed workflows preserve signing and Fastlane credential delivery while adding a release-tag configuration gate and signer-certificate verification; no actionable changed-code failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
Tag[Release tag] --> Gate{Signing configuration complete?}
Gate -->|No| Fail[Fail release]
Gate -->|Yes| Decode[Decode base64 keystore]
Decode --> Build[Build APK and AAB]
Build --> Sign[Sign artifacts]
Sign --> Verify[Verify APK signer SHA-256]
Verify -->|Mismatch| Fail
Verify -->|Match| Publish[Publish release artifacts]
FastlaneSecret[Base64 Fastlane credential] --> Credential[Decode API JSON]
Credential --> Publish
Reviews (1): Last reviewed commit: "fix(ci): migrate signing to base64 secre..." | Re-trigger Greptile |
|
CI-green and mergeable — waiting only on a maintainer click. This PR is ready to merge, but the bot has pull-only access to this repo and can't self-merge — surfacing it here so it isn't lost. The monitoring loop will stop re-flagging it now that this note is posted. |
|
Found and fixed one acceptance-criteria gap before merge: AABs were signed but never verified. Commit d2ddd94 now runs
|
Aligns with gptme/gptme Android release signing (tauri.yml release-android). Closes #208.
What changed
Keystore delivery: age → base64 secret
android.jks.age(age-encrypted keystore) committed in-repo; decrypted in CI usingKEY_ANDROID_JKSas the age identity key viaadnsio/setup-age-actionKEY_ANDROID_JKS_B64secret (base64-encoded keystore); decoded in CI withbase64 --decodeFastlane API credentials: same migration
fastlane/api-...json.agecommitted in-repo; decrypted viaKEY_FASTLANE_APIKEY_FASTLANE_API_B64secret; decoded withbase64 --decodeFail closed on release tags
New
Require signing configuration on release tagsstep exits with a descriptive error if any ofKEY_ANDROID_JKS_B64,KEY_ANDROID_JKS_STOREPASS,KEY_ANDROID_JKS_KEYPASS, orANDROID_CERT_SHA256is missing — instead of the current silent fallback to an unsigned artifact.Signer certificate SHA-256 pinning
New
Verify APK signer certificatestep inbuild-apk(andsign_apk.sh) checks the APK's actual signer cert againstANDROID_CERT_SHA256(repo variable). Mismatch = hard failure. Skipped if the variable is not set.adnsio/setup-age-action dropped
Removed from both
build.yml(build-apk + release-fastlane) andrelease.yml. Not needed once both secrets are in base64.Age-encrypted files removed
android.jks.ageandfastlane/api-...json.agedeleted from the repo (superseded by the new secrets). The keystore history in old commits is safe — the age file is still encrypted there.Operator steps before next release tag
Base64-encode the keystore:
Add as
KEY_ANDROID_JKS_B64secret → Settings → Secrets → ActionsBase64-encode the Fastlane API JSON:
Add as
KEY_FASTLANE_API_B64secretGet signer cert SHA-256 (from any existing signed APK):
Add as
ANDROID_CERT_SHA256repo variable → Settings → Variables → ActionsKeep existing passwords unchanged:
KEY_ANDROID_JKS_STOREPASSandKEY_ANDROID_JKS_KEYPASSremain as-is.Remove old secrets:
KEY_ANDROID_JKSandKEY_FASTLANE_APIcan be deleted after the new ones are in place.Reference
.github/workflows/tauri.ymlrelease-android jobdocs/contributing.rst"Android release signing"