Mobile Release Build (Deterministic & Code Transparency) #126
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Mobile Release Build (Deterministic & Code Transparency) | |
| on: | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| runs-on: ubuntu-22.04 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set SOURCE_DATE_EPOCH for Reproducible Builds | |
| run: | | |
| COMMIT_TIME=$(git log -1 --pretty=%ct) | |
| echo "SOURCE_DATE_EPOCH=$COMMIT_TIME" >> $GITHUB_ENV | |
| echo "Build Time Epoch: $COMMIT_TIME" | |
| - name: Setup JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: '17' | |
| distribution: 'temurin' | |
| cache: 'gradle' | |
| cache-dependency-path: 'gradle/wrapper/gradle-wrapper.properties' | |
| - name: Make scripts executable | |
| run: chmod +x gradlew | |
| - name: Read Version Info | |
| run: | | |
| VERSION_CODE=$(grep versionCode app/version.properties | cut -d= -f2 | tr -d '[:space:]') | |
| VERSION_NAME=$(grep -o 'currentVersionName = "[^"]*"' app/build.gradle.kts | cut -d'"' -f2) | |
| echo "VERSION_CODE=$VERSION_CODE" >> $GITHUB_ENV | |
| echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV | |
| echo ">>> Version: $VERSION_NAME (Build $VERSION_CODE)" | |
| - name: Inject secrets into verifyblind.properties | |
| env: | |
| SENTRY_DSN_ANDROID: ${{ secrets.SENTRY_DSN_ANDROID }} | |
| run: | | |
| # Eski SENTRY_DSN satirini sil (basit adres, replacement-escape yok), yenisini birebir ekle. | |
| # printf degeri yorumlamadan yazar — DSN'deki ozel karakterler (sed replacement) sorun cikarmaz. | |
| sed -i '/^SENTRY_DSN=/d' verifyblind.properties | |
| printf 'SENTRY_DSN=%s\n' "$SENTRY_DSN_ANDROID" >> verifyblind.properties | |
| LINE=$(grep '^SENTRY_DSN=' verifyblind.properties || true) | |
| [ "${#LINE}" -gt 11 ] && echo "DSN inject: OK" || { echo "DSN inject: FAILED (secret empty?)"; exit 1; } | |
| - name: Run Unit Tests | |
| run: ./gradlew test --no-daemon | |
| - name: Build Unsigned AAB | |
| run: ./gradlew bundleRelease -Dorg.gradle.java.home=$JAVA_HOME_17_X64 --no-daemon | |
| - name: Extract DEX Hashes & Generate dex-hashes.json | |
| run: | | |
| unzip -q app/build/outputs/bundle/release/app-release.aab "base/dex/*.dex" -d extracted_dex | |
| cat > dex-hashes.json << EOF | |
| { | |
| "version_code": $VERSION_CODE, | |
| "version_name": "$VERSION_NAME", | |
| "git_commit": "${{ github.sha }}", | |
| "repository": "${{ github.repository }}", | |
| "dex_hashes": { | |
| EOF | |
| FIRST=1 | |
| for dex in $(ls extracted_dex/base/dex/*.dex | sort); do | |
| HASH=$(sha256sum "$dex" | awk '{print $1}') | |
| FILENAME=$(basename "$dex") | |
| if [ $FIRST -eq 1 ]; then | |
| FIRST=0 | |
| else | |
| echo "," >> dex-hashes.json | |
| fi | |
| printf ' "%s": "%s"' "$FILENAME" "$HASH" >> dex-hashes.json | |
| done | |
| cat >> dex-hashes.json << EOF | |
| } | |
| } | |
| EOF | |
| echo ">>> dex-hashes.json:" | |
| cat dex-hashes.json | |
| - name: Generate Build Transparency Report | |
| run: | | |
| S="$GITHUB_STEP_SUMMARY" | |
| echo "### VerifyBlind Deterministic Build Transparency Report" >> $S | |
| echo "" >> $S | |
| echo "| Alan | Değer |" >> $S | |
| echo "|------|-------|" >> $S | |
| echo "| **Versiyon** | $VERSION_NAME (Build $VERSION_CODE) |" >> $S | |
| echo "| **Commit** | [\`${GITHUB_SHA:0:7}\`](https://github.com/${{ github.repository }}/tree/${{ github.sha }}) |" >> $S | |
| echo "| **Tam Commit Hash** | \`${{ github.sha }}\` |" >> $S | |
| echo "" >> $S | |
| echo "#### DEX Hash'leri" >> $S | |
| echo "Aşağıdaki hash'ler bu commit'ten derlenen uygulama kodunun matematiksel özetidir." >> $S | |
| echo "\`\`\`" >> $S | |
| for dex in $(ls extracted_dex/base/dex/*.dex | sort); do | |
| HASH=$(sha256sum "$dex" | awk '{print $1}') | |
| FILENAME=$(basename "$dex") | |
| echo "$HASH $FILENAME" >> $S | |
| done | |
| echo "\`\`\`" >> $S | |
| echo "" >> $S | |
| echo "---" >> $S | |
| echo "## Telefonunuzdaki Uygulamayı Nasıl Doğrularsınız?" >> $S | |
| echo "" >> $S | |
| echo "Aşağıdaki yöntemlerden birini seçin. Her ikisi de telefonun USB ile bağlı ve **USB Hata Ayıklama** açık olmasını gerektirir." >> $S | |
| echo "> **USB Hata Ayıklama:** Telefon Ayarları → Geliştirici Seçenekleri → USB Hata Ayıklama" >> $S | |
| echo "> Geliştirici Seçenekleri gizliyse: Ayarlar → Telefon Hakkında → Derleme Numarası'na 7 kez dokunun." >> $S | |
| echo "" >> $S | |
| echo "### Otomatik Doğrulama (Windows)" >> $S | |
| echo "" >> $S | |
| echo "**1.** Doğrulama scriptini indirin:" >> $S | |
| echo "- [verify-windows.ps1](https://cdn.verifyblind.com/autoverifyscripts/verify-windows.ps1)" >> $S | |
| echo "" >> $S | |
| echo "**2.** PowerShell açın ve scripti çalıştırın:" >> $S | |
| echo "\`\`\`powershell" >> $S | |
| echo "./verify-windows.ps1" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "> ADB (telefon bağlantısı için gerekli araç) sisteminizde yoksa script otomatik olarak indirip kurar — sizden bir şey yapmanız beklenmiyor." >> $S | |
| echo "> Script ilk kez çalışmıyorsa: PowerShell'de \`Set-ExecutionPolicy -Scope CurrentUser RemoteSigned\` yazıp tekrar deneyin." >> $S | |
| echo "" >> $S | |
| echo "### Otomatik Doğrulama (macOS / Linux)" >> $S | |
| echo "" >> $S | |
| echo "**1.** ADB kurun:" >> $S | |
| echo "\`\`\`bash" >> $S | |
| echo "# macOS" >> $S | |
| echo "brew install android-platform-tools" >> $S | |
| echo "" >> $S | |
| echo "# Ubuntu / Debian" >> $S | |
| echo "sudo apt install adb" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "" >> $S | |
| echo "**2.** Doğrulama scriptini indirin ve çalıştırın:" >> $S | |
| echo "\`\`\`bash" >> $S | |
| echo "curl -O https://cdn.verifyblind.com/autoverifyscripts/verify-unix.sh" >> $S | |
| echo "chmod +x verify-unix.sh" >> $S | |
| echo "./verify-unix.sh" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "" >> $S | |
| echo "---" >> $S | |
| echo "" >> $S | |
| echo "**Ekranda gördükleriniz ne anlama geliyor ve neden güvenebilirsiniz?** Script önce uygulamanızın versiyon ve commit hash'ini doğrudan telefonun belleğinden okur — bu değerler bu sayfanın üstündekiyle aynı olmalıdır. Sonra telefondaki APK'nın içindeki her \`classes*.dex\` dosyasının SHA-256 kriptografik özetini hesaplayıp GitHub Release'inde yayınlanan beklenen hash'lerle karşılaştırır. Her satırın yanındaki **ESLESTI** yazısı, telefonunuzdaki o kod parçasının bit-bit GitHub'daki kodla aynı olduğunu kanıtlar; son ekrandaki yeşil **DOGRULAMA BASARILI** mesajı ise uygulamayı çalıştıran kodun tamamen üstte gördüğünüz commit'ten derlendiğini matematiksel olarak garanti eder." >> $S | |
| echo "" >> $S | |
| echo "Bu doğrulamada VerifyBlind'in iddialarına değil, matematiğin kendisine güveniyorsunuz: scriptin her satırını çalıştırmadan önce açıp okuyabilirsiniz, karşılaştırılan hash'ler GitHub Actions'ın değiştirilemez build kayıtlarından geliyor ve SHA-256 öyle bir özet fonksiyondur ki farklı bir kodun aynı hash'i üretmesi pratik olarak imkânsızdır. Aradaki herhangi bir adımda — build sunucusu, dağıtım kanalı, hatta cihazınızın depolama alanı — farklı bir kod gizlenmiş olsaydı eşleşme olmazdı." >> $S | |
| echo "" >> $S | |
| echo "### Manuel Doğrulama (İleri Düzey)" >> $S | |
| echo "" >> $S | |
| echo "**1.** ADB'yi kurun (yukarıdaki adımlara bakın)" >> $S | |
| echo "" >> $S | |
| echo "**2.** Telefondaki APK yolunu öğrenin:" >> $S | |
| echo "\`\`\`bash" >> $S | |
| echo "adb shell pm path com.verifyblind.mobile" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "Çıktı örneği: \`package:/data/app/~~XxXx==/com.verifyblind.mobile-XxXx==/base.apk\`" >> $S | |
| echo "" >> $S | |
| echo "**3.** APK'yı bilgisayarınıza çekin (\`package:\` önekini kaldırarak yolu kullanın):" >> $S | |
| echo "\`\`\`bash" >> $S | |
| echo "adb pull /data/app/~~XxXx==/com.verifyblind.mobile-XxXx==/base.apk base.apk" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "" >> $S | |
| echo "**4.** DEX dosyalarını çıkarıp hash'leyin:" >> $S | |
| echo "\`\`\`bash" >> $S | |
| echo "# macOS / Linux" >> $S | |
| echo "unzip -q base.apk \"*.dex\" -d dex && sha256sum dex/*.dex" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "\`\`\`powershell" >> $S | |
| echo "# Windows PowerShell" >> $S | |
| echo "Expand-Archive base.apk dex" >> $S | |
| echo "Get-ChildItem dex\\*.dex | ForEach-Object { (Get-FileHash \$_ -Algorithm SHA256).Hash.ToLower() + \" \" + \$_.Name }" >> $S | |
| echo "\`\`\`" >> $S | |
| echo "" >> $S | |
| echo "**5.** Çıktıdaki hash'leri bu sayfanın üstündeki **DEX Hash'leri** tablosuyla karşılaştırın — tüm satırlar birebir eşleşmeli." >> $S | |
| - name: Create GitHub Release | |
| if: github.event_name == 'workflow_dispatch' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| TAG="build-$VERSION_CODE" | |
| TITLE="VerifyBlind v$VERSION_NAME (Build $VERSION_CODE)" | |
| printf '**Sürüm / Version:** %s (Build %s)\n' "$VERSION_NAME" "$VERSION_CODE" > release-body.md | |
| cat >> release-body.md <<'EOF' | |
| **Commit:** [`${{ github.sha }}`](https://github.com/${{ github.repository }}/commit/${{ github.sha }}) | |
| Bu release'e ekli `dex-hashes.json`, bu commit'ten derlenen uygulamanın DEX kod bileşenlerinin SHA-256 özetlerini içerir. Telefonunuzdaki uygulamanın bu koddan derlendiğini aşağıdaki araçla kanıtlayabilirsiniz. | |
| The attached `dex-hashes.json` contains the SHA-256 digests of the app's DEX code components built from this commit. You can prove the app on your phone was built from this code with the tool below. | |
| --- | |
| ### 🇹🇷 Telefonunuzdaki uygulamayı doğrulayın | |
| **Gereken:** Telefonda USB Hata Ayıklama açık + USB bağlı. (Ayarlar → Geliştirici Seçenekleri → USB Hata Ayıklama; Geliştirici Seçenekleri gizliyse Telefon Hakkında → Derleme Numarası'na 7 kez dokunun.) | |
| **Windows (PowerShell):** | |
| ```powershell | |
| irm https://cdn.verifyblind.com/autoverifyscripts/verify-windows.ps1 -OutFile verify-windows.ps1 | |
| ./verify-windows.ps1 | |
| ``` | |
| **macOS / Linux:** | |
| ```bash | |
| curl -O https://cdn.verifyblind.com/autoverifyscripts/verify-unix.sh | |
| chmod +x verify-unix.sh | |
| ./verify-unix.sh | |
| ``` | |
| Araç telefondaki APK'nın DEX dosyalarını hash'leyip yukarıdaki `dex-hashes.json` ile karşılaştırır; yeşil **DOĞRULAMA BAŞARILI** = kod birebir eşleşiyor. Tam açıklama + manuel yöntem: [README](https://github.com/${{ github.repository }}#readme). | |
| ### 🇬🇧 Verify the app on your phone | |
| **Requires:** USB debugging enabled + phone connected via USB. | |
| **Windows (PowerShell):** | |
| ```powershell | |
| irm https://cdn.verifyblind.com/autoverifyscripts/verify-windows.ps1 -OutFile verify-windows.ps1 | |
| ./verify-windows.ps1 | |
| ``` | |
| **macOS / Linux:** | |
| ```bash | |
| curl -O https://cdn.verifyblind.com/autoverifyscripts/verify-unix.sh | |
| chmod +x verify-unix.sh | |
| ./verify-unix.sh | |
| ``` | |
| The tool hashes the DEX files in the APK on your phone and compares them to `dex-hashes.json` above; a green **VERIFICATION SUCCESSFUL** means the code matches bit-for-bit. Full explanation + manual method: [README](https://github.com/${{ github.repository }}#readme). | |
| EOF | |
| gh release delete "$TAG" --yes 2>/dev/null || true | |
| git push origin ":refs/tags/$TAG" 2>/dev/null || true | |
| gh release create "$TAG" \ | |
| --title "$TITLE" \ | |
| --notes-file release-body.md \ | |
| --repo "${{ github.repository }}" \ | |
| dex-hashes.json \ | |
| app/build/outputs/bundle/release/app-release.aab | |
| - name: Upload AAB Artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: verifyblind-release-aab | |
| path: app/build/outputs/bundle/release/app-release.aab |