fix(scripts): remove the ADB verifier's pushed probe file from the device (#5256)

* fix(scripts): remove the ADB verifier's pushed probe file from the device

The verifier pushed `/data/local/tmp/rea-verify-<timestamp>.txt` for its
transfer roundtrip but never deleted it, so every successful run left a
probe behind while reporting that all checks passed.

After a successful no-overwrite push, the verifier now removes that exact
destination with the provider-reported adb client and confirms its absence
through `list_adb_directory`. Removal runs even when the pull fails, and a
removal failure is reported as a failed check instead of a pass.
`pull_adb_file` still retains device originals.

Fixes #5190

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(scripts): cover ADB probe cleanup after pull failure and leftover probes

Add verifier cases where the pull returns an error or throws after a
successful push, and where `adb shell rm` exits 0 but the listing still
shows the probe. Pull failures must still remove the probe, and a leftover
probe must fail the run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Syed Musa Raza Naqvi
2026-10-23 02:56:19 +05:00
committed by GitHub
parent c4b7a2e003
commit 81b94cebec
2 changed files with 216 additions and 36 deletions
+83 -24
View File
@@ -1,12 +1,15 @@
import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { join, posix } from "node:path";
import { promisify } from "node:util";
import { AdbDeviceAnalysisService } from "../dist/application/adb/AdbDeviceAnalysisService.js";
import { createAdbDeviceAnalysisProvider } from "../dist/composition/adb.js";
import { closeVerifierResources } from "./lib/verifier-cleanup.mjs";
const execFileAsync = promisify(execFile);
const options = parseArguments(process.argv.slice(2));
if (options.help) {
process.stdout.write(
@@ -40,6 +43,80 @@ const run = async (operation, input) => {
return result.value.normalized_result;
};
// Remove the verifier's own transfer probe with the provider-reported adb
// client, then confirm through the directory listing that it is gone.
const removeDeviceProbe = async (binary, serial, devicePath) => {
const name = "verifier transfer probe removed";
if (typeof binary !== "string" || binary === "") {
check(name, false, `${devicePath}: adb client path unavailable`);
return;
}
try {
await execFileAsync(
binary,
["-s", serial, "shell", "rm", "--", devicePath],
{
timeout: 30_000,
},
);
} catch (cause) {
check(name, false, `${devicePath}: ${formatFailure(cause)}`);
return;
}
const listing = await run("list_adb_directory", {
serial,
device_path: posix.dirname(devicePath),
});
if (listing !== null)
check(
name,
listing.coverage === "complete" &&
!listing.entries.some(
(entry) => entry.name === posix.basename(devicePath),
),
devicePath,
);
};
const verifyTransferRoundtrip = async ({
adbBinary,
serial,
payload,
devicePath,
outputDirectory,
}) => {
const pushed = await run("push_adb_file", {
serial,
local_path: payload,
device_path: devicePath,
overwrite: false,
});
if (pushed === null) return;
// A successful no-overwrite push proves the verifier created this exact
// destination; pull_adb_file deliberately retains device originals.
try {
check(
"push reports matching device-side digest",
pushed.device_digest_source === "device_sha256sum" &&
pushed.device_sha256 === pushed.sha256,
`${pushed.bytes} bytes`,
);
const pulled = await run("pull_adb_file", {
serial,
device_path: devicePath,
output_directory: outputDirectory,
});
if (pulled !== null)
check(
"pulled file digest matches the pushed digest",
pulled.sha256 === pushed.sha256,
`${pulled.bytes} bytes`,
);
} finally {
await removeDeviceProbe(adbBinary, serial, devicePath);
}
};
let verifierFailed = false;
let verifierFailure;
try {
@@ -245,31 +322,13 @@ try {
fs.writeFile(payload, payloadBytes),
);
const deviceTarget = `/data/local/tmp/rea-verify-${Date.now()}.txt`;
const pushed = await run("push_adb_file", {
await verifyTransferRoundtrip({
adbBinary: client?.client.binary_path,
serial,
local_path: payload,
device_path: deviceTarget,
overwrite: false,
payload,
devicePath: deviceTarget,
outputDirectory: transferRoot,
});
if (pushed !== null) {
check(
"push reports matching device-side digest",
pushed.device_digest_source === "device_sha256sum" &&
pushed.device_sha256 === pushed.sha256,
`${pushed.bytes} bytes`,
);
const pulled = await run("pull_adb_file", {
serial,
device_path: deviceTarget,
output_directory: transferRoot,
});
if (pulled !== null)
check(
"pulled file digest matches the pushed digest",
pulled.sha256 === pushed.sha256,
`${pulled.bytes} bytes`,
);
}
const screenRoot = await mkdtemp(join(tmpdir(), "rea-adb-screen-"));
try {
const screen = await run("capture_adb_screen", {