Make release APKs reproducible - #6219
AcideFluorhydrique wants to merge 3 commits into
Conversation
Two inputs to the release build were not fixed by anything in the repository. The NDK strips the jniLibs, so its version shapes the APK, but ndkVersion was only ever inserted into build.gradle.kts by a sed in build.yml at a hardcoded line number. Outside CI the Android Gradle Plugin default applied instead. Declare it in build.gradle.kts and drop the sed. setup-java was asked for '21', which resolves to whatever JDK 21 the runner image has preinstalled, so the JDK changed whenever GitHub updated the image. Pin the exact Temurin build, 21.0.12.1+1. It has to be written as the Adoptium semver 21.0.12+101.0.LTS: setup-java checks the runner's preinstalled JDKs before Adoptium, '21.0.12.1' happens to match the preinstalled folder today but nothing on Adoptium, and '21.0.12+101' matches nothing at all. That was checked by running setup-java v6.0.1's own version-matching code against the live Adoptium release list. The same ndkVersion line and JDK pin built identical APKs across three independent GitHub-hosted runs, one of them on a newer runner image.
build.yml downloads libv2ray.aar from the AndroidLibXrayLite release named
by `git describe --tags --abbrev=0`. When the submodule sits past a tag,
that silently resolves to the nearest older tag, and the APK ships a core
that is not the one the submodule points at.
This has happened. 1.10.30 was built with the submodule at 4ba2d04a, and
1.10.31 and 1.10.32 with it at 1655d531 ("Updating xray-core to v25.12.8"),
none of them tagged; describe resolved all three to v25.12.2, so they
shipped the v25.12.2 aar while the source tree said v25.12.8.
Use --exact-match and fail with an explanation instead. Nothing changes
when the submodule is on a tag, which was the case for 27 of the last 30
submodule updates.
|
Pairs well with #6181 ... |
2dust#6181 also drops the sed, and for a better reason: it adds imports for the public variant API, which moves the line the sed counts to. It passes the version as -PNDK_VERSION instead, with AGP's default applying when the property is absent. That default is the problem for reproducibility. Someone rebuilding a published APK runs Gradle without knowing about the property, gets AGP's default NDK, and strips the jniLibs with a different one, so the bytes differ with nothing to indicate why. Read the property and keep the pinned value as its default, so both hold: CI or a local build can override it, and a plain Gradle invocation still uses the NDK the release was built with.
Thanks — agreed, and there is one real overlap: #6181 drops the same The one thing I would ask for in whichever version lands: the pinned NDK has to remain the default, not only a CI-supplied So I have changed my commit to do both: ndkVersion = providers.gradleProperty("NDK_VERSION").getOrElse("29.0.14206865")That keeps your override and keeps a plain Nothing else here should collide: #6181 does not touch |
Companion to 2dust/AndroidLibXrayLite#207, which makes the released
libv2ray.aarreproducible. With both, anyone can rebuild a published APK from source and compare it byte for byte, which is what IzzyOnDroid and F-Droid's reproducible-builds verification needs. Each commit here stands on its own.Changes
ndkVersioninbuild.gradle.ktsand drop thesedinbuild.ymlthat inserted it at a hardcoded line number. The NDK strips the jniLibs, so its version is part of the APK, and thesedonly took effect inside CI.'21', which resolves to whatever JDK 21 the runner image has preinstalled. It is written as21.0.12+101.0.LTS, the formsetup-javamatches against Adoptium;'21.0.12.1'only matches the preinstalled copy by accident, and'21.0.12+101'matches nothing.git describe --tags --exact-matchinstead of--abbrev=0. When the submodule is past a tag,--abbrev=0resolves to the nearest older tag and the older aar is shipped. That happened for 1.10.30 to 1.10.32: the submodule pointed at4ba2d04aand1655d531("Updating xray-core to v25.12.8"), neither tagged, and--abbrev=0resolved both to v25.12.2, sobuild.ymldownloaded the v25.12.2 aar for all three. The step now fails with an explanation instead. 27 of the last 30 submodule updates were on a tag, where nothing changes.Validation
ndkVersionin three independent GitHub-hosted runs, all producing identical APKs: 34460850995, 34466248610, 34475374598. The third used this JDK pin and a newer runner image; the first two used the runner's preinstalled copy of the same JDK build. All three passed:app:assemblePlaystoreDebugand:app:testPlaystoreDebugUnitTestwith abuild.gradle.ktsidentical to this branch's apart from the comment.build.ymlon this branch, since it needs the release keystore.