mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 20:07:18 +01:00
Fix GMS gate APK mode false positive
Some checks are pending
data_transfer_flutter tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
Some checks are pending
data_transfer_flutter tests / test (push) Waiting to run
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
sync_settings_ui tests / test (push) Waiting to run
Decide by AGP library marker files instead of dex strings: play-services-base/basement reference GoogleSignInAccount without linking play-services-auth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzxdWVQE5pYiASpRGgA3Kg
This commit is contained in:
parent
eef7af4c86
commit
ae56037e41
@ -14,8 +14,8 @@
|
||||
# (google_sign_in_web, google_sign_in_platform_interface and their transitive
|
||||
# google_identity_services_web) are allowed while google_sign_in_android is
|
||||
# absent: kartka's web build uses them for the GIS button and they never
|
||||
# reach an APK. APK mode greps the built dex for the GMS auth classes, the
|
||||
# ground truth when a dependency arrives some other way.
|
||||
# reach an APK. APK mode looks for the GMS auth library marker files in the
|
||||
# built APK, the ground truth when a dependency arrives some other way.
|
||||
#
|
||||
# Usage: check_no_gms_signin.sh [pubspec.lock | dir ...]
|
||||
# check_no_gms_signin.sh --apk app.apk
|
||||
@ -35,7 +35,19 @@ readonly WEB_ONLY=(google_sign_in_web google_sign_in_platform_interface
|
||||
# Anchored so com.google.gms:google-services (Firebase) and
|
||||
# play-services-auth-api-phone do not trip it.
|
||||
readonly GRADLE_PATTERN='com\.google\.android\.gms:play-services-(auth|identity-credentials)([^-[:alnum:]]|$)|com\.google\.android\.libraries\.identity\.googleid|androidx\.credentials:credentials-play-services-auth|name[[:space:]]*=[[:space:]]*"(play-services-auth|play-services-identity-credentials|credentials-play-services-auth|googleid)"'
|
||||
readonly DEX_PATTERN='Lcom/google/android/(gms/auth|libraries/identity/googleid)/'
|
||||
# APK mode: library marker files AGP copies to the APK root (or META-INF),
|
||||
# one per linked artifact. Dex strings are not used: play-services-base and
|
||||
# -basement reference GoogleSignInAccount without linking play-services-auth.
|
||||
# play-services-fido (passkeys) is deliberately allowed.
|
||||
readonly APK_MARKERS=(
|
||||
googleid.properties
|
||||
play-services-auth.properties
|
||||
play-services-auth-base.properties
|
||||
play-services-auth-api-phone.properties
|
||||
play-services-auth-blockstore.properties
|
||||
play-services-identity-credentials.properties
|
||||
META-INF/androidx.credentials_credentials-play-services-auth.version
|
||||
)
|
||||
readonly PRUNE=(-name build -o -name .dart_tool -o -name .git -o -name .gradle -o -name .claude
|
||||
-o -name node_modules)
|
||||
|
||||
@ -122,17 +134,18 @@ check_lock() {
|
||||
}
|
||||
|
||||
check_apk() {
|
||||
local apk="$1" dex count
|
||||
local apk="$1" entries found=()
|
||||
local marker
|
||||
[[ -f "$apk" ]] || { echo "Error: no such APK: $apk" >&2; exit 2; }
|
||||
count="$(for dex in $(unzip -Z1 "$apk" 'classes*.dex'); do
|
||||
unzip -p "$apk" "$dex"
|
||||
done | strings | grep -cE "$DEX_PATTERN" || true)"
|
||||
if [[ "$count" -gt 0 ]]; then
|
||||
echo "Error: $apk has $count GMS sign-in class references" >&2
|
||||
echo " (Lcom/google/android/gms/auth or .../identity/googleid)." >&2
|
||||
fix_hint
|
||||
return 1
|
||||
fi
|
||||
entries="$(unzip -Z1 "$apk")"
|
||||
for marker in "${APK_MARKERS[@]}"; do
|
||||
grep -qxF -- "$marker" <<<"$entries" && found+=("$marker")
|
||||
done
|
||||
[[ "${#found[@]}" -eq 0 ]] && return 0
|
||||
echo "Error: $apk bundles Google's non-free sign-in libraries:" >&2
|
||||
printf ' %s\n' "${found[@]}" >&2
|
||||
fix_hint
|
||||
return 1
|
||||
}
|
||||
|
||||
# Expands the arguments into pubspec.lock paths, NUL-separated.
|
||||
|
||||
@ -136,23 +136,60 @@ def test_missing_explicit_file_is_a_usage_error(tmp_path: Path) -> None:
|
||||
assert _run(tmp_path / "nope.lock").returncode == 2
|
||||
|
||||
|
||||
def _apk(path: Path, dex: bytes) -> Path:
|
||||
CREDENTIALS_MARKER = "META-INF/androidx.credentials_credentials-play-services-auth.version"
|
||||
DEX_REF = b"\x00Lcom/google/android/gms/auth/api/signin/GoogleSignInAccount;\x00" * 2
|
||||
|
||||
|
||||
def _apk(path: Path, dex: bytes = b"", markers: tuple[str, ...] = ()) -> Path:
|
||||
"""Fake APK: dex strings plus library marker files AGP copies in."""
|
||||
with zipfile.ZipFile(path, "w") as apk:
|
||||
apk.writestr("AndroidManifest.xml", b"\x03\x00")
|
||||
apk.writestr("classes.dex", b"dex\n035\x00" + dex)
|
||||
apk.writestr("classes2.dex", b"dex\n035\x00Lkotlin/Unit;\x00")
|
||||
for name in markers:
|
||||
apk.writestr(name, b"version=1")
|
||||
return path
|
||||
|
||||
|
||||
def test_apk_with_gms_auth_classes_fails(tmp_path: Path) -> None:
|
||||
dex = b"\x00Lcom/google/android/gms/auth/api/signin/GoogleSignIn;\x00" * 2
|
||||
proc = _run("--apk", _apk(tmp_path / "bad.apk", dex))
|
||||
assert proc.returncode == 1
|
||||
assert "2" in proc.stderr
|
||||
assert "google_account_token" in proc.stderr
|
||||
|
||||
|
||||
def test_apk_without_gms_auth_classes_passes(tmp_path: Path) -> None:
|
||||
dex = b"\x00Lcom/google/android/gms/common/api/Status;\x00"
|
||||
proc = _run("--apk", _apk(tmp_path / "good.apk", dex))
|
||||
def test_apk_with_only_dex_references_passes(tmp_path: Path) -> None:
|
||||
"""play-services-base references GoogleSignInAccount without linking auth."""
|
||||
markers = (
|
||||
"play-services-base.properties",
|
||||
"play-services-basement.properties",
|
||||
"play-services-tasks.properties",
|
||||
"play-services-fido.properties",
|
||||
)
|
||||
proc = _run("--apk", _apk(tmp_path / "ok.apk", DEX_REF, markers))
|
||||
assert proc.returncode == 0, proc.stderr
|
||||
|
||||
|
||||
def test_apk_without_markers_passes(tmp_path: Path) -> None:
|
||||
assert _run("--apk", _apk(tmp_path / "clean.apk")).returncode == 0
|
||||
|
||||
|
||||
def test_apk_banned_markers_fail_and_are_named(tmp_path: Path) -> None:
|
||||
banned = (
|
||||
"play-services-auth.properties",
|
||||
"googleid.properties",
|
||||
"play-services-auth-base.properties",
|
||||
"play-services-auth-api-phone.properties",
|
||||
"play-services-auth-blockstore.properties",
|
||||
"play-services-identity-credentials.properties",
|
||||
CREDENTIALS_MARKER,
|
||||
)
|
||||
for marker in banned:
|
||||
apk = _apk(tmp_path / "bad.apk", DEX_REF, ("play-services-base.properties", marker))
|
||||
proc = _run("--apk", apk)
|
||||
assert proc.returncode == 1, marker
|
||||
assert marker in proc.stderr
|
||||
assert "google_account_token" in proc.stderr
|
||||
|
||||
|
||||
def test_apk_nested_marker_name_is_not_a_root_marker(tmp_path: Path) -> None:
|
||||
"""Only APK-root files count; a same-named file in a subdir is not AGP's."""
|
||||
apk = _apk(tmp_path / "nested.apk", markers=("assets/play-services-auth.properties",))
|
||||
assert _run("--apk", apk).returncode == 0
|
||||
|
||||
|
||||
def test_apk_missing_file_is_a_usage_error(tmp_path: Path) -> None:
|
||||
assert _run("--apk", tmp_path / "nope.apk").returncode == 2
|
||||
|
||||
Loading…
Reference in New Issue
Block a user