Prepare pre-Play production application release

This commit is contained in:
SimpleTest 2026-07-27 02:35:27 +03:00
parent 41011fe65c
commit 6c14531da3
13 changed files with 191 additions and 43 deletions

View File

@ -165,6 +165,7 @@ ARG WNH_FIREBASE_PROJECT_ID
ARG WNH_FIREBASE_GCM_SENDER_ID ARG WNH_FIREBASE_GCM_SENDER_ID
ARG WNH_PUBLIC_BUILD_TYPE ARG WNH_PUBLIC_BUILD_TYPE
ARG WNH_EXPECTED_APPLICATION_ID ARG WNH_EXPECTED_APPLICATION_ID
ARG WNH_SIGNING_CERT_SHA256
RUN --mount=type=cache,target=/home/gradle/.gradle,uid=1000,gid=1000 \ RUN --mount=type=cache,target=/home/gradle/.gradle,uid=1000,gid=1000 \
--mount=type=cache,target=/home/gradle/.android,uid=1000,gid=1000 \ --mount=type=cache,target=/home/gradle/.android,uid=1000,gid=1000 \
@ -177,6 +178,7 @@ RUN --mount=type=cache,target=/home/gradle/.gradle,uid=1000,gid=1000 \
*) echo "WNH_PUBLIC_BUILD_TYPE must be development or staging" >&2; exit 1 ;; \ *) echo "WNH_PUBLIC_BUILD_TYPE must be development or staging" >&2; exit 1 ;; \
esac \ esac \
&& test -n "${WNH_EXPECTED_APPLICATION_ID}" \ && test -n "${WNH_EXPECTED_APPLICATION_ID}" \
&& test -n "${WNH_SIGNING_CERT_SHA256}" \
&& WNH_ANDROID_SIGNING_STORE_FILE=/run/secrets/android_nonproduction_keystore \ && WNH_ANDROID_SIGNING_STORE_FILE=/run/secrets/android_nonproduction_keystore \
WNH_ANDROID_SIGNING_PASSWORD_FILE=/run/secrets/android_nonproduction_password \ WNH_ANDROID_SIGNING_PASSWORD_FILE=/run/secrets/android_nonproduction_password \
gradle --no-daemon \ gradle --no-daemon \
@ -256,13 +258,15 @@ ARG WNH_FIREBASE_APPLICATION_ID
ARG WNH_FIREBASE_CLIENT_VALUE ARG WNH_FIREBASE_CLIENT_VALUE
ARG WNH_FIREBASE_PROJECT_ID ARG WNH_FIREBASE_PROJECT_ID
ARG WNH_FIREBASE_GCM_SENDER_ID ARG WNH_FIREBASE_GCM_SENDER_ID
ARG WNH_SIGNING_CERT_SHA256
RUN --mount=type=cache,target=/home/gradle/.gradle,uid=1000,gid=1000 \ RUN --mount=type=cache,target=/home/gradle/.gradle,uid=1000,gid=1000 \
--mount=type=cache,target=/home/gradle/.android,uid=1000,gid=1000 \ --mount=type=cache,target=/home/gradle/.android,uid=1000,gid=1000 \
--mount=type=secret,id=android_upload_keystore,required=true,uid=1000,gid=1000,mode=0400 \ --mount=type=secret,id=android_upload_keystore,required=true,uid=1000,gid=1000,mode=0400 \
--mount=type=secret,id=android_upload_password,required=true,uid=1000,gid=1000,mode=0400 \ --mount=type=secret,id=android_upload_password,required=true,uid=1000,gid=1000,mode=0400 \
--mount=type=secret,id=android_upload_alias,required=true,env=WNH_ANDROID_SIGNING_KEY_ALIAS \ --mount=type=secret,id=android_upload_alias,required=true,env=WNH_ANDROID_SIGNING_KEY_ALIAS \
WNH_ANDROID_SIGNING_STORE_FILE=/run/secrets/android_upload_keystore \ test -n "${WNH_SIGNING_CERT_SHA256}" \
&& WNH_ANDROID_SIGNING_STORE_FILE=/run/secrets/android_upload_keystore \
WNH_ANDROID_SIGNING_PASSWORD_FILE=/run/secrets/android_upload_password \ WNH_ANDROID_SIGNING_PASSWORD_FILE=/run/secrets/android_upload_password \
gradle --no-daemon \ gradle --no-daemon \
"-PWNH_BASE_URL=${WNH_BASE_URL}" \ "-PWNH_BASE_URL=${WNH_BASE_URL}" \

