Guardrail: connected tests refuse to run without an emulator ANDROID_SERIAL
Post-incident: an unscoped connectedDebugAndroidTest fanned out to every adb device including the personal phone, where the debug test APK's signature mismatch was resolved by UNINSTALLING the release app — wiping its data. The v1->v2 Room migration was initially blamed but is innocent (three emulator replays preserved data; dumpsys firstInstallTime == lastUpdateTime proved the phone got a fresh install, not an upgrade). connected* tasks now fail fast unless ANDROID_SERIAL names an emulator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
8157922efd
commit
5346b6a879
2 changed files with 24 additions and 0 deletions
|
|
@ -90,5 +90,9 @@ All gradlew calls need `JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64` — system
|
||||||
- Verify alarms: `adb shell dumpsys alarm | grep meddetsamme` — `window=0` means exact
|
- Verify alarms: `adb shell dumpsys alarm | grep meddetsamme` — `window=0` means exact
|
||||||
- The phone (Pixel 7 Pro) has a RELEASE-signed install: `adb install` of debug builds is
|
- The phone (Pixel 7 Pro) has a RELEASE-signed install: `adb install` of debug builds is
|
||||||
rejected on signature; use release builds for the phone, emulator for debug.
|
rejected on signature; use release builds for the phone, emulator for debug.
|
||||||
|
- **INCIDENT RULE (2026-06-10, data was lost): never run a device-touching command
|
||||||
|
unscoped.** Every `adb` call gets `-s <serial>`; connected tests get
|
||||||
|
`ANDROID_SERIAL=emulator-<n>`. The build fails connected* tasks without an emulator
|
||||||
|
serial — that guard stays. The phone is never a test target.
|
||||||
|
|
||||||
See @README.md for architecture detail.
|
See @README.md for architecture detail.
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,26 @@ android {
|
||||||
sourceSets.getByName("androidTest").assets.srcDir("$projectDir/schemas")
|
sourceSets.getByName("androidTest").assets.srcDir("$projectDir/schemas")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Guardrail (added after a real incident): an unscoped connected test run fans
|
||||||
|
// out to EVERY adb device. On 2026-06-10 that meant the personal phone, where
|
||||||
|
// the debug test APK's signature mismatch got "resolved" by uninstalling the
|
||||||
|
// release app — destroying its data. Connected tests now refuse to run unless
|
||||||
|
// ANDROID_SERIAL pins them to a specific (emulator) device.
|
||||||
|
tasks.matching { it.name.startsWith("connected") }.configureEach {
|
||||||
|
doFirst {
|
||||||
|
val serial = System.getenv("ANDROID_SERIAL")
|
||||||
|
check(!serial.isNullOrBlank()) {
|
||||||
|
"Refusing to run connected tests without ANDROID_SERIAL — an unscoped run " +
|
||||||
|
"targets every adb device, including the phone. " +
|
||||||
|
"Use: ANDROID_SERIAL=emulator-5554 ./gradlew ${this@configureEach.name}"
|
||||||
|
}
|
||||||
|
check(serial.startsWith("emulator-")) {
|
||||||
|
"ANDROID_SERIAL=$serial is not an emulator — connected tests must never " +
|
||||||
|
"target a physical device."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Release builds refresh the bundled FEST dataset when it's >30 days old.
|
// Release builds refresh the bundled FEST dataset when it's >30 days old.
|
||||||
// The script fast-exits when fresh and keeps the old file on download failure,
|
// The script fast-exits when fresh and keeps the old file on download failure,
|
||||||
// so offline/CI release builds never break on this.
|
// so offline/CI release builds never break on this.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue