From 3d3f8360aeac65da638b754d31647f78a2272d61 Mon Sep 17 00:00:00 2001 From: sysadmin Date: Wed, 30 Sep 2026 21:56:03 +0100 Subject: [PATCH] fdroid-publish: find_tool must test its result (ls|tail exits 0 on no match) An empty SDK build-tools glob was reported as found, so the signer check ran nothing and refused a correctly signed APK with an empty signer. An unreadable signer now warns and defers to the host's pinned-cert check; only a real mismatch fails. Co-Authored-By: Claude Opus 5.5 --- fdroid-publish/publish.sh | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/fdroid-publish/publish.sh b/fdroid-publish/publish.sh index b42f047..a3f3776 100644 --- a/fdroid-publish/publish.sh +++ b/fdroid-publish/publish.sh @@ -54,17 +54,26 @@ find_tool() { # newest build-tools copy of $1 under the Android SDK, or PATH command -v "$1" 2>/dev/null && return 0 for sdk in "${ANDROID_HOME:-}" "${ANDROID_SDK_ROOT:-}" /opt/android-sdk /opt/android/sdk /usr/lib/android-sdk; do [ -n "$sdk" ] && [ -d "$sdk/build-tools" ] || continue - ls -d "$sdk"/build-tools/*/"$1" 2>/dev/null | sort -V | tail -n1 && return 0 + # Test the RESULT, not the pipeline: `ls … | tail` exits 0 even when ls found + # nothing, which once reported an empty path as found (empty signer → refusal). + p=$(ls -d "$sdk"/build-tools/*/"$1" 2>/dev/null | sort -V | tail -n1) + [ -n "$p" ] && [ -x "$p" ] && { printf '%s +' "$p"; return 0; } done return 1 } # Signer check before anything leaves the runner, so a mis-signed build fails # here with a clear message instead of as CERT_MISMATCH on the host. -if apksigner=$(find_tool apksigner); then - got=$("$apksigner" verify --print-certs "$apk" 2>/dev/null | sed -n 's/^Signer #1 certificate SHA-256 digest: //p' | head -n1 | tr 'A-F' 'a-f') - [ "$got" = "$cert" ] || fail "APK signer $got is not the pinned $app cert $cert — refusing to publish" - say "signer cert: OK ($cert)" +if apksigner=$(find_tool apksigner) && [ -n "$apksigner" ]; then + got=$("$apksigner" verify --print-certs "$apk" 2>/dev/null | sed -n 's/^Signer #1 certificate SHA-256 digest: //p' | head -n1 | tr 'A-F' 'a-f' || true) + if [ -z "$got" ]; then + say "::warning::apksigner at $apksigner printed no signer; the repo host verifies the cert" + elif [ "$got" != "$cert" ]; then + fail "APK signer $got is not the pinned $app cert $cert — refusing to publish" + else + say "signer cert: OK ($cert)" + fi else say "signer cert: apksigner not found here; the repo host verifies it" fi @@ -72,7 +81,7 @@ fi if [ -z "$version_code" ]; then # Needed for the no-downgrade guard below. A bare runner image (the promote # workflow's) has no Android SDK, so fetch Debian's aapt rather than guess. - if ! aapt=$(find_tool aapt2 || find_tool aapt); then + if ! aapt=$(find_tool aapt2 || find_tool aapt) || [ -z "$aapt" ]; then SUDO=; [ "$(id -u)" -eq 0 ] || SUDO=sudo { $SUDO apt-get update -qq && $SUDO apt-get install -y -qq aapt; } >/dev/null 2>&1 || true aapt=$(command -v aapt || true)