From 36e2199dfff76c5cb318718fb238577393daa3ec Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 21 Jun 2026 14:28:01 +0200 Subject: [PATCH] chore(fdroid): finalize recipe at v2.7.3 + reproducible-release CI guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2.7.3 is the first release built with `vcsInfo { include = false }` and is verified reproducible: a clean from-source build matched the published calendula_v2.7.3.apk byte-for-byte across all 1382 zip entries (only the signature block differs, which F-Droid copies). - Point the fdroiddata recipe's Builds entry + CurrentVersion at v2.7.3 (was the 2.7.2 placeholder, which lacks the fix and would fail verification). - UpdateCheckMode: Tags ^v[0-9.]+$ — after this one-time submission F-Droid auto-tracks new release tags and adds build entries itself; no manual recipe edits per release. - Add scripts/check_reproducible_release.sh + an always-on CI step asserting the release build keeps VCS-info disabled, so reproducibility can't silently regress and quietly stop official-repo publishing. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitea/workflows/ci.yaml | 6 ++++ .../de.jeanlucmakiola.calendula.yml | 29 ++++++++++--------- scripts/check_reproducible_release.sh | 23 +++++++++++++++ 3 files changed, 45 insertions(+), 13 deletions(-) create mode 100755 scripts/check_reproducible_release.sh diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index 1132547..b0f8513 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -30,6 +30,12 @@ jobs: # Full history so the base..HEAD diff below has a merge-base. fetch-depth: 0 + # Cheap, always-on guard: the release build must stay reproducible for the + # official F-Droid repo (no AGP VCS-info embedding). Runs regardless of + # change scope so a regression can't slip through on a "docs-only" PR. + - name: Reproducible-release invariant + run: bash scripts/check_reproducible_release.sh + # Decide whether anything that affects the app build changed. Docs, # F-Droid metadata and the licence don't, so those PRs skip the SDK + # Gradle work below but still report a green `ci`. diff --git a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml index 42be209..dd0fbac 100644 --- a/docs/fdroid-official/de.jeanlucmakiola.calendula.yml +++ b/docs/fdroid-official/de.jeanlucmakiola.calendula.yml @@ -27,16 +27,16 @@ AutoName: Calendula RepoType: git Repo: https://gitea.jeanlucmakiola.de/makiolaj/calendula.git -# IMPORTANT: the first build entry MUST target the first release that contains -# `vcsInfo { include = false }` (added on branch chore/release-verification-process). -# v2.7.1 and earlier embed META-INF/version-control-info.textproto, whose -# env-dependent git metadata breaks reproducibility — they will NOT verify. -# Update the versionName/versionCode/commit/Binaries below once that release is -# tagged (e.g. v2.7.2 -> versionCode 20702). Values below are placeholders. +# First build entry = v2.7.3, the first release with `vcsInfo { include = false }`. +# VERIFIED reproducible (2026-06-21): a clean from-source build of tag v2.7.3 +# matched the published calendula_v2.7.3.apk byte-for-byte across all 1382 zip +# entries (only the signature block differs, which F-Droid copies). v2.7.2 and +# earlier embed META-INF/version-control-info.textproto and will NOT verify — do +# not target them. Subsequent versions are added automatically (AutoUpdateMode). Builds: - - versionName: 2.7.2 - versionCode: 20702 - commit: v2.7.2 + - versionName: 2.7.3 + versionCode: 20703 + commit: v2.7.3 subdir: app gradle: - yes @@ -49,10 +49,13 @@ Builds: AllowedAPKSigningKeys: 5cdaee8eb31cb0df9157c646ae3ec8b3dc43b5bb72624e088c9ddea0c4eb5ec1 # Our own developer-signed APK for reproducible-build verification. %v -> the -# versionName, so v2.7.2 resolves to calendula_v2.7.2.apk on the self-hosted repo. +# versionName, so v2.7.3 resolves to calendula_v2.7.3.apk on the self-hosted repo. Binaries: https://apps.dev.jeanlucmakiola.de/dev/fdroid/repo/calendula_v%v.apk +# After this one-time submission F-Droid auto-tracks new vX.Y.Z tags and creates +# build entries itself — no manual recipe edits per release. The tag regex keeps +# it to release tags only. AutoUpdateMode: Version v%v -UpdateCheckMode: Tags -CurrentVersion: 2.7.2 -CurrentVersionCode: 20702 +UpdateCheckMode: Tags ^v[0-9.]+$ +CurrentVersion: 2.7.3 +CurrentVersionCode: 20703 diff --git a/scripts/check_reproducible_release.sh b/scripts/check_reproducible_release.sh new file mode 100755 index 0000000..fd4bbb3 --- /dev/null +++ b/scripts/check_reproducible_release.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Reproducibility guard for the official F-Droid repo. +# +# F-Droid only republishes OUR signed binary if a from-source build reproduces +# it byte-for-byte. AGP's VCS-info injection writes +# META-INF/version-control-info.textproto with build-environment git metadata +# (commit hash / path) — env-dependent, and the one thing that broke +# reproducibility before we disabled it. It MUST stay off on the release build, +# or new versions silently stop publishing to the official repo (fails safe, but +# you'd be stuck on an old version without noticing). Fail loudly if it regresses. +set -euo pipefail +F="app/build.gradle.kts" + +# Match `vcsInfo { ... include = false ... }` within the block, tolerant of +# whitespace/newlines (-z: whole file as one record; [^}] stays inside the block). +if grep -Pzoq 'vcsInfo\s*\{[^}]*include\s*=\s*false' "$F"; then + echo "OK: release build disables AGP VCS-info — stays reproducible for F-Droid." +else + echo "ERROR: '$F' release build is missing 'vcsInfo { include = false }'." >&2 + echo "AGP would embed env-dependent git metadata (version-control-info.textproto)," >&2 + echo "breaking F-Droid reproducible builds. Restore it. See docs/fdroid-official/." >&2 + exit 1 +fi -- 2.49.1