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. The SDK platform revision and android.jar bytes are checked after
sdkmanager installs them. 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.

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.