View File

@ -174,6 +174,16 @@ ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS=PLAY_APP_SIGNING_SHA256
Run `./scripts/android-release-build.sh` from that production release checkout. Run `./scripts/android-release-build.sh` from that production release checkout.
It produces an APK, Play AAB, package report, signing report, and lint report. It produces an APK, Play AAB, package report, signing report, and lint report.
Before the Play application exists, the build may use only the upload
certificate in `ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS` and leave
`ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS` empty. This is sufficient
to create the first signed AAB, but `check-environment-readiness.sh
--require-release` intentionally continues to report the Play identity as
missing. Application-only server releases use
`--require-server-release` plus the production validator's
`--allow-pre-play` mode: they accept this upload-certificate-only state while
continuing to reject every other missing production capability. These modes do
not make an Android build ready for Google Play.
After Play App Signing is enabled, add the Play signing certificate fingerprint After Play App Signing is enabled, add the Play signing certificate fingerprint
to the comma-separated App Links value; the upload certificate alone does not to the comma-separated App Links value; the upload certificate alone does not
describe Play-delivered APKs. Record the same Play fingerprint separately in describe Play-delivered APKs. Record the same Play fingerprint separately in
@ -942,8 +952,12 @@ verified Git bundle and transferred directly over SSH to only
The default `plan` action is read-only. It verifies the exact local and remote The default `plan` action is read-only. It verifies the exact local and remote
commits, requires a fast-forward history, checks the production checkout, commits, requires a fast-forward history, checks the production checkout,
Compose scope and healthy containers, checks public readiness, opens a Compose scope and healthy containers, checks public readiness, opens a
read-only PostgreSQL connection, and runs the complete environment capability read-only PostgreSQL connection, and runs the server-release environment
preflight. It neither uploads a bundle nor creates a backup. capability preflight. Before the first Google Play release, this preflight
allows only the absent Play App Signing certificate; the stricter
`check-environment-readiness.sh .env --require-release` remains the gate for
publishing Android through Google Play. The plan neither uploads a bundle nor
creates a backup.
After reviewing the exact commit printed by the plan, execution additionally After reviewing the exact commit printed by the plan, execution additionally
requires an explicit per-commit confirmation: requires an explicit per-commit confirmation:

View File

@ -39,10 +39,27 @@ for secret_file in "$KEYSTORE" "$PASSWORD_FILE"; do
esac esac
done done
SIGNING_CERT_SHA256=$(
keytool -list -v \
-storetype PKCS12 \
-keystore "$KEYSTORE" \
-storepass:file "$PASSWORD_FILE" \
-alias "$WNH_ANDROID_DEVELOPMENT_SIGNING_KEY_ALIAS" |
awk -F': ' '
/SHA256:/ {
print $2
found = 1
exit
}
END { if (!found) exit 1 }
'
)
docker build \ docker build \
--secret "id=android_nonproduction_keystore,src=$KEYSTORE" \ --secret "id=android_nonproduction_keystore,src=$KEYSTORE" \
--secret "id=android_nonproduction_password,src=$PASSWORD_FILE" \ --secret "id=android_nonproduction_password,src=$PASSWORD_FILE" \
--secret "id=android_nonproduction_alias,env=WNH_ANDROID_DEVELOPMENT_SIGNING_KEY_ALIAS" \ --secret "id=android_nonproduction_alias,env=WNH_ANDROID_DEVELOPMENT_SIGNING_KEY_ALIAS" \
--build-arg "WNH_SIGNING_CERT_SHA256=$SIGNING_CERT_SHA256" \
--build-arg "WNH_BASE_URL=$WNH_BASE_URL" \ --build-arg "WNH_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" \

View File

