test-kepr-build-helpers.sh

5.8 KB · raw

1#!/bin/sh2# Hermetic negative-path tests for the sourceable Kepr release-gate helpers.3# No Android SDK, Gradle project, signing key, network, or APK is required.4set -eu56SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)7# shellcheck source=scripts/kepr-build-helpers.sh8. "$SCRIPT_DIR/kepr-build-helpers.sh"910TEMP_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/peach-kepr-helper-tests.XXXXXX")11trap 'trash "$TEMP_ROOT"' EXIT HUP INT TERM1213fail() {14    printf 'FAIL: %s\n' "$1" >&215    exit 116}1718expect_failure() {19    if "$@"; then20        fail "expected failure: $*"21    fi22}2324touch_tools() {25    mkdir -p "$TEMP_ROOT/sdk/build-tools/$1"26    : > "$TEMP_ROOT/sdk/build-tools/$1/aapt2"27    chmod +x "$TEMP_ROOT/sdk/build-tools/$1/aapt2"28}2930touch_tools 34.0.031touch_tools 35.0.032touch_tools 35.1.0-preview33touch_tools 36.0.0-rc134touch_tools latest35touch_tools arbitrary3637selected=$(find_stable_build_tools_dir "$TEMP_ROOT/sdk")38[ "$selected" = "$TEMP_ROOT/sdk/build-tools/35.0.0" ] ||39    fail "stable build-tools selection chose '$selected'"40for rejected in latest 35.1.0-preview 36.0.0-rc1 arbitrary 35 35.0; do41    expect_failure is_stable_build_tools_basename "$rejected"42done4344printf '2.8.4\n' > "$TEMP_ROOT/VERSION"45[ "$(read_root_semver "$TEMP_ROOT/VERSION")" = "2.8.4" ] || fail "valid VERSION was rejected"46printf '2.8.4\n2.8.5\n' > "$TEMP_ROOT/VERSION.ambiguous"47expect_failure read_root_semver "$TEMP_ROOT/VERSION.ambiguous"48printf '2.8\n' > "$TEMP_ROOT/VERSION.malformed"49expect_failure read_root_semver "$TEMP_ROOT/VERSION.malformed"5051cat > "$TEMP_ROOT/metadata.json" <<'JSON'52{53  "applicationId": "com.peachpasswords",54  "elements": [55    {"versionCode": 240146, "versionName": "2.8.4", "outputFile": "app-arm64-v8a-release.apk"},56    {"versionCode": 240146, "versionName": "2.8.4", "outputFile": "app-x86_64-release.apk"}57  ]58}59JSON60printf "package: name='com.peachpasswords' versionCode='240146' versionName='2.8.4'\nnative-code: 'arm64-v8a'\n" > "$TEMP_ROOT/badging"61validate_release_metadata "$TEMP_ROOT/metadata.json" "$TEMP_ROOT/badging" 2.8.4 com.peachpasswords app-arm64-v8a-release.apk arm64-v8a6263printf '{"applicationId":"com.peachpasswords",' > "$TEMP_ROOT/metadata.malformed"64expect_failure validate_release_metadata "$TEMP_ROOT/metadata.malformed" "$TEMP_ROOT/badging" 2.8.4 com.peachpasswords app-arm64-v8a-release.apk arm64-v8a65cat > "$TEMP_ROOT/metadata.duplicate.json" <<'JSON'66{"applicationId":"com.peachpasswords","applicationId":"com.peachpasswords","elements":[{"versionCode":240146,"versionName":"2.8.4"}]}67JSON68expect_failure validate_release_metadata "$TEMP_ROOT/metadata.duplicate.json" "$TEMP_ROOT/badging" 2.8.4 com.peachpasswords app-arm64-v8a-release.apk arm64-v8a69cat > "$TEMP_ROOT/metadata.ambiguous.json" <<'JSON'70{"applicationId":"com.peachpasswords","elements":[{"versionCode":240146,"versionName":"2.8.4"},{"versionCode":240147,"versionName":"2.8.4"}]}71JSON72expect_failure validate_release_metadata "$TEMP_ROOT/metadata.ambiguous.json" "$TEMP_ROOT/badging" 2.8.4 com.peachpasswords app-release.apk arm64-v8a73expect_failure validate_release_metadata "$TEMP_ROOT/metadata.json" "$TEMP_ROOT/badging" 2.8.5 com.peachpasswords app-arm64-v8a-release.apk arm64-v8a74printf "package: name='com.peachpasswords' versionCode='240146' versionName='2.8.5'\n" > "$TEMP_ROOT/badging.mismatch"75printf "native-code: 'arm64-v8a'\n" >> "$TEMP_ROOT/badging.mismatch"76expect_failure validate_release_metadata "$TEMP_ROOT/metadata.json" "$TEMP_ROOT/badging.mismatch" 2.8.4 com.peachpasswords app-arm64-v8a-release.apk arm64-v8a77expect_failure validate_release_metadata "$TEMP_ROOT/metadata.json" "$TEMP_ROOT/badging" 2.8.4 com.peachpasswords app-arm64-v8a-release.apk x86_647879# PB-26-132: the publish path must compare the APK's signer certificate against80# the configured release keystore's certificate, because aapt2 badging reports81# no signature at all.82if [ ! -x "${JAVA_HOME:-}/bin/keytool" ]; then83    for candidate in \84        /opt/homebrew/opt/openjdk@17 \85        /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home86    do87        if [ -x "$candidate/bin/keytool" ]; then88            JAVA_HOME="$candidate"89            export JAVA_HOME90            break91        fi92    done93fi94[ -x "${JAVA_HOME:-}/bin/keytool" ] ||95    fail "keytool not found; set JAVA_HOME to exercise the signing-identity helpers"9697"$JAVA_HOME/bin/keytool" -genkeypair -alias peachtest -keyalg RSA -keysize 2048 \98    -dname "CN=Peach Test" -validity 2 -keystore "$TEMP_ROOT/test.p12" \99    -storetype PKCS12 -storepass testpass -keypass testpass >/dev/null 2>&1100101keystore_digest=$(release_certificate_sha256 "$TEMP_ROOT/test.p12" testpass peachtest)102[ "${#keystore_digest}" -eq 64 ] ||103    fail "keystore certificate digest was not extracted: '$keystore_digest'"104105cat > "$TEMP_ROOT/apksigner" <<EOF106#!/bin/sh107printf 'Signer #1 certificate DN: CN=Peach Test\n'108printf 'Signer #1 certificate SHA-256 digest: $keystore_digest\n'109printf 'Signer #1 certificate SHA-1 digest: aa:bb:cc\n'110EOF111chmod +x "$TEMP_ROOT/apksigner"112113apk_digest=$(apk_signer_sha256 "$TEMP_ROOT/apksigner" "$TEMP_ROOT/ignored.apk")114[ "$apk_digest" = "$keystore_digest" ] ||115    fail "APK signer digest was not extracted: '$apk_digest'"116117assert_release_signer_matches "$keystore_digest" "$apk_digest" "test.apk"118different_digest=$(printf 'ab%.0s' 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)119expect_failure assert_release_signer_matches "$keystore_digest" "$different_digest" "test.apk"120expect_failure assert_release_signer_matches "" "$apk_digest" "test.apk"121expect_failure assert_release_signer_matches "$keystore_digest" "" "test.apk"122expect_failure assert_established_release_certificate "$keystore_digest"123assert_established_release_certificate "e10b975178f0bee7fb5a4802519da70ec2988b6ef7d8c9401fbbcff5a1137668"124125printf 'PASS: stable tool selection, malformed/ambiguous metadata, semantic-version mismatch, and signing-identity gates\n'