From 827653aa291e37ae63c0cfa1eee4fbaa20cea122 Mon Sep 17 00:00:00 2001 From: Lena Date: Sat, 1 Aug 2026 00:00:00 +0000 Subject: build: pin and verify release inputs --- scripts/build-apk | 87 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 16 deletions(-) (limited to 'scripts/build-apk') diff --git a/scripts/build-apk b/scripts/build-apk index 476731b..3040ee0 100755 --- a/scripts/build-apk +++ b/scripts/build-apk @@ -8,7 +8,7 @@ # KEY_PASS password for that key (often the same as KEYSTORE_PASS) # # Required tooling: -# Android build-tools 35.0.0 apksigner under ANDROID_SDK_ROOT or on PATH. +# Android build-tools 35.0.0 under ANDROID_SDK_ROOT or on PATH. # # Usage: # scripts/build-apk @@ -25,11 +25,10 @@ set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd)" APK="$ROOT/app/build/outputs/apk/release/app-release.apk" -JAR="$ROOT/app/src/main/assets/scrcpy-server.jar" require() { name="$1" - eval "val=\${$name:-}" + val="$2" if [ -z "$val" ]; then echo "build-apk: \$$name is not set" >&2 echo " see the header of $0 for the required environment" >&2 @@ -37,10 +36,10 @@ require() { fi } -require KEYSTORE_PATH -require KEYSTORE_PASS -require KEY_ALIAS -require KEY_PASS +require KEYSTORE_PATH "${KEYSTORE_PATH:-}" +require KEYSTORE_PASS "${KEYSTORE_PASS:-}" +require KEY_ALIAS "${KEY_ALIAS:-}" +require KEY_PASS "${KEY_PASS:-}" if [ ! -f "$KEYSTORE_PATH" ]; then echo "build-apk: keystore not found at $KEYSTORE_PATH" >&2 @@ -62,23 +61,79 @@ fi SUM=$(sha256sum "$APK" | awk '{print $1}') APKSIGNER="" -if [ -n "${ANDROID_SDK_ROOT:-}" ]; then - APKSIGNER="$ANDROID_SDK_ROOT/build-tools/35.0.0/apksigner" - if [ ! -x "$APKSIGNER" ]; then - APKSIGNER="" - fi +AAPT2="" +ZIPALIGN="" +SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" +if [ -n "$SDK_ROOT" ]; then + APKSIGNER="$SDK_ROOT/build-tools/35.0.0/apksigner" + AAPT2="$SDK_ROOT/build-tools/35.0.0/aapt2" + ZIPALIGN="$SDK_ROOT/build-tools/35.0.0/zipalign" + [ -x "$APKSIGNER" ] || APKSIGNER="" + [ -x "$AAPT2" ] || AAPT2="" + [ -x "$ZIPALIGN" ] || ZIPALIGN="" fi if [ -z "$APKSIGNER" ] && command -v apksigner >/dev/null 2>&1; then APKSIGNER=$(command -v apksigner) fi -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 +if [ -z "$AAPT2" ] && command -v aapt2 >/dev/null 2>&1; then + AAPT2=$(command -v aapt2) +fi +if [ -z "$ZIPALIGN" ] && command -v zipalign >/dev/null 2>&1; then + ZIPALIGN=$(command -v zipalign) +fi +if [ -z "$APKSIGNER" ] || [ -z "$AAPT2" ] || [ -z "$ZIPALIGN" ]; then + echo "build-apk: build-tools 35.0.0 are required" >&2 + echo " set ANDROID_SDK_ROOT or put apksigner, aapt2, and zipalign on PATH" >&2 exit 1 fi +# Capture rather than pipe: POSIX sh has no pipefail, so +# `apksigner verify | sed` reports sed's status and a rejected APK would +# sail past set -e and be announced below as if it were signed. echo "build-apk: apksigner verify" -"$APKSIGNER" verify --verbose --print-certs "$APK" | sed 's/^/ /' +if ! verify_out=$("$APKSIGNER" verify --verbose --print-certs "$APK" 2>&1); then + printf '%s\n' "$verify_out" >&2 + echo "build-apk: apksigner rejected $APK" >&2 + exit 1 +fi +printf '%s\n' "$verify_out" | sed 's/^/ /' + +"$ZIPALIGN" -c -P 16 4 "$APK" + +expected_permissions=$(cat <&2 + printf '%s\n' "$actual_permissions" >&2 + exit 1 +fi + +expected_sdk=$(cat <&2 + printf '%s\n' "$actual_sdk" >&2 + exit 1 +fi + +expected_abis="native-code: 'arm64-v8a' 'x86_64'" +actual_abis=$("$AAPT2" dump badging "$APK" | sed -n '/^native-code:/p') +if [ "$actual_abis" != "$expected_abis" ]; then + echo "build-apk: unexpected release ABIs: $actual_abis" >&2 + exit 1 +fi echo "build-apk: $APK" echo "build-apk: sha256 $SUM" -- cgit v1.2.3