@ -50,6 +50,22 @@ for secret_file in "$KEYSTORE" "$PASSWORD_FILE"; do
esac esac
done done
SIGNING_CERT_SHA256=$(
keytool -list -v \
-storetype PKCS12 \
-keystore "$KEYSTORE" \
-storepass:file "$PASSWORD_FILE" \
-alias "$WNH_ANDROID_SIGNING_KEY_ALIAS" |
awk -F': ' '
/SHA256:/ {
print $2
found = 1
exit
}
END { if (!found) exit 1 }
'
)
case "$OUTPUT_DIR" in case "$OUTPUT_DIR" in
/*) ;; /*) ;;
*) OUTPUT_DIR="$ROOT/$OUTPUT_DIR" ;; *) OUTPUT_DIR="$ROOT/$OUTPUT_DIR" ;;
@ -59,6 +75,7 @@ docker build \
--secret "id=android_upload_keystore,src=$KEYSTORE" \ --secret "id=android_upload_keystore,src=$KEYSTORE" \
--secret "id=android_upload_password,src=$PASSWORD_FILE" \ --secret "id=android_upload_password,src=$PASSWORD_FILE" \
--secret "id=android_upload_alias,env=WNH_ANDROID_SIGNING_KEY_ALIAS" \ --secret "id=android_upload_alias,env=WNH_ANDROID_SIGNING_KEY_ALIAS" \
--build-arg "WNH_SIGNING_CERT_SHA256=$SIGNING_CERT_SHA256" \
--build-arg "WNH_BASE_URL=$WNH_BASE_URL" \ --build-arg "WNH_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" \

View File

@ -40,10 +40,27 @@ for secret_file in "$KEYSTORE" "$PASSWORD_FILE"; do
esac esac
done done
SIGNING_CERT_SHA256=$(
keytool -list -v \
-storetype PKCS12 \
-keystore "$KEYSTORE" \
-storepass:file "$PASSWORD_FILE" \
-alias "$WNH_ANDROID_STAGING_SIGNING_KEY_ALIAS" |
awk -F': ' '
/SHA256:/ {
print $2
found = 1
exit
}
END { if (!found) exit 1 }
'
)
docker build \ docker build \
--secret "id=android_nonproduction_keystore,src=$KEYSTORE" \ --secret "id=android_nonproduction_keystore,src=$KEYSTORE" \
--secret "id=android_nonproduction_password,src=$PASSWORD_FILE" \ --secret "id=android_nonproduction_password,src=$PASSWORD_FILE" \
--secret "id=android_nonproduction_alias,env=WNH_ANDROID_STAGING_SIGNING_KEY_ALIAS" \ --secret "id=android_nonproduction_alias,env=WNH_ANDROID_STAGING_SIGNING_KEY_ALIAS" \
--build-arg "WNH_SIGNING_CERT_SHA256=$SIGNING_CERT_SHA256" \
--build-arg "WNH_BASE_URL=$WNH_BASE_URL" \ --build-arg "WNH_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" \

View File

@ -9,8 +9,9 @@ if [[ "$env_file" != /* ]]; then
env_file="$ROOT/$env_file" env_file="$ROOT/$env_file"
fi fi
if [[ "$mode" != "" && "$mode" != "--require-release" ]]; then if [[ "$mode" != "" && "$mode" != "--require-release" &&
echo "Usage: $0 [ENV_FILE] [--require-release]" >&2 "$mode" != "--require-server-release" ]]; then
echo "Usage: $0 [ENV_FILE] [--require-release|--require-server-release]" >&2
exit 2 exit 2
fi fi
@ -301,7 +302,13 @@ elif all_set ANDROID_APP_LINKS_PACKAGE_NAME ANDROID_APP_LINKS_SHA256_CERT_FINGER
elif [[ "$deployment_env" != production ]]; then elif [[ "$deployment_env" != production ]]; then
ready "Android App Links" "package and signing fingerprints match this environment" ready "Android App Links" "package and signing fingerprints match this environment"
elif ! is_set ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS; then elif ! is_set ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS; then
missing "Android App Links" "production requires the Play App Signing SHA-256 fingerprint" if [[ "$mode" == "--require-server-release" ]]; then
ready "Android App Links" \
"pre-Play server release publishes the verified upload certificate"
else
missing "Android App Links" \
"production requires the Play App Signing SHA-256 fingerprint"
fi
elif ! valid_sha256_fingerprint_list \ elif ! valid_sha256_fingerprint_list \
"$(value ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)"; then "$(value ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS)"; then
invalid "Android App Links" "Play App Signing fingerprints are malformed" invalid "Android App Links" "Play App Signing fingerprints are malformed"
@ -367,6 +374,7 @@ fi
printf '\nEnvironment readiness: %d blocking item(s), %d local-only warning(s).\n' \ printf '\nEnvironment readiness: %d blocking item(s), %d local-only warning(s).\n' \
"$failures" "$warnings" "$failures" "$warnings"
if [[ "$mode" == "--require-release" && ($failures -ne 0 || $warnings -ne 0) ]]; then if [[ "$mode" =~ ^--require-(release|server-release)$ &&
($failures -ne 0 || $warnings -ne 0) ]]; then
exit 1 exit 1
fi fi

View File

@ -79,7 +79,8 @@ current_commit=$(git -C "$root" rev-parse --verify HEAD)
exit 2 exit 2
} }
"$root/scripts/validate-production-env.sh" "$env_file" "$expected_domain" >/dev/null "$root/scripts/validate-production-env.sh" \
"$env_file" "$expected_domain" --allow-pre-play >/dev/null
"$root/scripts/compose.sh" "$env_file" config --quiet "$root/scripts/compose.sh" "$env_file" config --quiet
case "$app_topology" in case "$app_topology" in
@ -295,10 +296,12 @@ else
git -C "$root" checkout --detach "$release_ref" git -C "$root" checkout --detach "$release_ref"
fi fi
"$root/scripts/set-deployment-revision.sh" "$env_file" "$root/scripts/set-deployment-revision.sh" "$env_file" --allow-pre-play
revision_changed=true revision_changed=true
"$root/scripts/validate-production-env.sh" "$env_file" "$expected_domain" "$root/scripts/validate-production-env.sh" \
"$root/scripts/check-environment-readiness.sh" "$env_file" --require-release "$env_file" "$expected_domain" --allow-pre-play
"$root/scripts/check-environment-readiness.sh" \
"$env_file" --require-server-release
"$root/scripts/compose.sh" "$env_file" build "${build_services[@]}" "$root/scripts/compose.sh" "$env_file" build "${build_services[@]}"

View File

@ -79,7 +79,7 @@ if ! ssh -o BatchMode=yes "$ssh_target" \
fi fi
if ! ssh -o BatchMode=yes "$ssh_target" \ if ! ssh -o BatchMode=yes "$ssh_target" \
"bash -s -- '$remote_root/.env' --require-release" \ "bash -s -- '$remote_root/.env' --require-server-release" \
<"$ROOT/scripts/check-environment-readiness.sh"; then <"$ROOT/scripts/check-environment-readiness.sh"; then
plan_failed=1 plan_failed=1
fi fi

View File

@ -109,7 +109,8 @@ public_origin=$(read_unique "$env_file" WNH_BASE_URL)
exit 2 exit 2
} }
"$root/scripts/validate-production-env.sh" "$env_file" "$expected_domain" >/dev/null "$root/scripts/validate-production-env.sh" \
"$env_file" "$expected_domain" --allow-pre-play >/dev/null
"$root/scripts/compose.sh" "$env_file" config --quiet "$root/scripts/compose.sh" "$env_file" config --quiet
previous_commit=$(read_unique "$manifest" previous_commit) previous_commit=$(read_unique "$manifest" previous_commit)

View File

@ -784,6 +784,10 @@ if ./scripts/check-environment-readiness.sh \
echo "Environment readiness accepted upload-only Android App Links." >&2 echo "Environment readiness accepted upload-only Android App Links." >&2
exit 1 exit 1
fi fi
./scripts/validate-production-env.sh \
"$upload_only_app_links_env" help.test --allow-pre-play >/dev/null
./scripts/check-environment-readiness.sh \
"$upload_only_app_links_env" --require-server-release >/dev/null
unpublished_play_app_links_env="$scan_dir/production.unpublished-play-app-links.env" unpublished_play_app_links_env="$scan_dir/production.unpublished-play-app-links.env"
cp "$production_env" "$unpublished_play_app_links_env" cp "$production_env" "$unpublished_play_app_links_env"
@ -800,6 +804,18 @@ if ./scripts/check-environment-readiness.sh \
echo "Environment readiness accepted an unpublished Play App Signing fingerprint." >&2 echo "Environment readiness accepted an unpublished Play App Signing fingerprint." >&2
exit 1 exit 1
fi fi
if ./scripts/validate-production-env.sh \
"$unpublished_play_app_links_env" help.test \
--allow-pre-play >/dev/null 2>&1; then
echo "Pre-Play validation accepted an unpublished Play App Signing fingerprint." >&2
exit 1
fi
if ./scripts/check-environment-readiness.sh \
"$unpublished_play_app_links_env" \
--require-server-release >/dev/null 2>&1; then
echo "Server-release readiness accepted an unpublished Play App Signing fingerprint." >&2
exit 1
fi
grep -Fx 'COMPOSE_PROJECT_NAME=who_need_help_production' "$production_env" >/dev/null grep -Fx 'COMPOSE_PROJECT_NAME=who_need_help_production' "$production_env" >/dev/null
grep -E '^APP_IMAGE=who-need-help:production-[0-9a-f]{12}$' "$production_env" >/dev/null grep -E '^APP_IMAGE=who-need-help:production-[0-9a-f]{12}$' "$production_env" >/dev/null

View File

@ -4,6 +4,15 @@ umask 077
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
env_file=${1:-"$ROOT/.env"} env_file=${1:-"$ROOT/.env"}
validation_mode=${2:-}
case "$validation_mode" in
'' | --allow-pre-play) ;;
*)
echo "Usage: $0 [ENV_FILE] [--allow-pre-play]" >&2
exit 1
;;
esac
case "$env_file" in case "$env_file" in
/*) ;; /*) ;;
@ -95,7 +104,14 @@ trap - EXIT HUP INT TERM
case "$deployment_env" in case "$deployment_env" in
test) "$ROOT/scripts/validate-test-env.sh" "$env_file" "$domain" ;; test) "$ROOT/scripts/validate-test-env.sh" "$env_file" "$domain" ;;
production) "$ROOT/scripts/validate-production-env.sh" "$env_file" "$domain" ;; production)
if [ -n "$validation_mode" ]; then
"$ROOT/scripts/validate-production-env.sh" \
"$env_file" "$domain" "$validation_mode"
else
"$ROOT/scripts/validate-production-env.sh" "$env_file" "$domain"
fi
;;
esac esac
echo "Selected $deployment_env deployment revision $git_sha without rotating secrets." echo "Selected $deployment_env deployment revision $git_sha without rotating secrets."

View File

@ -58,6 +58,27 @@ read_unique() {
printf '%s' "$output" printf '%s' "$output"
} }
read_optional_unique() {
local key=$1
awk -v key="$key" '
index($0, key "=") == 1 {
count += 1
value = substr($0, length(key) + 2)
}
END {
if (count != 1) exit 1
if (value ~ /^".*"$/ || value ~ /^'\''.*'\''$/) {
value = substr(value, 2, length(value) - 2)
}
print value
}
' "$env_file" || {
echo "$key must occur exactly once in $env_file." >&2
exit 1
}
}
deployment_environment=$(read_unique DEPLOYMENT_ENV) deployment_environment=$(read_unique DEPLOYMENT_ENV)
phx_host=$(read_unique PHX_HOST) phx_host=$(read_unique PHX_HOST)
phx_scheme=$(read_unique PHX_SCHEME) phx_scheme=$(read_unique PHX_SCHEME)
@ -70,7 +91,7 @@ app_links_fingerprints=$(read_unique ANDROID_APP_LINKS_SHA256_CERT_FINGERPRINTS)
play_app_signing_fingerprints= play_app_signing_fingerprints=
if [[ "$expected_environment" == production ]]; then if [[ "$expected_environment" == production ]]; then
play_app_signing_fingerprints=$( play_app_signing_fingerprints=$(
read_unique ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS read_optional_unique ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS
) )
fi fi
@ -131,7 +152,8 @@ for fingerprint in "${fingerprints[@]}"; do
} }
done done
if [[ "$expected_environment" == production ]]; then if [[ "$expected_environment" == production &&
-n "$play_app_signing_fingerprints" ]]; then
IFS=',' read -r -a play_fingerprints <<<"$play_app_signing_fingerprints" IFS=',' read -r -a play_fingerprints <<<"$play_app_signing_fingerprints"
for play_fingerprint in "${play_fingerprints[@]}"; do for play_fingerprint in "${play_fingerprints[@]}"; do
compact_play=${play_fingerprint//:/} compact_play=${play_fingerprint//:/}

View File

@ -4,9 +4,10 @@ set -euo pipefail
ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
env_file=${1:-} env_file=${1:-}
expected_domain=${2:-} expected_domain=${2:-}
android_release_mode=${3:-}
usage() { usage() {
echo "Usage: $0 ENV_FILE EXPECTED_DOMAIN" >&2 echo "Usage: $0 ENV_FILE EXPECTED_DOMAIN [--allow-pre-play]" >&2
} }
if [[ -z "$env_file" || -z "$expected_domain" ]]; then if [[ -z "$env_file" || -z "$expected_domain" ]]; then
@ -14,6 +15,12 @@ if [[ -z "$env_file" || -z "$expected_domain" ]]; then
exit 1 exit 1
fi fi
if [[ -n "$android_release_mode" &&
"$android_release_mode" != "--allow-pre-play" ]]; then
usage
exit 1
fi
if [[ ! -f "$env_file" ]]; then if [[ ! -f "$env_file" ]]; then
echo "Deployment environment does not exist: $env_file" >&2 echo "Deployment environment does not exist: $env_file" >&2
exit 1 exit 1
@ -497,11 +504,15 @@ if [[ -n "$android_app_links_package_name" ||
-n "$android_app_links_fingerprints" || -n "$android_app_links_fingerprints" ||
-n "$android_play_app_signing_fingerprints" ]]; then -n "$android_play_app_signing_fingerprints" ]]; then
[[ -n "$android_app_links_package_name" && [[ -n "$android_app_links_package_name" &&
-n "$android_app_links_fingerprints" && -n "$android_app_links_fingerprints" ]] || {
-n "$android_play_app_signing_fingerprints" ]] || { echo "Production Android App Links require the package and published fingerprints together." >&2
echo "Production Android App Links require the package, published fingerprints, and Play App Signing fingerprints together." >&2
exit 1 exit 1
} }
if [[ -z "$android_play_app_signing_fingerprints" &&
"$android_release_mode" != "--allow-pre-play" ]]; then
echo "Production Android App Links require Play App Signing fingerprints for full release readiness." >&2
exit 1
fi
[[ "$android_app_links_package_name" =~ ^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$ ]] || { [[ "$android_app_links_package_name" =~ ^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$ ]] || {
echo "ANDROID_APP_LINKS_PACKAGE_NAME is not a valid Android application ID." >&2 echo "ANDROID_APP_LINKS_PACKAGE_NAME is not a valid Android application ID." >&2
exit 1 exit 1
@ -525,6 +536,7 @@ if [[ -n "$android_app_links_package_name" ||
} }
done done
if [[ -n "$android_play_app_signing_fingerprints" ]]; then
IFS=',' read -r -a play_fingerprints <<<"$android_play_app_signing_fingerprints" IFS=',' read -r -a play_fingerprints <<<"$android_play_app_signing_fingerprints"
[[ ${#play_fingerprints[@]} -gt 0 ]] || { [[ ${#play_fingerprints[@]} -gt 0 ]] || {
echo "ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS is empty." >&2 echo "ANDROID_PLAY_APP_SIGNING_SHA256_CERT_FINGERPRINTS is empty." >&2
@ -552,6 +564,7 @@ if [[ -n "$android_app_links_package_name" ||
exit 1 exit 1
} }
done done
fi
fi fi
case "$codex_session_id" in case "$codex_session_id" in