diff options
Diffstat (limited to 'REPRODUCIBLE-BUILDS')
| -rw-r--r-- | REPRODUCIBLE-BUILDS | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/REPRODUCIBLE-BUILDS b/REPRODUCIBLE-BUILDS new file mode 100644 index 0000000..7cfcde9 --- /dev/null +++ b/REPRODUCIBLE-BUILDS @@ -0,0 +1,79 @@ +rsend reproducible builds +========================= +How rsend stays reproducible and what F-Droid needs to build it. + + +Pinning +------- +Every tool and source version lives in ./versions: the rsync source, Go, JDK, +Android NDK, SDK platform, build-tools, command-line tools, Gradle, the Android +Gradle Plugin, and Kotlin. Directly downloaded archives have repository-owned +checksums. Temurin's glibc and musl archives have separate checksums and cache +directories. The Gradle wrapper records its distribution checksum too. The +gradle files and go.mod repeat some pins because gradle cannot source a shell +file. Gradle's verification-metadata.xml locks every resolved Maven and plugin +artifact by SHA-256. ci/test.sh fails if direct pins or packaged notices drift. + +The packages sdkmanager installs are the exception. The NDK and build-tools are +pinned by revision and verified against the checksums Google publishes in the +SDK repository manifest, not against a checksum this repository owns; only the +platform's android.jar is checked here byte for byte. A republished revision +would therefore change the output without any pin in this tree changing. Adding +repository-owned hashes would mean bypassing sdkmanager and fetching the +multi-gigabyte archives directly, which is not worth the exchange. + +After a deliberate dependency change, regenerate the checksum manifest while +running every Gradle path that resolves artifacts, then review its diff: + + gradle --write-verification-metadata sha256 \ + :app:testReleaseUnitTest :app:lintRelease :app:assembleRelease + + +Determinism +----------- +- rsh (Go): built with the NDK clang, -trimpath, -ldflags "-s -w -buildid=", + CGO_CFLAGS=-ffile-prefix-map to drop build paths, and 16 KB ELF alignment. +- rsync (C): cross-compiled with -ffile-prefix-map and stripped; optional + dependencies are disabled and zlib and popt come from rsync's bundled copies, + so the binary needs nothing outside Bionic. Stack protection, fortified libc + calls, RELRO, immediate binding, and a non-executable stack are explicit. + Configure's host-dependent nobody group is pinned explicitly. Linker flags + give it 16 KB ELF alignment too. +- APK: no code shrinking (minifyEnabled false), the Google dependency-metadata + block is dropped (dependenciesInfo off), and native libs use legacy packaging. + +Verify locally from a clean commit. The script extracts that commit twice at +different absolute paths, builds both complete unsigned APKs, and compares them +byte for byte: + + make verify-repro + +A local gitignored keystore.properties is harmless: git archive cannot copy it +into either clean build tree. + + +F-Droid +------- +The build recipe lives in fdroiddata, not in this repo. F-Droid supplies the +NDK named by the recipe's ndk field and exports ANDROID_NDK_HOME. It pins Go +through the go srclib (the official Go source) and builds it with make.bash, +and installs make and g++ for rsync. The native lib*.so are then built in the +recipe's build step, which runs after F-Droid's source scanner and calls +rsync/build.sh and rsh/build.sh; Gradle then assembles the APK. The release +build is unsigned unless a local keystore.properties is present, so F-Droid +signs the published APK with its own key. + +Each release recipe must set the go srclib ref to the exact GO_VERSION in +./versions. In particular, the published 0.1.3 recipe's go1.25.0 ref must not +be reused for a release built with a newer Go patch version. + + +All-files access +---------------- +rsend requests MANAGE_EXTERNAL_STORAGE. It is required: backup targets such as +OEM call-recording directories and app-specific media folders live outside the +scoped-media buckets, and rsync needs real filesystem paths rather than SAF +content URIs. At runtime the app makes no network access other than SSH +connections to hosts the user configures. Android backup and device-transfer +rules exclude all app data, including the encrypted identity, host pins, paths, +and logs. |