test(android): bind artifacts to source state

This commit is contained in:
SimpleTest 2026-07-24 11:04:06 +03:00
parent 7b09becc09
commit 7cdf5ab4eb
9 changed files with 145 additions and 5 deletions

View File

@ -48,8 +48,8 @@ public final class CrossClientStagingInstrumentedTest {
waitForElement("remember-login-button"); waitForElement("remember-login-button");
click("remember-login-button"); click("remember-login-button");
waitForElementText( waitForElementText(
"main-content", "home-title",
"Help can be closer than you think." "Need help nearby? Ask the community."
); );
} }

View File

@ -41,6 +41,12 @@ browser_image="who-need-help-e2e-tests:android-$run_id"
android_image="who-need-help-android:$variant-cross-client-$run_id" android_image="who-need-help-android:$variant-cross-client-$run_id"
container="who-need-help-android-$variant-cross-client-$run_id" container="who-need-help-android-$variant-cross-client-$run_id"
avd_volume="who-need-help-android-avd-$variant-cross-client-$run_id" avd_volume="who-need-help-android-avd-$variant-cross-client-$run_id"
# Android's Automated Test Device image removes applications and background
# services that are unrelated to app-level automation. Keep the API 37/16 KB
# compatibility coverage in the instrumentation matrix and public smoke test;
# use the Google ATD image for this resource-intensive two-client workflow.
android_api=35
android_system_image=system-images/android-35/google_atd/x86_64
service_class=org.whoneedhelp.mobile.TrackingService service_class=org.whoneedhelp.mobile.TrackingService
fixture_password="$(openssl rand -hex 24)" fixture_password="$(openssl rand -hex 24)"
android_message="android-$run_id" android_message="android-$run_id"
@ -123,6 +129,10 @@ if [[ ! -s "$TEST_APK" ]]; then
exit 1 exit 1
fi fi
"$ROOT/scripts/verify-android-artifact-source.sh" \
"$ROOT/android/dist-$variant" \
"$build_script"
set -a set -a
# shellcheck source=/dev/null # shellcheck source=/dev/null
. "$ENV_FILE" . "$ENV_FILE"
@ -645,8 +655,7 @@ docker build \
--build-arg "WNH_DEBUG_BASE_URL=$WNH_BASE_URL" \ --build-arg "WNH_DEBUG_BASE_URL=$WNH_BASE_URL" \
--build-arg "WNH_TRACKING_MIN_TIME_MS=$WNH_TRACKING_MIN_TIME_MS" \ --build-arg "WNH_TRACKING_MIN_TIME_MS=$WNH_TRACKING_MIN_TIME_MS" \
--build-arg "WNH_TRACKING_HTTP_TIMEOUT_MS=$WNH_TRACKING_HTTP_TIMEOUT_MS" \ --build-arg "WNH_TRACKING_HTTP_TIMEOUT_MS=$WNH_TRACKING_HTTP_TIMEOUT_MS" \
--build-arg \ --build-arg "ANDROID_EMULATOR_SYSTEM_IMAGE=$android_system_image" \
"ANDROID_EMULATOR_SYSTEM_IMAGE=system-images/android-37.0/google_apis_ps16k/x86_64" \
--target emulator \ --target emulator \
--tag "$android_image" \ --tag "$android_image" \
android >"$output_dir/android-image-build.log" android >"$output_dir/android-image-build.log"
@ -808,7 +817,8 @@ fi
{ {
printf 'run_id=%s\n' "$run_id" printf 'run_id=%s\n' "$run_id"
printf 'android_api=37.0\n' printf 'android_api=%s\n' "$android_api"
printf 'android_system_image=%s\n' "$android_system_image"
printf 'package=%s\n' "$package" printf 'package=%s\n' "$package"
printf 'public_origin=%s\n' "$WNH_BASE_URL" printf 'public_origin=%s\n' "$WNH_BASE_URL"
printf 'magic_link_login=true\n' printf 'magic_link_login=true\n'

View File

@ -58,6 +58,9 @@ docker build \
--output "type=local,dest=$ROOT/android/dist-development" \ --output "type=local,dest=$ROOT/android/dist-development" \
"$ROOT/android" "$ROOT/android"
"$ROOT/scripts/android-source-fingerprint.sh" \
>"$ROOT/android/dist-development/source-fingerprint.sha256"
"$ROOT/scripts/android-app-links-verify.sh" \ "$ROOT/scripts/android-app-links-verify.sh" \
"$ENV_FILE" \ "$ENV_FILE" \
"$ROOT/android/dist-development" \ "$ROOT/android/dist-development" \

View File

@ -72,6 +72,9 @@ docker build \
--output "type=local,dest=$OUTPUT_DIR" \ --output "type=local,dest=$OUTPUT_DIR" \
"$ROOT/android" "$ROOT/android"
"$ROOT/scripts/android-source-fingerprint.sh" \
>"$OUTPUT_DIR/source-fingerprint.sha256"
for artifact in \ for artifact in \
"$OUTPUT_DIR/who-need-help-release.apk" \ "$OUTPUT_DIR/who-need-help-release.apk" \
"$OUTPUT_DIR/who-need-help-release.aab" \ "$OUTPUT_DIR/who-need-help-release.aab" \
@ -79,6 +82,7 @@ for artifact in \
"$OUTPUT_DIR/package-name.txt" \ "$OUTPUT_DIR/package-name.txt" \
"$OUTPUT_DIR/bundle-signing-verification.txt" \ "$OUTPUT_DIR/bundle-signing-verification.txt" \
"$OUTPUT_DIR/bundletool-validation.txt" \ "$OUTPUT_DIR/bundletool-validation.txt" \
"$OUTPUT_DIR/source-fingerprint.sha256" \
"$OUTPUT_DIR/lint-results-release.html"; do "$OUTPUT_DIR/lint-results-release.html"; do
if [ ! -s "$artifact" ]; then if [ ! -s "$artifact" ]; then
echo "Android release build did not export the expected artifact: $artifact" >&2 echo "Android release build did not export the expected artifact: $artifact" >&2

View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
mapfile -d '' -t source_files < <(
git -C "$ROOT" ls-files \
--cached \
--others \
--exclude-standard \
-z \
-- android |
LC_ALL=C sort -z
)
if [[ "${#source_files[@]}" -eq 0 ]]; then
echo "No Android source files were found." >&2
exit 1
fi
{
for relative_path in "${source_files[@]}"; do
absolute_path="$ROOT/$relative_path"
if [[ ! -f "$absolute_path" ]]; then
echo "Android source input is not a regular file: $relative_path" >&2
exit 1
fi
printf '%s\0' "$relative_path"
sha256sum "$absolute_path" | awk '{print $1}'
done
} | sha256sum | awk '{print $1}'

View File

@ -59,6 +59,9 @@ docker build \
--output "type=local,dest=$ROOT/android/dist-staging" \ --output "type=local,dest=$ROOT/android/dist-staging" \
"$ROOT/android" "$ROOT/android"
"$ROOT/scripts/android-source-fingerprint.sh" \
>"$ROOT/android/dist-staging/source-fingerprint.sha256"
"$ROOT/scripts/android-app-links-verify.sh" \ "$ROOT/scripts/android-app-links-verify.sh" \
"$ENV_FILE" \ "$ENV_FILE" \
"$ROOT/android/dist-staging" \ "$ROOT/android/dist-staging" \

View File

@ -57,6 +57,10 @@ if [ ! -s "$TEST_APK" ]; then
exit 1 exit 1
fi fi
"$ROOT/scripts/verify-android-artifact-source.sh" \
"$ROOT/android/dist-$variant" \
"$build_script"
set -a set -a
# shellcheck source=/dev/null # shellcheck source=/dev/null
. "$ENV_FILE" . "$ENV_FILE"

View File

@ -30,6 +30,7 @@ socket_proxy_container="wnh-socket-proxy-audit-$run_id"
scan_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-quality-scan.XXXXXX") scan_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-quality-scan.XXXXXX")
scan_list="${scan_dir}.files" scan_list="${scan_dir}.files"
scan_tar="${scan_dir}.tar" scan_tar="${scan_dir}.tar"
android_fingerprint_probe="$ROOT/android/.quality-source-fingerprint-$run_id"
umask 077 umask 077
QUALITY_POSTGRES_USER="wnh_quality_$(openssl rand -hex 6)" QUALITY_POSTGRES_USER="wnh_quality_$(openssl rand -hex 6)"
@ -49,6 +50,7 @@ cleanup() {
"$boundary_mock_image" "$socket_proxy_image" "$postgis_image" \ "$boundary_mock_image" "$socket_proxy_image" "$postgis_image" \
"$caddy_image" "$traefik_image" \ "$caddy_image" "$traefik_image" \
>/dev/null 2>&1 || true >/dev/null 2>&1 || true
rm -f "$android_fingerprint_probe"
rm -rf "$scan_dir" "$scan_list" "$scan_tar" rm -rf "$scan_dir" "$scan_list" "$scan_tar"
} }
trap cleanup EXIT HUP INT TERM trap cleanup EXIT HUP INT TERM
@ -97,6 +99,47 @@ grep -Fx '/.runner' .dockerignore >/dev/null
grep -Fx '/act_runner' .dockerignore >/dev/null grep -Fx '/act_runner' .dockerignore >/dev/null
grep -Fx '/act_runner-data/' .dockerignore >/dev/null grep -Fx '/act_runner-data/' .dockerignore >/dev/null
echo "Checking Android artifacts are bound to their exact source tree"
android_fingerprint_before=$(./scripts/android-source-fingerprint.sh)
android_artifact_probe="$scan_dir/android-artifact"
mkdir "$android_artifact_probe"
printf '%s\n' "$android_fingerprint_before" \
>"$android_artifact_probe/source-fingerprint.sha256"
./scripts/verify-android-artifact-source.sh \
"$android_artifact_probe" \
scripts/android-development-build.sh >/dev/null
printf '%s\n' 'quality source mutation' >"$android_fingerprint_probe"
android_fingerprint_after=$(./scripts/android-source-fingerprint.sh)
if [ "$android_fingerprint_before" = "$android_fingerprint_after" ]; then
echo "Android source fingerprint did not change for a source mutation." >&2
exit 1
fi
if ./scripts/verify-android-artifact-source.sh \
"$android_artifact_probe" \
scripts/android-development-build.sh >/dev/null 2>&1; then
echo "Android artifact verifier accepted stale source inputs." >&2
exit 1
fi
rm -f "$android_fingerprint_probe"
test "$(./scripts/android-source-fingerprint.sh)" = "$android_fingerprint_before"
printf '%s\n' malformed >"$android_artifact_probe/source-fingerprint.sha256"
if ./scripts/verify-android-artifact-source.sh \
"$android_artifact_probe" \
scripts/android-development-build.sh >/dev/null 2>&1; then
echo "Android artifact verifier accepted a malformed fingerprint." >&2
exit 1
fi
rm -f "$android_artifact_probe/source-fingerprint.sha256"
if ./scripts/verify-android-artifact-source.sh \
"$android_artifact_probe" \
scripts/android-development-build.sh >/dev/null 2>&1; then
echo "Android artifact verifier accepted a missing fingerprint." >&2
exit 1
fi
unset android_fingerprint_before android_fingerprint_after
echo "Checking atomic environment credential imports" echo "Checking atomic environment credential imports"
credential_env="$scan_dir/credentials.env" credential_env="$scan_dir/credentials.env"
cp .env.example "$credential_env" cp .env.example "$credential_env"

