summaryrefslogtreecommitdiffhomepage
path: root/.github/workflows/android-reproducible-builds.yml
blob: 6381690c8a17e73e8c10386c17bd70872b06e332 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
---
name: Android - Verify F-Droid and reproducible builds
on:
  schedule:
    # At 04:20 UTC every monday.
    # Notifications for scheduled workflows are sent to the user who last modified the cron
    # syntax in the workflow file. If you update this you must have notifications for
    # Github Actions enabled, so these don't go unnoticed.
    # https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/notifications-for-workflow-runs
    - cron: '20 6 * * 1'
  workflow_dispatch:
    inputs:
      commit_hash:
        type: string
        required: false
  pull_request:
    paths:
      - '.github/workflows/android-reproducible-builds.yml'
      - 'building/android-container-image.txt'
      - 'dist-assets/android-version*'
      - 'android/src/main/play/release-notes/en-US/default.txt'
      - 'android/gradle/**'
      - 'android/flake*'
  push:
    tags:
      - 'android/**'

permissions: {}

jobs:
  set-up-env:
    name: Setup commit hash
    runs-on: ubuntu-latest
    steps:
      - id: hash
        name: Set commit hash or default to github.sha
        run: |
          # If the input has a value, it is filled by that value; otherwise, fallback to PR sha.
          # If it is not triggered by a PR, use github.sha.
          if [ -n "${{ inputs.commit_hash }}" ]; then
            echo "commit_hash=${{ inputs.commit_hash }}" >> "$GITHUB_OUTPUT"
          else
            echo "commit_hash=${{ github.event.pull_request.head.sha || github.sha }}" >> "$GITHUB_OUTPUT"
          fi
    outputs:
      COMMIT_HASH: ${{ steps.hash.outputs.commit_hash }}

  build-using-container:
    name: Build fdroid variant using container
    runs-on: ubuntu-latest
    needs: set-up-env
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.set-up-env.outputs.COMMIT_HASH }}
          submodules: true

      - name: Fetch submodules and tags
        run: |
          git submodule update --init wireguard-go-rs/libwg/wireguard-go
          git fetch --no-tags origin 'refs/tags/android/*:refs/tags/android/*'

      - name: Build app
        run: ./building/containerized-build.sh android --fdroid

      - name: Upload apks
        uses: actions/upload-artifact@v4
        with:
          name: apk-container
          path: android/app/build/outputs/apk/ossProd/fdroid/app-oss-prod-fdroid-unsigned.apk
          if-no-files-found: error
          retention-days: 7

  build-using-fdroidserver:
    name: Build fdroid variant using fdroidserver
    runs-on: ubuntu-latest
    needs: set-up-env
    steps:
      - name: Install fdroidserver
        run: |
          sudo apt-get -y update
          sudo apt-get -y install fdroidserver

      - name: Check out gradle properties
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.set-up-env.outputs.COMMIT_HASH }}
          path: app-gradle
          sparse-checkout: |
            android/gradle/wrapper/gradle-wrapper.properties
          sparse-checkout-cone-mode: false

      - name: Extract gradle version
        run: |
          echo "gradle_version=\
          $(grep -oP 'gradle-\K[0-9]+\.[0-9]+\.[0-9]+' app-gradle/android/gradle/wrapper/gradle-wrapper.properties)" \
          >> $GITHUB_ENV

      - name: Install gradle
        run: |
          sudo apt-get -y remove gradle
          mkdir /opt/gradle
          curl -sfLo /opt/gradle/gradle-${{ env.gradle_version }}-bin.zip \
          https\://services.gradle.org/distributions/gradle-${{ env.gradle_version }}-bin.zip
          unzip -d /opt/gradle /opt/gradle/gradle-${{ env.gradle_version }}-bin.zip

      # These are equivalent to the sudo section of the metadata file
      - name: Install dependencies
        run: sudo apt-get install -y build-essential protobuf-compiler libprotobuf-dev

      - name: Init fdroid
        run: fdroid init

      - name: Check out metadata
        uses: actions/checkout@v4
        with:
          path: app-metadata
          sparse-checkout: |
            android/fdroid-build/metadata/net.mullvad.mullvadvpn.yml
          sparse-checkout-cone-mode: false

      - name: Prepare metadata
        run: |
          mkdir metadata
          cp app-metadata/android/fdroid-build/metadata/net.mullvad.mullvadvpn.yml metadata/net.mullvad.mullvadvpn.yml
          sed -i 's/commit-hash/${{ needs.set-up-env.outputs.COMMIT_HASH }}/' metadata/net.mullvad.mullvadvpn.yml

      - name: Build app
        run: |
          export PATH=$PATH:/opt/gradle/gradle-${{ env.gradle_version }}/bin
          fdroid build net.mullvad.mullvadvpn:1

      - name: Upload apks
        uses: actions/upload-artifact@v4
        with:
          name: apk-fdroidserver
          path: |
            build/net\.mullvad\.mullvadvpn/android/app/build/outputs/apk/ossProd/fdroid/app-oss-prod-fdroid-unsigned.apk
          if-no-files-found: error
          retention-days: 7

  build-using-nix:
    name: Build fdroid variant using nix
    runs-on: ${{ matrix.runs-on }}
    needs: set-up-env
    strategy:
      fail-fast: false
      matrix:
        include:
          - runs-on: ubuntu-latest
          - runs-on: macos-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.set-up-env.outputs.COMMIT_HASH }}
          submodules: true

      - name: Fetch submodules and tags
        run: |
          git submodule update --init wireguard-go-rs/libwg/wireguard-go
          git fetch --no-tags origin 'refs/tags/android/*:refs/tags/android/*'

      - uses: cachix/install-nix-action@v31
        with:
          nix_path: nixpkgs=channel:nixos-unstable

      - name: Build app
        working-directory: android
        run: nix develop -c ./gradlew assembleOssProdFdroid

      - name: Upload apks
        uses: actions/upload-artifact@v4
        with:
          name: apk-nix-${{ matrix.runs-on }}
          path: android/app/build/outputs/apk/ossProd/fdroid/app-oss-prod-fdroid-unsigned.apk
          if-no-files-found: error
          retention-days: 7

  compare-builds:
    name: Check builds
    runs-on: ubuntu-latest
    needs: [build-using-container, build-using-fdroidserver, build-using-nix]
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
          pattern: apk-*
          merge-multiple: false

      - name: Print checksums
        working-directory: ./artifacts
        run: sha256sum */*

      - name: Compare files
        working-directory: ./artifacts
        run: diff apk-container/app-oss-prod-fdroid-unsigned.apk apk-fdroidserver/app-oss-prod-fdroid-unsigned.apk

  # Included in this workflow since it's the only place
  # release artifacts are built. Should eventually be moved.
  check-permissions:
    name: Check APK permissions
    runs-on: ubuntu-latest
    needs: [set-up-env, build-using-container]
    steps:
      - name: Install apktool
        run: sudo apt-get install -y apktool

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          ref: ${{ needs.set-up-env.outputs.COMMIT_HASH }}
          submodules: true

      - name: Download container apk
        uses: actions/download-artifact@v4
        with:
          name: apk-container

      - name: Extract resources
        run: |
          apktool d app-oss-prod-fdroid-unsigned.apk -s -o output

      - name: Compare manifest permissions with checked in snapshot
        run: |
          diff android/snapshot/manifest-permissions-oss.txt <(cat output/AndroidManifest.xml | grep uses-permission)