ci(release): add Android release keystore signing, GPG signatures, and Sigstore attestations

This commit is contained in:
John Smith
2026-09-13 12:30:14 -04:00
parent 2a8db2ff2b
commit 448bd8d490
2 changed files with 83 additions and 6 deletions
+62 -6
View File
@@ -29,8 +29,27 @@ jobs:
- name: Set up Android SDK
uses: android-actions/setup-android@v3
- name: Assemble debug
- name: Decode Android Keystore
if: env.HAS_KEYSTORE == 'true'
run: echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > app/release.jks
env:
HAS_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE_BASE64 != '' }}
- name: Assemble release (signed)
if: env.HAS_KEYSTORE == 'true'
run: ./gradlew assembleRelease --stacktrace
env:
HAS_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE_BASE64 != '' }}
KEYSTORE_PATH: release.jks
KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
- name: Assemble debug (fallback when keystore absent)
if: env.HAS_KEYSTORE != 'true'
run: ./gradlew assembleDebug --stacktrace
env:
HAS_KEYSTORE: ${{ secrets.ANDROID_KEYSTORE_BASE64 != '' }}
- name: Unit tests + UI parity suites + design-invariant audit
run: ./gradlew test --stacktrace
@@ -44,11 +63,19 @@ jobs:
- name: Corpus tooling syntax check
run: python3 -m py_compile tools/*.py
- name: Select APK artifact
run: |
if [ -f "app/build/outputs/apk/release/app-release.apk" ]; then
echo "APK_PATH=app/build/outputs/apk/release/app-release.apk" >> "$GITHUB_ENV"
else
echo "APK_PATH=app/build/outputs/apk/debug/app-debug.apk" >> "$GITHUB_ENV"
fi
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: dorado-hd-debug
path: app/build/outputs/apk/debug/app-debug.apk
name: dorado-hd-apk
path: ${{ env.APK_PATH }}
publish:
name: Publish APK
@@ -61,6 +88,8 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Compute short SHA
@@ -69,11 +98,36 @@ jobs:
- name: Download APK
uses: actions/download-artifact@v4
with:
name: dorado-hd-debug
name: dorado-hd-apk
path: apk
- name: Name APK with commit hash
run: cp apk/app-debug.apk "dorado-hd-${SHORT_SHA}.apk"
run: |
src_apk=$(find apk -name '*.apk' | head -n1)
cp "$src_apk" "dorado-hd-${SHORT_SHA}.apk"
- name: Generate Checksums
run: sha256sum dorado-hd-${SHORT_SHA}.apk > SHA256SUMS
- name: Import GPG Key
if: env.HAS_GPG == 'true'
uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
env:
HAS_GPG: ${{ secrets.GPG_PRIVATE_KEY != '' }}
- name: Sign Checksums
if: env.HAS_GPG == 'true'
run: gpg --batch --yes --detach-sign --armor SHA256SUMS
- name: Attest Build Provenance
uses: actions/attest-build-provenance@v2
with:
subject-path: |
dorado-hd-*.apk
SHA256SUMS*
# Each main-branch commit is published as a prerelease tagged with the
# short commit hash for a stable per-commit download URL.
@@ -84,7 +138,9 @@ jobs:
name: dorado-hd build ${{ env.SHORT_SHA }}
prerelease: true
generate_release_notes: true
files: dorado-hd-${{ env.SHORT_SHA }}.apk
files: |
dorado-hd-${{ env.SHORT_SHA }}.apk
SHA256SUMS*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+21
View File
@@ -16,6 +16,24 @@ android {
versionName = "0.1.0"
}
val keystorePath = System.getenv("KEYSTORE_PATH") ?: project.findProperty("KEYSTORE_PATH") as? String
val keystorePassword = System.getenv("KEYSTORE_PASSWORD") ?: project.findProperty("KEYSTORE_PASSWORD") as? String
val keyAlias = System.getenv("KEY_ALIAS") ?: project.findProperty("KEY_ALIAS") as? String
val keyPassword = System.getenv("KEY_PASSWORD") ?: project.findProperty("KEY_PASSWORD") as? String
val releaseSigningConfig = if (keystorePath != null && file(keystorePath).exists() && keystorePassword != null && keyAlias != null && keyPassword != null) {
signingConfigs.create("release") {
storeFile = file(keystorePath)
storePassword = keystorePassword
this.keyAlias = keyAlias
this.keyPassword = keyPassword
enableV1Signing = true
enableV2Signing = true
}
} else {
null
}
buildTypes {
release {
isMinifyEnabled = true
@@ -24,6 +42,9 @@ android {
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
if (releaseSigningConfig != null) {
signingConfig = releaseSigningConfig
}
}
debug {
applicationIdSuffix = ".debug"