diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 107013e39cfb28daccd81bf4accb14fdc1b9d874..b75fa62e4dd84a0137600d9f71aa5c62a61b1b34 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,12 +24,14 @@ build: test_success: stage: test script: - - docker run ${TEST_IMAGE} ./reproduce.py release-1.0.1 + # Consider adding the cap and the device directly to the CI config + # https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-docker-section + - docker run --cap-add SYS_ADMIN --device /dev/fuse ${TEST_IMAGE} ./reproduce.py release-1.0.1 test_failure: stage: test script: - - if docker run ${TEST_IMAGE} ./reproduce.py release-1.0.3; then exit 1; else exit 0; fi + - if docker run --cap-add SYS_ADMIN --device /dev/fuse ${TEST_IMAGE} ./reproduce.py release-1.0.3; then exit 1; else exit 0; fi release: stage: release diff --git a/README.md b/README.md index 06b1f4e37e2c25fcf4dc14e5120f3a4062b90055..6019ef213d3153b82dd0367214915fd90894374e 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,22 @@ Build our Docker image: ### Run the verification +Currently, the verification needs `disorderfs` as a deterministic file-system. +Therefore, please make sure that `fuse` is installed on your host system. + + apt install fuse + To verify a specific version of Briar, run - docker run briar/reproducer:latest ./reproduce.py [tag] + docker run --cap-add SYS_ADMIN --device /dev/fuse briar/reproducer:latest ./reproduce.py [tag] Where `[tag]` is the git tag (source code snapshot) that identifies the version you want to test, for example `release-1.0.1`. You can find a list of tags in Briar's [source code repository](https://code.briarproject.org/akwizgran/briar/tags). + +The `SYS_ADMIN` capability and the `fuse` device are required, +so the container can build the app inside a `disorderfs`. +We hope to be able to drop this requirement +once this [upstream issue](https://issuetracker.google.com/issues/110237303) is fixed. \ No newline at end of file diff --git a/install-dependencies.sh b/install-dependencies.sh index 4afd8b4e6a41762e392540b3a9d49347280ee823..ef0574e5208985eb5e4f8b0089ce9f2fe2410f64 100755 --- a/install-dependencies.sh +++ b/install-dependencies.sh @@ -5,5 +5,7 @@ set -x apt-get install -y --no-install-recommends \ git \ default-jdk-headless \ + fuse \ + disorderfs \ unzip \ wget diff --git a/reproduce.py b/reproduce.py index c2479fc24ef3ad7e4e87813da030672246be19cb..e48eb00a25af63b8fff7a334a78e8dbc76468992 100755 --- a/reproduce.py +++ b/reproduce.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 import os -import subprocess +from subprocess import call, check_call, check_output import sys REPO_DIR = "briar" REFERENCE_URL = 'https://briarproject.org/apk/briar-%s.apk' GRADLE_TASK = "briar-android:assembleRelease" APK_PATH = "briar-android/build/outputs/apk/release/briar-android-release-unsigned.apk" +BUILD_DIR = "briar-build" def main(): @@ -22,14 +23,19 @@ def main(): version = tag.split('-')[1] url = REFERENCE_URL % version reference_apk = "briar-%s.apk" % version - subprocess.check_call(['wget', '--no-verbose', url, '-O', reference_apk]) + check_call(['wget', '--no-verbose', url, '-O', reference_apk]) + + # use deterministic file system for building the app + if not os.path.exists(BUILD_DIR): + os.makedirs(BUILD_DIR) + check_call(['disorderfs', '--sort-dirents=yes', '--reverse-dirents=no', REPO_DIR, BUILD_DIR]) # build the app - repo_call(["./gradlew", "--no-daemon", GRADLE_TASK]) + check_call(["./gradlew", "--no-daemon", GRADLE_TASK], cwd=BUILD_DIR) # check if both APKs match - apk = os.path.join(REPO_DIR, APK_PATH) - if subprocess.call(['./verify-apk.py', reference_apk, apk]) == 0: + apk = os.path.join(BUILD_DIR, APK_PATH) + if call(['./verify-apk.py', reference_apk, apk]) == 0: print("Version '%s' was built reproducible! :)" % tag) sys.exit(0) else: @@ -44,7 +50,7 @@ def prepare_repo(tag): repo_call(['git', 'checkout', '-f', 'master']) else: # clone repo - subprocess.check_call(['git', 'clone', os.environ.get("REPO_URL"), REPO_DIR]) + check_call(['git', 'clone', os.environ.get("REPO_URL"), REPO_DIR]) # undo all changes repo_call(['git', 'reset', '--hard']) @@ -54,7 +60,7 @@ def prepare_repo(tag): # use latest tag if none given if tag is None: - result = subprocess.check_output(['git', 'describe', '--abbrev=0', '--tags'], cwd=REPO_DIR) + result = check_output(['git', 'describe', '--abbrev=0', '--tags'], cwd=REPO_DIR) tag = result.decode().rstrip() # strip away line-break # checkout tag @@ -65,7 +71,7 @@ def prepare_repo(tag): def repo_call(command): - subprocess.check_call(command, cwd=REPO_DIR) + check_call(command, cwd=REPO_DIR) def fail(msg=""):