From 603980a118df084e5edc0941e3a8fda9c8b0f4c7 Mon Sep 17 00:00:00 2001 From: Stem0794 <215477546+Stem0794@users.noreply.github.com> Date: Fri, 21 Aug 2026 10:06:54 +0200 Subject: [PATCH 1/3] docs(release): require fresh clone builds --- docs/RELEASING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 130849a..0a34f12 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -7,7 +7,7 @@ 5. Test an update from the previous published Harbor release while Harbor remains profile owner. 6. Complete the physical-device release matrix. 7. Create an immutable annotated source tag named `v` and verify it points to the intended release commit. -8. From a clean checkout of that exact tag, build the unsigned release APK with the documented JDK and Android SDK versions. +8. From a fresh `git clone` of the repository, check out that exact tag and build the unsigned release APK with the documented JDK and Android SDK versions. 9. Sign the APK with `sh scripts/sign-release.sh`. The script uses an F-Droid-compatible Android Build Tools 34 `apksigner`, writes the exact asset name `app-release-signed.apk` by default, and verifies the resulting certificate before returning success. 10. Publish the GitHub release with `app-release-signed.apk` attached. 11. Verify that F-Droid detects the tag, independently rebuilds it, and successfully completes its reproducibility check before treating the F-Droid release as complete. @@ -47,7 +47,7 @@ Before signing, provide these environment variables through the release environm The signing script passes password references to `apksigner` using its `env:` input mode; it does not put password values in the command arguments. -From a clean checkout of the release tag: +From a fresh `git clone` of the repository, check out the release tag and run: ```shell ./gradlew --no-daemon clean assembleRelease From ee7882a935f739c6ebfdfa51c825dc21c92a82e8 Mon Sep 17 00:00:00 2001 From: Stem0794 <215477546+Stem0794@users.noreply.github.com> Date: Fri, 21 Aug 2026 10:07:06 +0200 Subject: [PATCH 2/3] build: reject invalid release Git metadata --- scripts/verify-deterministic-build.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/verify-deterministic-build.sh b/scripts/verify-deterministic-build.sh index ad48f13..04db4e6 100644 --- a/scripts/verify-deterministic-build.sh +++ b/scripts/verify-deterministic-build.sh @@ -6,13 +6,28 @@ second_dir=$(mktemp -d) trap 'rm -rf "$first_dir" "$second_dir"' EXIT gradle_bin=${GRADLE_BIN:-./gradlew} +if ! command -v unzip >/dev/null 2>&1; then + printf 'unzip is required to inspect release APK metadata\n' >&2 + exit 1 +fi + +verify_vcs_metadata() { + apk=$1 + if unzip -p "$apk" META-INF/version-control-info.textproto 2>/dev/null | grep -Fq 'NO_VALID_GIT_FOUND'; then + printf 'Release APK contains invalid Git metadata: NO_VALID_GIT_FOUND\n' >&2 + exit 1 + fi +} + "$gradle_bin" --no-daemon --no-parallel --no-configuration-cache clean "$gradle_bin" --no-daemon --no-parallel --no-configuration-cache assembleRelease cp app/build/outputs/apk/release/app-release-unsigned.apk "$first_dir/harbor.apk" +verify_vcs_metadata "$first_dir/harbor.apk" "$gradle_bin" --no-daemon --no-parallel --no-configuration-cache clean "$gradle_bin" --no-daemon --no-parallel --no-configuration-cache assembleRelease cp app/build/outputs/apk/release/app-release-unsigned.apk "$second_dir/harbor.apk" +verify_vcs_metadata "$second_dir/harbor.apk" hash_file() { if command -v sha256sum >/dev/null 2>&1; then From 618071825b0e0b66d4d6f0cbd302afcb2a7e1500 Mon Sep 17 00:00:00 2001 From: Stem0794 <215477546+Stem0794@users.noreply.github.com> Date: Fri, 21 Aug 2026 10:28:02 +0200 Subject: [PATCH 3/3] fix(release): require valid VCS metadata --- scripts/verify-deterministic-build.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/verify-deterministic-build.sh b/scripts/verify-deterministic-build.sh index 04db4e6..aae475b 100644 --- a/scripts/verify-deterministic-build.sh +++ b/scripts/verify-deterministic-build.sh @@ -13,7 +13,12 @@ fi verify_vcs_metadata() { apk=$1 - if unzip -p "$apk" META-INF/version-control-info.textproto 2>/dev/null | grep -Fq 'NO_VALID_GIT_FOUND'; then + if ! metadata=$(unzip -p "$apk" META-INF/version-control-info.textproto 2>/dev/null); then + printf 'Release APK is missing valid VCS metadata\n' >&2 + exit 1 + fi + + if printf '%s\n' "$metadata" | grep -Fq 'NO_VALID_GIT_FOUND'; then printf 'Release APK contains invalid Git metadata: NO_VALID_GIT_FOUND\n' >&2 exit 1 fi