Skip to content

Update token secret for checkout action #19

Update token secret for checkout action

Update token secret for checkout action #19

name: Reproducible Build Check (master)
on:
push:
branches: [ "master" ]
jobs:
build-1:
name: Build 1 (signed)
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > ${{ github.workspace }}/release.keystore
if [ ! -s ${{ github.workspace }}/release.keystore ]; then
echo "Keystore file is empty — check the KEYSTORE_BASE64 secret."
exit 1
fi
ls -lh ${{ github.workspace }}/release.keystore
echo "Keystore decoded successfully."
- name: Build Docker image
working-directory: ci
run: docker build -t deku_rep_build_release .
- name: Build unsigned APK
run: |
docker run --rm \
-v "$(pwd)":/project \
-w /project \
--user "$(id -u):$(id -g)" \
-e ANDROID_USER_HOME=/project/.android \
-e GRADLE_USER_HOME=/project/.gradle \
deku_rep_build_release \
./gradlew assembleRelease \
--no-daemon \
--max-workers=2 \
--console=plain \
-Dorg.gradle.jvmargs="-Xmx2048m -Xms512m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8" \
-Dkotlin.daemon.jvm.options="-Xmx512m,-Xss1m" \
-Dkotlin.compiler.execution.strategy=in-process
- name: Sign APK with apksigner
run: |
BUILD_TOOLS=$(ls $ANDROID_HOME/build-tools | sort -V | tail -1)
$ANDROID_HOME/build-tools/$BUILD_TOOLS/apksigner sign \
--ks ${{ github.workspace }}/release.keystore \
--ks-type JKS \
--ks-key-alias "${{ secrets.KEY_ALIAS }}" \
--ks-pass pass:"${{ secrets.STORE_PASSWORD }}" \
--key-pass pass:"${{ secrets.KEY_PASSWORD }}" \
--out app/build/outputs/apk/release/app-release-signed.apk \
app/build/outputs/apk/release/app-release-unsigned.apk
- name: Verify signature
run: |
BUILD_TOOLS=$(ls $ANDROID_HOME/build-tools | sort -V | tail -1)
$ANDROID_HOME/build-tools/$BUILD_TOOLS/apksigner verify \
--verbose \
app/build/outputs/apk/release/app-release-signed.apk
- name: Upload signed APK
uses: actions/upload-artifact@v4
with:
name: apk-build-1
path: app/build/outputs/apk/release/app-release-signed.apk
retention-days: 1
build-2:
name: Build 2 (signed)
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Decode keystore
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode > ${{ github.workspace }}/release.keystore
if [ ! -s ${{ github.workspace }}/release.keystore ]; then
echo "Keystore file is empty — check the KEYSTORE_BASE64 secret."
exit 1
fi
ls -lh ${{ github.workspace }}/release.keystore
echo "Keystore decoded successfully."
- name: Build Docker image
working-directory: ci
run: docker build -t deku_rep_build_release .
- name: Build unsigned APK
run: |
docker run --rm \
-v "$(pwd)":/project \
-w /project \
--user "$(id -u):$(id -g)" \
-e ANDROID_USER_HOME=/project/.android \
-e GRADLE_USER_HOME=/project/.gradle \
deku_rep_build_release \
./gradlew assembleRelease \
--no-daemon \
--max-workers=2 \
--console=plain \
-Dorg.gradle.jvmargs="-Xmx2048m -Xms512m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8" \
-Dkotlin.daemon.jvm.options="-Xmx512m,-Xss1m" \
-Dkotlin.compiler.execution.strategy=in-process
- name: Sign APK with apksigner
run: |
BUILD_TOOLS=$(ls $ANDROID_HOME/build-tools | sort -V | tail -1)
$ANDROID_HOME/build-tools/$BUILD_TOOLS/apksigner sign \
--ks ${{ github.workspace }}/release.keystore \
--ks-type JKS \
--ks-key-alias "${{ secrets.KEY_ALIAS }}" \
--ks-pass pass:"${{ secrets.STORE_PASSWORD }}" \
--key-pass pass:"${{ secrets.KEY_PASSWORD }}" \
--out app/build/outputs/apk/release/app-release-signed.apk \
app/build/outputs/apk/release/app-release-unsigned.apk
- name: Verify signature
run: |
BUILD_TOOLS=$(ls $ANDROID_HOME/build-tools | sort -V | tail -1)
$ANDROID_HOME/build-tools/$BUILD_TOOLS/apksigner verify \
--verbose \
app/build/outputs/apk/release/app-release-signed.apk
- name: Upload signed APK
uses: actions/upload-artifact@v4
with:
name: apk-build-2
path: app/build/outputs/apk/release/app-release-signed.apk
retention-days: 1
compare:
name: Compare signed APKs
runs-on: ubuntu-latest
needs: [ build-1, build-2 ]
steps:
- name: Download APK from build 1
uses: actions/download-artifact@v4
with:
name: apk-build-1
path: apk-build-1
- name: Download APK from build 2
uses: actions/download-artifact@v4
with:
name: apk-build-2
path: apk-build-2
- name: Compare hashes
id: compare
run: |
SHA1=$(sha256sum apk-build-1/app-release-signed.apk | awk '{ print $1 }')
SHA2=$(sha256sum apk-build-2/app-release-signed.apk | awk '{ print $1 }')
echo "Build 1: $SHA1"
echo "Build 2: $SHA2"
if [ "$SHA1" = "$SHA2" ]; then
echo "Reproducible build verified — hashes match."
echo "reproducible=true" >> "$GITHUB_OUTPUT"
else
echo "Build is NOT reproducible — hashes differ!"
echo "reproducible=false" >> "$GITHUB_OUTPUT"
fi
- name: Install diffoscope
if: steps.compare.outputs.reproducible == 'false'
run: |
sudo apt-get update -qq
sudo apt-get install -y diffoscope
- name: Run diffoscope
if: steps.compare.outputs.reproducible == 'false'
run: |
diffoscope \
--text diffoscope-report.txt \
--html diffoscope-report.html \
apk-build-1/app-release-signed.apk \
apk-build-2/app-release-signed.apk || true
- name: Upload diffoscope report
if: steps.compare.outputs.reproducible == 'false'
uses: actions/upload-artifact@v4
with:
name: diffoscope-report
path: |
diffoscope-report.txt
diffoscope-report.html
retention-days: 7
- name: Fail if not reproducible
if: steps.compare.outputs.reproducible == 'false'
run: |
echo "See the diffoscope-report artifact for a full breakdown of differences."
exit 1
tag-and-release:
name: Tag and create GitHub release
runs-on: ubuntu-latest
needs: [ compare ]
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_LIB_SYNC_TOKEN }}
- name: Read version.properties
id: version
run: |
if [ ! -f version.properties ]; then
echo "ERROR: version.properties not found"
exit 1
fi
VERSION_NAME=$(grep "^versionName=" version.properties | cut -d'=' -f2)
if [ -z "$VERSION_NAME" ]; then
echo "ERROR: versionName missing from version.properties"
exit 1
fi
echo "version_name=$VERSION_NAME" >> "$GITHUB_OUTPUT"
echo "versionName=$VERSION_NAME"
- name: Compute next tag
id: next_tag
run: |
LATEST=$(git tag --sort=-v:refname | head -1)
if [ -z "$LATEST" ]; then
LATEST="0"
fi
echo "Latest tag: $LATEST"
NEW_TAG=$((LATEST + 1))
echo "New tag: $NEW_TAG"
echo "new_tag=$NEW_TAG" >> "$GITHUB_OUTPUT"
- name: Create and push tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.next_tag.outputs.new_tag }}" -m "Release ${{ steps.version.outputs.version_name }} — reproducible build verified"
git push origin "${{ steps.next_tag.outputs.new_tag }}"
echo "Tagged ${{ steps.next_tag.outputs.new_tag }} and pushed."
- name: Download signed APK from build-1
uses: actions/download-artifact@v4
with:
name: apk-build-1
path: apk-release
- name: Rename APK with version name
run: |
mv apk-release/app-release-signed.apk \
"apk-release/${{ steps.version.outputs.version_name }}.apk"
- name: Create GitHub release
env:
GH_TOKEN: ${{ secrets.GH_LIB_SYNC_TOKEN }}
run: |
gh release create "${{ steps.next_tag.outputs.new_tag }}" \
"apk-release/${{ steps.version.outputs.version_name }}.apk" \
--title "${{ steps.version.outputs.version_name }}" \
--notes "Reproducible build verified
SHA256: $(sha256sum "apk-release/${{ steps.version.outputs.version_name }}.apk" | awk '{print $1}')" \
--draft