diff --git a/README.md b/README.md index 0ad469c2..fe1bab8e 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,10 @@ adb install -r app/build/outputs/apk/debug/app-debug.apk The app requests Bluetooth, location (required for BLE scanning), and notification permissions at runtime. Release APKs and the Android App Bundle can be rebuilt byte-for-byte in the -pinned Linux container. See [Reproducible builds](docs/reproducible-builds.md) -for the build, GitHub release, and Google Play verification procedures. +pinned Linux container. Maintainers should follow the +[Android release guide](docs/maintainer-release-guide.md). See +[Reproducible builds](docs/reproducible-builds.md) for the build trust model +and public GitHub/Google Play verification procedures. ## Testing diff --git a/docs/maintainer-release-guide.md b/docs/maintainer-release-guide.md new file mode 100644 index 00000000..0da9c385 --- /dev/null +++ b/docs/maintainer-release-guide.md @@ -0,0 +1,582 @@ +# Android maintainer release guide + +This is the operational runbook for publishing a Bitchat Android release to +GitHub and Google Play. Follow it from top to bottom for every release. + +The central rule is: + +> GitHub Actions builds and attests the unsigned release. A maintainer signs +> those exact files locally. Nothing is rebuilt after the tag. + +No keystore or password is stored in GitHub, GitHub Actions, the repository, +release notes, or workflow artifacts. + +For the technical trust model and third-party verification instructions, see +[Reproducible builds](reproducible-builds.md). + +## Release flow + +| Stage | Where it happens | Result | +|---|---|---| +| Approve source | Pull requests and the release gate | One reviewed commit on `main` | +| Create tag | Maintainer machine | Signed `vX.Y.Z` tag | +| Build twice | GitHub Actions | Two identical unsigned APK/AAB builds | +| Promote build | GitHub Actions | Attested `verified-unsigned-release` artifact | +| Sign | Maintainer machine | Three installable APKs and one Play upload AAB | +| Test Play build | Play Console internal track | Play-generated APKs tested before public rollout | +| Prepare release | Maintainer machine and GitHub draft | Checksummed public release assets | +| Publish | GitHub Releases and Play Console | Public GitHub release and promoted Play rollout | + +## What the signing identities mean + +These are four separate signing identities: + +1. **Git tag signature**: identifies the maintainer who approved the source + commit. It is created locally by `git tag -s`. +2. **GitHub APK signature**: lets Android install and update the APKs published + on GitHub. Use the existing GitHub release key. Its certificate SHA-256 must + match `BITCHAT_GITHUB_RELEASE_CERT_SHA256` in `gradle.properties`. +3. **Play upload signature**: the maintainer signs the AAB with the Play upload + key so Play will accept it. +4. **Play app signature**: Google generates device APKs and signs them with the + separate Play app-signing key. + +APK and AAB signatures are embedded in those files. Do not create or publish +detached `.sig` files. GitHub build-provenance attestations are stored by GitHub +and verified with `gh attestation verify`; they are not release asset files. + +Never request, export, or use Google's Play app-signing private key during this +process. + +## Prerequisites + +### Access + +The maintainer needs: + +- permission to push a release tag and create GitHub Releases; +- a GitHub CLI login authorized for + `permissionlesstech/bitchat-android`; +- Play Console permission to create and promote releases for + `com.bitchat.droid`; and +- access to the project's release approval record. + +Check the GitHub login: + +```bash +gh auth status +``` + +### Local tools + +Install: + +- Git; +- [GitHub CLI](https://cli.github.com/); +- the exact JDK in `tools/reproducible-builds/TOOLCHAIN.env`; +- Android SDK Build Tools 37.0.0, including `apksigner` and `zipalign`; and +- Docker with Linux/amd64 support if doing the optional independent rebuild. + +Android Studio's SDK Manager can install the required Build Tools version. +Select **SDK Tools**, enable **Show Package Details**, and install 37.0.0. + +Load the toolchain pins and check the local tools: + +```bash +export JAVA_HOME=/secure/path/to/jdk-21 +export ANDROID_SDK_ROOT=/secure/path/to/android-sdk +source tools/reproducible-builds/TOOLCHAIN.env +gh --version +"$JAVA_HOME/bin/java" -version +"$ANDROID_SDK_ROOT/build-tools/$ANDROID_BUILD_TOOLS_VERSION/apksigner" version +"$ANDROID_SDK_ROOT/build-tools/$ANDROID_BUILD_TOOLS_VERSION/zipalign" -h +``` + +The JDK output must match `JAVA_VERSION`; the Android path must use +`ANDROID_BUILD_TOOLS_VERSION`. + +### Local key material + +Keep these in a password manager or encrypted offline storage: + +- the existing GitHub APK release keystore, alias, store password, and key + password; +- the Play upload keystore, alias, store password, and key password; and +- the maintainer's configured Git tag signing key. + +The GitHub APK key and Play upload key may be different. Treat them as different +credentials even if the project's historical setup placed them in one +keystore. + +Do not put a keystore inside the repository checkout. Do not place passwords on +a command line, in a shell profile, or in a release-notes file. + +## 1. Prepare and approve the release commit + +1. Update `versionCode` and `versionName` in `app/build.gradle.kts`. + `versionCode` must be greater than every build previously uploaded to Play. + `versionName` must match the release tag without the leading `v`. +2. Merge all intended release changes into `main`. +3. Confirm required CI checks are green. +4. Complete the + [physical-device and cross-client release gate](release-gate-runbook.md). + Keep its privacy-reviewed evidence in the release approval record; do not + attach raw device identifiers or logs to the public release. +5. Confirm the release notes and user-visible Play changelog are ready. + +Start from a clean, current checkout: + +```bash +git switch main +git pull --ff-only +git status --short +git log -1 --oneline +``` + +`git status --short` must print nothing. + +Set shell variables for the rest of the release: + +```bash +export REPOSITORY=permissionlesstech/bitchat-android +export TAG=vX.Y.Z +export VERSION_CODE=NN +export RELEASE_DIR="release-${TAG#v}" +``` + +Confirm the source version: + +```bash +grep -nE 'versionCode|versionName' app/build.gradle.kts +test "$(sed -n 's/.*versionName = "\([^"]*\)".*/\1/p' app/build.gradle.kts)" = "${TAG#v}" +test "$(sed -n 's/.*versionCode = \([0-9][0-9]*\).*/\1/p' app/build.gradle.kts)" = "$VERSION_CODE" +``` + +Stop if either `test` command fails. + +## 2. Create and push the release tag + +Create a signed annotated tag on the approved commit: + +```bash +git tag -s "$TAG" -m "Bitchat Android $TAG" +git tag -v "$TAG" +git push origin "$TAG" +``` + +Do not create the GitHub Release yet. Pushing the tag starts the `Release` +workflow, which checks out that exact tag. + +Never move or replace a release tag after pushing it. If source must change, +increment `versionCode`, create a new version, and use a new tag. + +## 3. Wait for the reproducible GitHub build + +Find the `Release` workflow run: + +```bash +gh run list \ + --repo "$REPOSITORY" \ + --workflow release.yml \ + --limit 20 +``` + +Copy the run ID for `$TAG`, then: + +```bash +export RUN_ID=123456789 +gh run watch "$RUN_ID" --repo "$REPOSITORY" --exit-status +gh run view "$RUN_ID" --repo "$REPOSITORY" +``` + +The run is successful only when: + +- both independent unsigned build jobs pass; +- the byte-for-byte comparison passes; +- provenance attestation succeeds; and +- `verified-unsigned-release` is uploaded. + +If the tag already existed and the workflow must be dispatched manually, run +it against the tag ref: + +```bash +gh workflow run release.yml \ + --repo "$REPOSITORY" \ + --ref "$TAG" \ + -f tag="$TAG" +``` + +The workflow rejects a dispatch from a different ref because that would produce +incorrect provenance. + +### Accessing the artifacts + +With the CLI: + +```bash +test ! -e "$RELEASE_DIR" +gh run download "$RUN_ID" \ + --repo "$REPOSITORY" \ + --name verified-unsigned-release \ + --dir "$RELEASE_DIR" +``` + +In the GitHub web interface: + +1. Open **Actions** in the repository. +2. Open the **Release** workflow run for `$TAG`. +3. Scroll to **Artifacts**. +4. Download **verified-unsigned-release**. + +Do not sign `unsigned-release-a` or `unsigned-release-b`. Those are the two +replicas retained for diagnostics. Only `verified-unsigned-release` passed the +comparison gate. Workflow artifacts expire after 30 days, so finish the release +before then. + +## 4. Verify the downloaded unsigned release + +The directory must initially contain exactly these canonical files: + +- `BUILDINFO.json` +- `SHA256SUMS.unsigned` +- `bitchat-android-arm64-unsigned.apk` +- `bitchat-android-armv7-unsigned.apk` +- `bitchat-android-universal-unsigned.apk` +- `bitchat-android-x86-unsigned.apk` +- `bitchat-android-x86_64-unsigned.apk` +- `bitchat-android-release-unsigned.aab` + +Verify the checksum manifest: + +```bash +( + cd "$RELEASE_DIR" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum -c SHA256SUMS.unsigned + else + shasum -a 256 -c SHA256SUMS.unsigned + fi +) +``` + +Verify that `BUILDINFO.json` identifies the tag commit: + +```bash +TAG_COMMIT="$(git rev-list -n 1 "$TAG")" +ARTIFACT_COMMIT="$( + sed -n 's/.*"sourceCommit": *"\([^"]*\)".*/\1/p' \ + "$RELEASE_DIR/BUILDINFO.json" +)" +test "$TAG_COMMIT" = "$ARTIFACT_COMMIT" +``` + +Verify GitHub's provenance for every unsigned APK and AAB: + +```bash +for artifact in \ + "$RELEASE_DIR"/*-unsigned.apk \ + "$RELEASE_DIR"/*-unsigned.aab +do + gh attestation verify "$artifact" --repo "$REPOSITORY" +done +``` + +Stop immediately if a checksum, commit, or attestation check fails. + +## 5. Sign the GitHub APKs locally + +Set the SDK and GitHub release-key locations. Load passwords from the password +manager without placing their values in shell history: + +```bash +export ANDROID_SDK_ROOT=/secure/path/to/android-sdk +export BITCHAT_GITHUB_KEYSTORE=/secure/path/to/github-release.jks +export BITCHAT_GITHUB_KEY_ALIAS=release-key-alias + +printf 'GitHub keystore password: ' +IFS= read -r -s BITCHAT_GITHUB_KEYSTORE_PASSWORD +printf '\nGitHub key password: ' +IFS= read -r -s BITCHAT_GITHUB_KEY_PASSWORD +printf '\n' +export BITCHAT_GITHUB_KEYSTORE_PASSWORD +export BITCHAT_GITHUB_KEY_PASSWORD +``` + +Run: + +```bash +tools/reproducible-builds/sign-release.sh "$RELEASE_DIR" +``` + +The helper: + +- re-verifies `SHA256SUMS.unsigned`; +- uses the pinned Android Build Tools; +- signs each selected APK twice and requires identical results; +- verifies the embedded APK signatures; +- rejects a key whose certificate fingerprint does not match the pinned + GitHub release certificate; and +- writes `SHA256SUMS`. + +It creates: + +- `bitchat-android-arm64.apk` +- `bitchat-android-universal.apk` +- `bitchat-android-x86_64.apk` + +The unsigned armv7 and x86 APKs remain available for reproducibility, but are +not published as signed install targets under the current release policy. + +If the helper stops after creating any signed file, do not continue or overwrite +files manually. Start again in a new directory downloaded from the same +successful workflow run. + +## 6. Sign the Google Play AAB locally + +Set the pinned JDK and Play upload-key locations, then load the passwords: + +```bash +export JAVA_HOME=/secure/path/to/jdk-21 +export BITCHAT_PLAY_UPLOAD_KEYSTORE=/secure/path/to/play-upload.jks +export BITCHAT_PLAY_UPLOAD_KEY_ALIAS=upload-key-alias + +printf 'Play upload keystore password: ' +IFS= read -r -s BITCHAT_PLAY_KEYSTORE_PASSWORD +printf '\nPlay upload key password: ' +IFS= read -r -s BITCHAT_PLAY_KEY_PASSWORD +printf '\n' +export BITCHAT_PLAY_KEYSTORE_PASSWORD +export BITCHAT_PLAY_KEY_PASSWORD +``` + +Run: + +```bash +tools/reproducible-builds/sign-play-bundle.sh "$RELEASE_DIR" +``` + +The helper creates `bitchat-android-play-upload.aab`, verifies its JAR +signature, proves that every non-signature payload entry matches the canonical +unsigned AAB, and updates `SHA256SUMS`. + +This is the only file to upload to Play Console: + +```text +release-X.Y.Z/bitchat-android-play-upload.aab +``` + +Do not upload an APK or `bitchat-android-release-unsigned.aab` to Play. Do not +open Android Studio and rebuild the bundle. + +Remove passwords from the environment after both signing steps: + +```bash +unset BITCHAT_GITHUB_KEYSTORE_PASSWORD +unset BITCHAT_GITHUB_KEY_PASSWORD +unset BITCHAT_PLAY_KEYSTORE_PASSWORD +unset BITCHAT_PLAY_KEY_PASSWORD +``` + +## 7. Prepare all GitHub Release assets + +Run: + +```bash +tools/reproducible-builds/prepare-github-release.sh "$RELEASE_DIR" +``` + +The helper verifies all checksums and renames the public build information and +checksum manifests. It refuses missing or pre-existing release files. + +The final GitHub Release must contain all 13 files below: + +| Asset | Signed? | Why it is published | +|---|---:|---| +| `bitchat-android-arm64.apk` | APK release key | Primary direct-install APK | +| `bitchat-android-universal.apk` | APK release key | Fallback direct-install APK | +| `bitchat-android-x86_64.apk` | APK release key | x86_64 install APK | +| Five `bitchat-android-*-unsigned.apk` files | No | Reproducibility inputs for every ABI target | +| `bitchat-android-release-unsigned.aab` | No | Canonical reproducible Play input | +| `bitchat-android-play-upload.aab` | Play upload key | Exact bundle uploaded to Play | +| `BITCHAT_BUILDINFO.json` | GitHub attestation | Source commit and pinned toolchain | +| `BITCHAT_SHA256SUMS.unsigned` | GitHub attestation | Original canonical CI manifest | +| `BITCHAT_SHA256SUMS` | No detached signature | SHA-256 for every published asset | + +Run the public checksum verification once more: + +```bash +( + cd "$RELEASE_DIR" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum -c BITCHAT_SHA256SUMS + else + shasum -a 256 -c BITCHAT_SHA256SUMS + fi +) +``` + +Do not add keystores, certificate exports, passwords, raw release-gate logs, +local paths, or device/user identifiers to this directory. + +## 8. Create release notes and a draft GitHub Release + +Create a local release-notes file. At minimum it must contain: + +```markdown +## Bitchat Android vX.Y.Z + +- Version code: NN +- Source tag: vX.Y.Z +- GitHub APK signing certificate SHA-256: FINGERPRINT +- Play upload certificate SHA-256: FINGERPRINT +- Play app-signing certificate SHA-256: FINGERPRINT + +Checksums, canonical unsigned APK/AAB inputs, the exact Play upload AAB, and +build information are attached. See `docs/reproducible-builds.md` for public +verification instructions. + +## Changes + +- User-visible change +``` + +The GitHub APK fingerprint comes from `gradle.properties`. Obtain both Play +certificate fingerprints from **Play Console > Setup > App integrity**. Publish +only the SHA-256 fingerprints, not certificate subject details or private-key +material. + +Create a draft release and upload every prepared asset: + +```bash +gh release create "$TAG" "$RELEASE_DIR"/* \ + --repo "$REPOSITORY" \ + --verify-tag \ + --draft \ + --title "Bitchat Android $TAG" \ + --notes-file "release-notes-$TAG.md" +``` + +`--verify-tag` prevents `gh` from silently creating a tag at the wrong commit. +GitHub automatically exposes source archives for the tag; do not upload separate +source ZIP or tar files. + +Inspect the draft: + +```bash +gh release view "$TAG" --repo "$REPOSITORY" --web +``` + +Keep it as a draft until the Play internal-track checks below pass. + +## 9. Upload and test the AAB in Google Play + +1. Open Play Console and select `com.bitchat.droid`. +2. Open **Test and release > Testing > Internal testing**. +3. Create a new release. +4. Upload exactly: + `release-X.Y.Z/bitchat-android-play-upload.aab`. +5. Confirm Play accepts the upload signature and reports the expected package, + `versionCode`, and `versionName`. +6. Add the user-visible Play release notes. +7. Resolve blocking Play checks, save the release, and start the internal + rollout. +8. Install the build through the internal-test opt-in link on a representative + physical device. Confirm startup, upgrade from the previous public release, + networking, and the release-critical scenarios. +9. In **App bundle explorer**, select the uploaded version. If the account + permits downloading the original AAB, download it and verify that its digest + matches `bitchat-android-play-upload.aab` in `BITCHAT_SHA256SUMS`. +10. In **Setup > App integrity**, confirm the Play app-signing certificate + SHA-256 is the value recorded in the GitHub release notes. + +Promote this same tested Play release from internal testing to production. +Do not rebuild or upload a second AAB for production. Use a staged production +rollout when appropriate. + +Google signs the device APKs with the Play app-signing key, so Play-delivered +APKs will not be byte-identical to the GitHub APKs. That is expected. + +## 10. Publish GitHub and promote Play + +After the internal Play build passes and the GitHub draft has all 13 assets: + +```bash +gh release edit "$TAG" \ + --repo "$REPOSITORY" \ + --draft=false \ + --latest +``` + +Then complete or schedule the production promotion in Play Console. If managed +publishing is enabled, send the approved changes for review and publish them at +the coordinated release time. + +Do not replace assets after the GitHub Release is public. If any published +binary is wrong, create a new version and release. + +## 11. Verify the public release + +From a clean checkout of the tag: + +```bash +git checkout "$TAG" +tools/reproducible-builds/verify-github-release.sh "$TAG" --no-rebuild +``` + +For the strongest check, omit `--no-rebuild` and let the pinned container +rebuild and compare all unsigned artifacts: + +```bash +tools/reproducible-builds/verify-github-release.sh "$TAG" +``` + +Also verify: + +- the GitHub release is marked **Latest**; +- the three signed APKs install and show the expected version; +- the Play listing shows the intended production version and rollout state; +- a Play-installed build is signed by the app-signing certificate recorded in + the release notes; and +- the final GitHub URL and Play status are added to the internal release + approval record. + +## Failure and retry rules + +- **A GitHub build or comparison fails:** do not sign anything. Fix the source, + increment the version, and create a new tag. Rerun the same tag only for an + infrastructure-only failure that did not change source. +- **A checksum, provenance, or commit check fails:** stop. Do not publish. +- **A local signing helper fails:** use a fresh download directory. Do not + overwrite partially created signed artifacts. +- **Play rejects the upload key:** stop and resolve the registered upload key in + Play Console. Never substitute the app-signing key. +- **Play has accepted the version code but the binary must change:** increment + `versionCode` and create a new release. +- **A GitHub draft is wrong:** keep it private while correcting it from a fresh, + verified artifact directory. +- **A public release is wrong:** do not move the tag or replace assets. Publish + a new version. + +## Final checklist + +- [ ] Version name and version code updated and approved +- [ ] Required CI and physical-device release gate passed +- [ ] Signed tag pushed from the approved commit +- [ ] `Release` workflow and two-build comparison passed +- [ ] `verified-unsigned-release` downloaded by run ID +- [ ] Checksums, source commit, and attestations verified +- [ ] GitHub APKs signed locally with the pinned certificate +- [ ] Play AAB signed locally with the registered upload key +- [ ] `BITCHAT_SHA256SUMS` verifies all 13 release assets +- [ ] GitHub draft created with certificate fingerprints and all assets +- [ ] Exact signed AAB uploaded to and tested on Play internal track +- [ ] GitHub Release published +- [ ] Same tested Play release promoted to production +- [ ] Public GitHub and Play verification completed + +## Official references + +- [GitHub CLI: download workflow artifacts](https://cli.github.com/manual/gh_run_download) +- [GitHub CLI: create a release](https://cli.github.com/manual/gh_release_create) +- [Google Play App Signing](https://support.google.com/googleplay/android-developer/answer/9842756) +- [Play Console App bundle explorer](https://support.google.com/googleplay/android-developer/answer/9859152) diff --git a/docs/reproducible-builds.md b/docs/reproducible-builds.md index 170a647d..9c65690e 100644 --- a/docs/reproducible-builds.md +++ b/docs/reproducible-builds.md @@ -10,6 +10,11 @@ to GitHub Actions. Anyone can reproduce the unsigned artifacts; maintainers download the verified CI output, sign the selected GitHub APKs and Play upload AAB locally, then manually publish those exact files. +Maintainers should use the complete +[Android maintainer release guide](maintainer-release-guide.md) for the +step-by-step release procedure, artifact inventory, local signing commands, and +GitHub/Google Play publication checklist. + ## What is pinned - Gradle wrapper version and distribution SHA-256 @@ -202,105 +207,13 @@ uploads it manually to Google Play. ## Maintainer release process -Pushing a `vX.Y.Z` tag runs `.github/workflows/release.yml`: +Follow the +[Android maintainer release guide](maintainer-release-guide.md). It is the +authoritative operational runbook from version preparation through the signed +tag, GitHub Actions artifact download, local APK/AAB signing, GitHub draft, +Play internal test, public rollout, and post-release verification. -1. two jobs independently build the canonical unsigned release; -2. a comparison job requires exact byte equality; -3. GitHub generates provenance attestations for the canonical unsigned - artifacts; and -4. Actions uploads `verified-unsigned-release` for the maintainer to download. - -The workflow has read-only repository access and no signing secrets. It does not -create a GitHub Release or upload to Google Play. - -To rerun an existing tag manually, dispatch the workflow against the tag ref -(not the default branch): - -```bash -gh workflow run release.yml \ - --repo permissionlesstech/bitchat-android \ - --ref vX.Y.Z \ - -f tag=vX.Y.Z -``` - -The workflow rejects a dispatch whose selected ref and requested tag resolve to -different commits, keeping the GitHub provenance tied to the source actually -built. - -### 1. Download the verified build - -Find the completed tag workflow's run ID, then download the promoted replica: - -```bash -gh run download RUN_ID \ - --repo permissionlesstech/bitchat-android \ - --name verified-unsigned-release \ - --dir release -``` - -Verify `release/SHA256SUMS.unsigned` before signing. - -### 2. Sign GitHub APKs locally - -Install Android Build Tools 37.0.0 and set these local environment variables: - -- `ANDROID_SDK_ROOT` -- `BITCHAT_GITHUB_KEYSTORE` -- `BITCHAT_GITHUB_KEY_ALIAS` -- `BITCHAT_GITHUB_KEYSTORE_PASSWORD` -- `BITCHAT_GITHUB_KEY_PASSWORD` - -Then run: - -```bash -tools/reproducible-builds/sign-release.sh release -``` - -The helper signs the arm64, x86_64, and universal APKs twice, requires the two -signed results to match, and verifies their certificate against -`BITCHAT_GITHUB_RELEASE_CERT_SHA256` in `gradle.properties`. - -### 3. Sign the Play AAB locally - -Use JDK 21 and the Play upload key—not the Play app-signing key managed by -Google. Set: - -- `JAVA_HOME` -- `BITCHAT_PLAY_UPLOAD_KEYSTORE` -- `BITCHAT_PLAY_UPLOAD_KEY_ALIAS` -- `BITCHAT_PLAY_KEYSTORE_PASSWORD` -- `BITCHAT_PLAY_KEY_PASSWORD` - -Then run: - -```bash -tools/reproducible-builds/sign-play-bundle.sh release -``` - -This creates `release/bitchat-android-play-upload.aab`, verifies its JAR -signature, proves that its non-signature payload matches the canonical unsigned -AAB, and updates `SHA256SUMS`. Upload that exact signed AAB to Play Console; do -not rebuild it in Android Studio. - -### 4. Prepare and publish the GitHub Release - -After both local signing steps: - -```bash -tools/reproducible-builds/prepare-github-release.sh release -gh release create vX.Y.Z release/* \ - --repo permissionlesstech/bitchat-android \ - --verify-tag \ - --draft \ - --title "Release vX.Y.Z" \ - --notes "See docs/reproducible-builds.md for verification instructions." -``` - -Review the draft assets and Play internal-track result before publishing the -GitHub Release and promoting the Play rollout. - -Never store a keystore or password in the repository, GitHub Actions secrets, -workflow artifacts, logs, release notes, or build information. +The workflow has no signing secrets and never publishes a release by itself. ## Updating dependencies or toolchains diff --git a/tools/reproducible-builds/prepare-github-release.sh b/tools/reproducible-builds/prepare-github-release.sh index 9d1b92e2..73ea9f32 100755 --- a/tools/reproducible-builds/prepare-github-release.sh +++ b/tools/reproducible-builds/prepare-github-release.sh @@ -23,9 +23,15 @@ required=( BUILDINFO.json SHA256SUMS SHA256SUMS.unsigned + bitchat-android-arm64-unsigned.apk bitchat-android-arm64.apk + bitchat-android-armv7-unsigned.apk bitchat-android-play-upload.aab + bitchat-android-release-unsigned.aab + bitchat-android-universal-unsigned.apk bitchat-android-universal.apk + bitchat-android-x86-unsigned.apk + bitchat-android-x86_64-unsigned.apk bitchat-android-x86_64.apk ) for artifact in "${required[@]}"; do @@ -35,6 +41,28 @@ for artifact in "${required[@]}"; do fi done +for artifact_path in "$RELEASE_DIR"/*; do + if [ ! -f "$artifact_path" ]; then + echo "error: unexpected non-file in release directory: $(basename "$artifact_path")" >&2 + exit 1 + fi + artifact="$(basename "$artifact_path")" + case "$artifact" in + BUILDINFO.json|SHA256SUMS|SHA256SUMS.unsigned|\ + bitchat-android-arm64-unsigned.apk|bitchat-android-arm64.apk|\ + bitchat-android-armv7-unsigned.apk|\ + bitchat-android-play-upload.aab|bitchat-android-release-unsigned.aab|\ + bitchat-android-universal-unsigned.apk|bitchat-android-universal.apk|\ + bitchat-android-x86-unsigned.apk|\ + bitchat-android-x86_64-unsigned.apk|bitchat-android-x86_64.apk) + ;; + *) + echo "error: unexpected release artifact: $artifact" >&2 + exit 1 + ;; + esac +done + for destination in BITCHAT_BUILDINFO.json BITCHAT_SHA256SUMS BITCHAT_SHA256SUMS.unsigned; do if [ -e "$RELEASE_DIR/$destination" ]; then echo "error: public release manifest already exists: $destination" >&2 diff --git a/tools/reproducible-builds/sign-release.sh b/tools/reproducible-builds/sign-release.sh index 226202c8..b36d2da9 100755 --- a/tools/reproducible-builds/sign-release.sh +++ b/tools/reproducible-builds/sign-release.sh @@ -65,20 +65,27 @@ trap 'rm -rf "$TEMP_DIR"' EXIT export BITCHAT_GITHUB_KEYSTORE_PASSWORD export BITCHAT_GITHUB_KEY_PASSWORD -declare -A signed_names=( - ["bitchat-android-arm64-unsigned.apk"]="bitchat-android-arm64.apk" - ["bitchat-android-universal-unsigned.apk"]="bitchat-android-universal.apk" - ["bitchat-android-x86_64-unsigned.apk"]="bitchat-android-x86_64.apk" +unsigned_names=( + "bitchat-android-arm64-unsigned.apk" + "bitchat-android-universal-unsigned.apk" + "bitchat-android-x86_64-unsigned.apk" +) +signed_names=( + "bitchat-android-arm64.apk" + "bitchat-android-universal.apk" + "bitchat-android-x86_64.apk" ) -for unsigned_name in "${!signed_names[@]}"; do +for ((index = 0; index < ${#unsigned_names[@]}; index++)); do + unsigned_name="${unsigned_names[$index]}" + signed_name="${signed_names[$index]}" unsigned_apk="$RELEASE_DIR/$unsigned_name" - signed_apk="$RELEASE_DIR/${signed_names[$unsigned_name]}" + signed_apk="$RELEASE_DIR/$signed_name" first_signed="$TEMP_DIR/first.apk" second_signed="$TEMP_DIR/second.apk" if [ -e "$signed_apk" ]; then - echo "error: signed APK already exists: ${signed_names[$unsigned_name]}" >&2 + echo "error: signed APK already exists: $signed_name" >&2 exit 1 fi "$ZIPALIGN" -c -P 16 4 "$unsigned_apk"