MetaMask / MetaMask/metamask-mobile

[BUILD] Failure to Build from Source - Reproducible Builds

Open
#25,034 0 comments 0 reactions 0 assignees View on GitHub
external-contributor
Dominant language
TypeScript
Stars
3k
Forks
1.7k
Avg merge
1d 14h
Merged PRs (30d)
669

Description

### What is this about?

# Reproducible Build Verification: FTBFS for MetaMask Android v7.61.6

👋 Introduction

Hi MetaMask team!

We're from [WalletScrutiny](https://walletscrutiny.com), a project dedicated to verifying whether
cryptocurrency wallets can be built reproducibly from source. Our mission is to help users verify
that the app they download from the Play Store matches the publicly available source code — a
critical security property for self-custody wallets.

We've been working on verifying MetaMask Android and wanted to share our findings and challenges.

## Our Objective

We attempted to build MetaMask Android v7.66.1 from source and compare the
resulting APKs against the official Play Store release. Our process:

1. Clone the repository and checkout the release tag
2. Build the AAB using `./gradlew bundleProdRelease`
3. Extract split APKs using bundletool with a device-spec.json
4. Compare SHA-256 hashes and file contents against official split APKs

## 📋 Summary of Our Efforts

Over the past two days, we developed a containerized build script and iterated through **21
versions** to address various build failures. Our build environment:

- **Base image:** Node.js 20 (Debian Bookworm)
- **Android SDK:** Platforms 24-35, Build Tools 34.0.0 & 35.0.0
- **NDK:** 26.1.10909125
- **Java:** OpenJDK 17
- **Yarn:** 4.10.3 via corepack

### Issues Encountered and Resolved

| Issue | Root Cause | Our Workaround |
|-------|------------|----------------|
| Gradle build failures | Deprecated `compile()` in various `node_modules/*/build.gradle` | Global
sed patch: `compile` → `implementation` |
| Missing SDK platforms | RN modules target SDK 24-28, Gradle can't auto-install | Pre-install
platforms 24-35 in Dockerfile |
| Java compilation errors | Some modules have `compileSdkVersion < 30` | Patch to minimum 30 for
Java 9+ compatibility |
| Sentry upload failures | No auth credentials in reproducible build environment | Disable
`*SentryUpload*` tasks via `sentry.gradle` patch |
| CMake installation | Hermes `installCMake` tries to write to read-only SDK dir | Pre-install
`cmake;3.18.1` and `cmake;3.22.1` |

### Blocking Issue: Boost Tarball Extraction

The build consistently fails at `:react-native:prepareBoost` during Hermes engine compilation. We
attempted multiple fixes:

1. **v0.1.14:** Delete cached tarball to force re-download
2. **v0.1.15:** Explicit curl download with `tar -tzf` verification
3. **v0.1.18:** Try multiple mirrors (archives.boost.io, jfrog)
4. **v0.1.19:** Disable `downloadBoost` task to preserve verified tarball
5. **v0.1.20:** Repack tarball with fresh `tar -czf`
6. **v0.1.21:** Pre-extract Boost to `build/third-party-ndk/boost_1_83_0` and disable
`prepareBoost`

Despite these efforts, the Gradle build continues to fail during Boost/Hermes preparation.

## Current Verdict: FTBFS (Fails To Build From Source)

We are marking MetaMask Android as **FTBFS** on WalletScrutiny because:

1. **No official reproducible build instructions exist** — We could not find documentation
describing how to build the exact APK distributed on the Play Store
2. **Build environment is undocumented** — The CI/CD pipeline likely uses specific tooling,
environment variables, or patches not captured in the repository
3. **React Native + Hermes complexity** — The Boost/Hermes build chain has fragile network
dependencies and platform-specific extraction logic
4. **ProGuard/R8 non-determinism** — Even if the build succeeds, R8 obfuscation typically produces
non-deterministic DEX bytecode unless specific flags are used

## 💡 Recommendations

We'd love to work with you toward reproducible builds. Here are some suggestions:

### 1. Publish Reproducible Build Instructions

A `BUILDING.md` or section in the README documenting:
- Exact Node.js, Yarn, JDK, and Android SDK versions
- Required environment variables (e.g., `METAMASK_BUILD_TYPE`, `METAMASK_ENVIRONMENT`)
- Any CI-specific gradle.properties or patches
- How to obtain/generate `google-services.json` for Firebase (or document that it's optional)

### 2. Pin Hermes/Boost Dependencies

The Boost tarball download is fragile. Consider:
- Vendoring Boost in the repo or using a checksum-verified mirror
- Documenting the exact Boost version and download URL
- Using a prebuilt Hermes binary with known provenance

### 3. Address R8/ProGuard Determinism

For true reproducibility:
- Document whether `enableProguardInReleaseBuilds` should be true/false
- If enabled, provide the ProGuard mapping file or seed
- Consider using deterministic R8 flags if available

### 4. Publish Build Attestations

Even if byte-for-byte reproducibility is difficult, publishing:
- Git commit hash used for each release
- Build environment container image (e.g., Docker image digest)
- SHA-256 hashes of build artifacts

...would allow independent verification of the build chain.

## 📁 Our Work

We're happy to share our build script and detailed error logs if helpful. Our script handles:
- Containerized builds (Docker/Podman)
- AAB → split APK extraction via bundletool
- Per-split comparison with META-INF filtering
- YAML output for automation

## 🤝 Next Steps

We'd appreciate any guidance on:
1. Is there an internal build guide we might have missed?
2. Are there known issues with building from source?
3. Would the team be interested in collaborating on reproducible build support?

Thank you for building an open-source wallet! We're rooting for MetaMask to achieve reproducible
builds. 🦊

---

**WalletScrutiny Links:**
- Website: https://walletscrutiny.com
- MetaMask listing: https://walletscrutiny.com/android/io.metamask/
- Methodology: https://walletscrutiny.com/methodology/

**References:**
- MetaMask Mobile repo: https://github.com/MetaMask/metamask-mobile
- Reproducible Builds project: https://reproducible-builds.org/

### Scenario

_No response_

### Design

_No response_

### Technical Details

_No response_

### Threat Modeling Framework

_No response_

### Acceptance Criteria

_No response_

### Stakeholder review needed before the work gets merged

- [ ] Engineering (needed in most cases)
- [ ] Design
- [ ] Product
- [ ] QA (automation tests are required to pass before merging PRs but not all changes are covered by automation tests - please review if QA is needed beyond automation tests)
- [ ] Security
- [ ] Legal
- [ ] Marketing
- [ ] Management (please specify)
- [x] Other (please specify)

### References

_No response_

Contributor guide

Open the contributing guide

Research direction

Begin with ./gradlew bundleProdRelease and the :react-native:prepareBoost failure, using the listed SDK, NDK, JDK, Node.js and Yarn versions. Review the build configuration around Hermes/Boost and the sentry.gradle handling mentioned in the issue. Done means the source build path is documented and the build can be reproduced and compared with the Play Store artifacts.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, docker, node.js, react-native
Domain
build-system, documentation, mobile-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.