#!/bin/sh # Hermetic negative-path tests for the release-manifest inventory drift gate # (PB-26-113). No Android SDK, Gradle project, or merged build output required. set -eu SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) CHECK="$SCRIPT_DIR/check-release-manifest.py" TEMP_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/peach-release-manifest-tests.XXXXXX") trap 'trash "$TEMP_ROOT"' EXIT HUP INT TERM MERGED="$TEMP_ROOT/AndroidManifest.xml" INVENTORY="$TEMP_ROOT/inventory.txt" fail() { printf 'FAIL: %s\n' "$1" >&2 exit 1 } write_manifest() { cat > "$MERGED" < $1 XML } write_manifest "" python3 "$CHECK" write "$MERGED" "$INVENTORY" [ -s "$INVENTORY" ] || fail "write produced no inventory" grep -q '^permission|android.permission.INTERNET|' "$INVENTORY" || fail "inventory is missing the declared permission" python3 "$CHECK" check "$MERGED" "$INVENTORY" python3 "$CHECK" write "$MERGED" "$INVENTORY" python3 "$CHECK" check "$MERGED" "$INVENTORY" # A permission added to the merged manifest after the inventory was recorded # must refuse, and must say so rather than crashing. write_manifest '' if output=$(python3 "$CHECK" check "$MERGED" "$INVENTORY" 2>&1); then fail "drifted merged manifest was accepted" fi case "$output" in *"differs from checked-in inventory"*) ;; *) fail "drift refusal did not report drift: $output" ;; esac # Missing inputs fail closed instead of reporting a clean comparison. if python3 "$CHECK" check "$TEMP_ROOT/absent.xml" "$INVENTORY" >/dev/null 2>&1; then fail "a missing merged manifest was accepted" fi if python3 "$CHECK" check "$MERGED" "$TEMP_ROOT/absent.txt" >/dev/null 2>&1; then fail "a missing inventory was accepted" fi # An exposure-bearing attribute changed without any name or exported flag # changing must also refuse (PB-26-133): these three cases all passed the old # inventory silently. write_provider_manifest() { cat > "$MERGED" < XML } write_provider_manifest "false" python3 "$CHECK" write "$MERGED" "$INVENTORY" python3 "$CHECK" check "$MERGED" "$INVENTORY" write_provider_manifest "true" if python3 "$CHECK" check "$MERGED" "$INVENTORY" >/dev/null 2>&1; then fail "a granted URI permission was accepted as no drift" fi # Nested intent-filter data attributes are security-relevant and must drift. cat > "$MERGED" <<'XML' XML python3 "$CHECK" write "$MERGED" "$INVENTORY" grep -q '^intent-filter-data|activity|.MainActivity|host=example.com;scheme=https$' "$INVENTORY" || fail "inventory is missing nested intent-filter data" python3 "$CHECK" check "$MERGED" "$INVENTORY" sed 's/android:host="example.com"/android:host="evil.example.com"/' "$MERGED" > "$MERGED.changed" mv "$MERGED.changed" "$MERGED" if python3 "$CHECK" check "$MERGED" "$INVENTORY" >/dev/null 2>&1; then fail "nested intent data drift was accepted" fi cat > "$MERGED" <<'XML' XML if python3 "$CHECK" check "$MERGED" "$INVENTORY" >/dev/null 2>&1; then fail "a new maxSdkVersion was accepted as no drift" fi cat > "$MERGED" <<'XML' XML if python3 "$CHECK" check "$MERGED" "$INVENTORY" >/dev/null 2>&1; then fail "a debuggable application element was accepted as no drift" fi printf 'PASS: release manifest inventory drift gate\n'