View File

@ -0,0 +1,40 @@
#!/bin/sh
set -eu
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
artifact_dir=${1:-}
build_command=${2:-the matching Android build script}
if [ -z "$artifact_dir" ]; then
echo "usage: $0 ARTIFACT_DIR [BUILD_COMMAND]" >&2
exit 2
fi
case "$artifact_dir" in
/*) ;;
*) artifact_dir="$ROOT/$artifact_dir" ;;
esac
fingerprint_file="$artifact_dir/source-fingerprint.sha256"
if [ ! -s "$fingerprint_file" ]; then
echo "Android artifacts do not record their source fingerprint: $fingerprint_file" >&2
echo "Run $build_command before using these artifacts." >&2
exit 1
fi
expected=$(tr -d '\r\n' <"$fingerprint_file")
actual=$("$ROOT/scripts/android-source-fingerprint.sh")
if ! printf '%s\n' "$expected" | grep -Eq '^[0-9a-f]{64}$'; then
echo "Android artifact source fingerprint is malformed." >&2
exit 1
fi
if [ "$expected" != "$actual" ]; then
echo "Android artifacts are stale relative to the current Android source." >&2
echo "Run $build_command before smoke or cross-client testing." >&2
exit 1
fi
printf 'Verified Android artifact source fingerprint: %s\n' "$actual"