From 0f88f2c1e5e108021ccddeee24f1216107115791 Mon Sep 17 00:00:00 2001 From: Lena Date: Wed, 1 Jul 2026 00:00:00 +0000 Subject: build: verify release inputs Pin and verify what goes into a release: JitPack confined to the SPAKE2 module via exclusiveContent, the vendored subtree pulled by commit SHA instead of a mutable tag, a pinned Docker base digest with a checksummed cmdline-tools download, and a verifyScrcpyServer task wired into every assets merge. The expected server checksum can be overridden with -PscrcpyServerSha256 when the jar is built from source. build-apk now requires apksigner and fails unless independent signature verification succeeds. Split the test image into unit and e2e targets so JVM-only test runs do not download an emulator. Ship THIRD_PARTY_NOTICES and the LGPL text for SPAKE2 in the APK. Add scripts/check as the host quality gate. --- scripts/build-apk | 29 +++++++++++++++-------------- scripts/check | 10 ++++++++++ scripts/check-server | 39 +++++++++++++++++++++++++++++++++++++++ scripts/check-wrapper | 2 +- scripts/fetch-vendor | 4 ++-- 5 files changed, 67 insertions(+), 17 deletions(-) create mode 100755 scripts/check create mode 100755 scripts/check-server (limited to 'scripts') diff --git a/scripts/build-apk b/scripts/build-apk index 9fd1409..476731b 100755 --- a/scripts/build-apk +++ b/scripts/build-apk @@ -7,10 +7,8 @@ # KEY_ALIAS alias of the signing key inside the keystore # KEY_PASS password for that key (often the same as KEYSTORE_PASS) # -# Optional: -# ANDROID_SDK_ROOT if set, apksigner is located via this; otherwise -# the script trusts gradle's output and skips the -# post-build verification step. +# Required tooling: +# Android build-tools 35.0.0 apksigner under ANDROID_SDK_ROOT or on PATH. # # Usage: # scripts/build-apk @@ -49,11 +47,8 @@ if [ ! -f "$KEYSTORE_PATH" ]; then exit 1 fi -if [ ! -f "$JAR" ]; then - echo "build-apk: $JAR is missing" >&2 - echo " run scripts/update-server first" >&2 - exit 1 -fi +"$ROOT/scripts/check-wrapper" +"$ROOT/scripts/check-server" echo "build-apk: gradle :app:assembleRelease" cd "$ROOT" @@ -66,18 +61,24 @@ fi SUM=$(sha256sum "$APK" | awk '{print $1}') -# Best-effort: if apksigner is reachable, confirm the signature. APKSIGNER="" if [ -n "${ANDROID_SDK_ROOT:-}" ]; then - APKSIGNER=$(ls "$ANDROID_SDK_ROOT"/build-tools/*/apksigner 2>/dev/null | sort | tail -n 1 || true) + APKSIGNER="$ANDROID_SDK_ROOT/build-tools/35.0.0/apksigner" + if [ ! -x "$APKSIGNER" ]; then + APKSIGNER="" + fi fi if [ -z "$APKSIGNER" ] && command -v apksigner >/dev/null 2>&1; then APKSIGNER=$(command -v apksigner) fi -if [ -n "$APKSIGNER" ]; then - echo "build-apk: apksigner verify" - "$APKSIGNER" verify --verbose "$APK" | sed 's/^/ /' +if [ -z "$APKSIGNER" ]; then + echo "build-apk: apksigner 35.0.0 is required" >&2 + echo " set ANDROID_SDK_ROOT or put apksigner on PATH" >&2 + exit 1 fi +echo "build-apk: apksigner verify" +"$APKSIGNER" verify --verbose --print-certs "$APK" | sed 's/^/ /' + echo "build-apk: $APK" echo "build-apk: sha256 $SUM" diff --git a/scripts/check b/scripts/check new file mode 100755 index 0000000..6886411 --- /dev/null +++ b/scripts/check @@ -0,0 +1,10 @@ +#!/bin/sh +# Run the repository's host/VM quality gate. + +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" + +"$ROOT/scripts/check-wrapper" +"$ROOT/scripts/check-server" +"$ROOT/gradlew" --no-daemon :app:test :adb:test :app:lint diff --git a/scripts/check-server b/scripts/check-server new file mode 100755 index 0000000..9a895a1 --- /dev/null +++ b/scripts/check-server @@ -0,0 +1,39 @@ +#!/bin/sh +# Verify the scrcpy server asset against its tracked SHA-256 sidecar. + +set -eu + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +ASSETS="$ROOT/app/src/main/assets" +JAR="$ASSETS/scrcpy-server.jar" +SUM="$ASSETS/scrcpy-server.sha256" +VERSION="$ASSETS/scrcpy-server.version" + +for file in "$JAR" "$SUM" "$VERSION"; do + if [ ! -s "$file" ]; then + echo "check-server: $file is missing or empty" >&2 + exit 1 + fi +done + +expected=$(awk 'NR == 1 { print $1 }' "$SUM") +case "$expected" in + *[!0-9a-f]*|'') + echo "check-server: invalid SHA-256 in $SUM" >&2 + exit 1 + ;; +esac +if [ "${#expected}" -ne 64 ]; then + echo "check-server: invalid SHA-256 length in $SUM" >&2 + exit 1 +fi + +actual=$(sha256sum "$JAR" | awk '{ print $1 }') +if [ "$actual" != "$expected" ]; then + echo "check-server: scrcpy-server.jar checksum mismatch" >&2 + echo " want: $expected" >&2 + echo " got: $actual" >&2 + exit 1 +fi + +echo "check-server: ok ($(cat "$VERSION"))" diff --git a/scripts/check-wrapper b/scripts/check-wrapper index 31531b6..3997bed 100755 --- a/scripts/check-wrapper +++ b/scripts/check-wrapper @@ -4,7 +4,7 @@ set -eu -cd "$(git rev-parse --show-toplevel)" +cd "$(cd "$(dirname "$0")/.." && pwd)" WRAPPER='gradle/wrapper/gradle-wrapper.jar' EXPECTED_FILE="$WRAPPER.sha256" diff --git a/scripts/fetch-vendor b/scripts/fetch-vendor index 4c73381..1e3ae59 100755 --- a/scripts/fetch-vendor +++ b/scripts/fetch-vendor @@ -35,10 +35,10 @@ fi if [ ! -d "$LIBADB_PREFIX" ]; then echo "fetch-vendor: adding $LIBADB_PREFIX @ $LIBADB_TAG ($LIBADB_SHA)" - git subtree add --prefix="$LIBADB_PREFIX" "$LIBADB_REPO" "$LIBADB_TAG" --squash + git subtree add --prefix="$LIBADB_PREFIX" "$LIBADB_REPO" "$LIBADB_SHA" --squash else echo "fetch-vendor: pulling $LIBADB_PREFIX @ $LIBADB_TAG ($LIBADB_SHA)" - git subtree pull --prefix="$LIBADB_PREFIX" "$LIBADB_REPO" "$LIBADB_TAG" --squash + git subtree pull --prefix="$LIBADB_PREFIX" "$LIBADB_REPO" "$LIBADB_SHA" --squash fi echo "fetch-vendor: ok" -- cgit v1.2.3