Reprodukowalne kompilacje zapewniają weryfikowalne powiązanie między opublikowanym kodem źródłowym a plikiem binarnym wydania. Nasz obecny zakres reprodukowalnych kompilacji obejmuje wydanie F-Droid dla systemu Android. Zamierzamy rozszerzyć ten zakres na dodatkowe kanały dystrybucji dla systemów Android i iOS.

Android

F-Droid

Gem Wallet korzysta z niezależnej infrastruktury kompilacji F-Droid, aby ponownie zbudować plik APK dla F-Droid i zweryfikować go przed publikacją.

Model weryfikacji

Gem Wallet publikuje podpisany plik APK dla F-Droid przy każdym wydaniu. Niezależnie od tego serwery kompilacji F-Droid wykonują publiczny przepis kompilacji w czystym środowisku:

  1. Metadane F-Droid wskazują dokładny commit Git oraz wersję Android NDK.
  2. F-Droid pobiera wskazany commit z publicznego repozytorium Gem Wallet.
  3. Publiczne skrypty reprodukowalnej kompilacji instalują przypięty natywny toolchain i uruchamiają :app:assembleFdroidRelease.
  4. Kompilacja generuje niepodpisany plik APK. F-Droid pobiera odpowiadający mu plik APK podpisany przez dewelopera i potwierdza, że jest on podpisany certyfikatem, którego odcisk zadeklarowano w AllowedAPKSigningKeys.
  5. F-Droid kopiuje podpis APK do ponownie zbudowanego artefaktu i weryfikuje go. Podpisy Android APK Signature Scheme v2/v3 obejmują cały plik APK poza blokiem podpisu, więc pomyślna weryfikacja wymaga, aby zawartość ponownie zbudowanego pliku APK była bajt po bajcie zgodna z wydaniem Gem Wallet.
  6. F-Droid publikuje plik APK podpisany przez dewelopera tylko wtedy, gdy weryfikacja zakończy się powodzeniem. Wydanie, którego nie udaje się odtworzyć, nie jest publikowane.

Mechanizmy deterministycznej kompilacji

Gem Wallet zawiera natywne biblioteki napisane w języku Rust, przez co wynik kompilacji jest wrażliwy na różnice w kompilatorze, linkerze, NDK, platformie hosta i optymalizatorze. Kompilacja F-Droid kontroluje te dane wejściowe poprzez:

  • przypięcie wersji toolchainu Rust i cargo-ndk w android/reproducible/versions.sh;
  • instalację cargo-ndk z flagą --locked, podczas gdy zależności aplikacji w języku Rust są rozwiązywane na podstawie pliku Cargo.lock z repozytorium;
  • przypięcie dokładnej rewizji Android NDK zarówno w projekcie Android, jak i w metadanych F-Droid;
  • kompilację na hoście Linux x86_64 z jawnie określonymi ścieżkami do linkera i archiwizatora NDK;
  • ograniczenie natywnych architektur docelowych APK do armeabi-v7a i arm64-v8a, niezależnie od hosta kompilacji x86_64;
  • użycie dedykowanego kanału produktowego fdroid, bez modułów Google do powiadomień push i recenzji;
  • wyłączenie optymalizacji R8 za pomocą -dontoptimize, aby zapobiec niedeterminizmowi w wyjściu DEX i identyfikatorach mapowania;
  • uruchamianie Gradle bez demona i pamięci podręcznej konfiguracji oraz czyszczenie pamięci podręcznych transformacji przed kompilacją wydania.

Dokładny commit źródłowy, polecenia kompilacji, ścieżka wyjściowa, rewizja NDK, adres URL oryginalnego pliku APK oraz dozwolony certyfikat podpisujący są publicznie dostępne w metadanych F-Droid. Skrypty konfigurujące Rust, Cargo, toolchain NDK i Gradle są utrzymywane razem z kodem źródłowym aplikacji w katalogu android/reproducible.

Właściwości bezpieczeństwa i ograniczenia

Pomyślna weryfikacja F-Droid dowodzi, że podpisany plik APK opublikowany przez Gem Wallet można odtworzyć z zadeklarowanego commita źródłowego i przepisu kompilacji. Ponowna kompilacja odbywa się poza infrastrukturą Gem Wallet, co zmniejsza zależność od naszego potoku wydań jako pojedynczego punktu zaufania.

Reprodukowalność nie dowodzi, że kod źródłowy jest wolny od podatności, że każda zależność jest godna zaufania ani że wybrany toolchain kompilatora nie został skompromitowany. Te ryzyka wymagają, oprócz reprodukowalnych kompilacji, przeglądu kodu źródłowego, kontroli zależności i zabezpieczenia toolchainu.

Status kompilacji i zweryfikowane wydania są dostępne na stronie Gem Wallet w katalogu F-Droid.

Universal APK i Google Play

Universal APK od Gem Wallet oraz wydanie w Google Play nie są obecnie objęte opisaną wyżej weryfikacją F-Droid. Obsługa reprodukowalnych kompilacji dla tych kanałów dystrybucji w systemie Android jest planowana w ramach przyszłych prac.

iOS

Wydanie w App Store nie jest obecnie reprodukowalne. Obsługa reprodukowalnych kompilacji dla iOS oraz niezależna weryfikacja pliku binarnego z App Store są planowane w ramach przyszłych prac.

Frequently Asked Questions

Reprodukowalne kompilacje pozwalają każdemu zbudować Gem Wallet z publicznego kodu źródłowego i zweryfikować, że powstała aplikacja odpowiada oficjalnemu wydaniu. Zapewnia to dodatkową przejrzystość i pomaga potwierdzić, że opublikowana aplikacja została zbudowana z tego samego kodu źródłowego, który jest dostępny na GitHubie.
Open source oznacza, że kod źródłowy Gem Wallet jest publicznie dostępny i każdy może go przejrzeć. Reprodukowalne kompilacje idą o krok dalej: pozwalają niezależnym deweloperom i serwisom, takim jak F-Droid, zbudować aplikację z zadeklarowanego kodu źródłowego i zweryfikować, że powstały plik APK dla systemu Android jest bajt po bajcie zgodny z oficjalnym wydaniem Gem Wallet.
Tak. Zarówno aplikację dla systemu Android, jak i dla iOS możesz zbudować z publicznego kodu źródłowego Gem Wallet. Aplikacja dla systemu Android obsługuje reprodukowalne kompilacje z wykorzystaniem publicznych skryptów kompilacji i przypiętego toolchainu. Aplikację dla iOS możesz również zbudować i uruchomić lokalnie.
Skrypty reprodukowalnej kompilacji oraz konfiguracja przypiętego toolchainu są publiczne. Metadane F-Droid deklarują dokładny commit źródłowy, rewizję Android NDK, polecenia kompilacji i oczekiwany wynikowy plik APK dla każdego wydania. F-Droid niezależnie ponownie buduje aplikację dla systemu Android i publikuje ją tylko wtedy, gdy zawartość pliku APK jest bajt po bajcie zgodna z wydaniem Gem Wallet.
Jeśli masz pytanie, napotkasz problem z kompilacją lub znajdziesz rozbieżność, zgłoś issue w repozytorium Gem Wallet na GitHubie. Dołącz informacje o swoim środowisku, krokach kompilacji i wszelkich istotnych komunikatach o błędach, aby pomóc nam zbadać problem.