From 1da304b28213ca7a50f6787eae716abe73c4e628 Mon Sep 17 00:00:00 2001 From: HawkForge <75696486+HawkForge@users.noreply.github.com> Date: Fri, 30 Oct 2026 00:48:51 +0600 Subject: [PATCH] fix(adb): verify pushes to long device paths (#8047) * fix(adb): verify pushes to long device paths sha256sum echoes the device path, so a correct digest line for a path near 1 KiB exceeded the fixed 1 KiB capture budget. The resulting resource failure was then reported as device_digest_source "unavailable", the same outcome as a device without sha256sum. Size the budget to the path, and return a capture-budget failure as a resource constraint instead of an unverified success. Fixes #3369 * Keep adbDeviceAnalysis.ts as on main * test(adb): keep only the long-path digest test Main already covers an oversized checksum answer as a resource constraint with the completed push retained. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- src/adb/AdbProvider.test.ts | 30 ++++++++++++++++++++++++++++++ src/adb/AdbProvider.ts | 7 ++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/adb/AdbProvider.test.ts b/src/adb/AdbProvider.test.ts index b5e6b77e7c..d81ade095a 100644 --- a/src/adb/AdbProvider.test.ts +++ b/src/adb/AdbProvider.test.ts @@ -1345,6 +1345,36 @@ exit 1`, expect(closeAttempts).toBe(2); }); +it("verifies the device-side digest for a long device path", async () => { + const { binary, root } = await writeAdbStub( + () => `if [ "$1" = "version" ]; then ${VERSION_BLOCK}; exit 0; fi +if [ "$1" = "-s" ] && [ "$4" = "test" ]; then exit 1; fi +if [ "$1" = "-s" ] && [ "$3" = "push" ]; then exit 0; fi +if [ "$1" = "-s" ] && [ "$4" = "sha256sum" ]; then printf '%s %s\\n' "8748b5d17d1ebcec7d46674fa6a8b92c0f95598a552f27c1c8a132eb58c04043" "$5"; exit 0; fi +exit 1`, + ); + const localFile = join(root, "payload.bin"); + await writeFile(localFile, "push-payload"); + const digest = createHash("sha256").update("push-payload").digest("hex"); + const pushed = await evidenceResult(providerOver(binary), { + operation: "push_adb_file", + input: { + serial: "emulator-5554", + local_path: localFile, + // Each component stays within the usual 255-byte limit; the whole + // path still makes the digest line exceed the former 1 KiB budget. + device_path: `/data/local/tmp/${Array.from({ length: 5 }, (_, index) => + String(index).padEnd(220, "d"), + ).join("/")}/payload.bin`, + overwrite: false, + }, + }); + expect(pushed).toMatchObject({ + device_sha256: digest, + device_digest_source: "device_sha256sum", + }); +}); + it("reports a digest mismatch after push as a changed artifact", async () => { const { binary, root } = await writeAdbStub( () => `if [ "$1" = "version" ]; then ${VERSION_BLOCK}; exit 0; fi diff --git a/src/adb/AdbProvider.ts b/src/adb/AdbProvider.ts index c5a5ace10b..7bf5f5de70 100644 --- a/src/adb/AdbProvider.ts +++ b/src/adb/AdbProvider.ts @@ -2585,7 +2585,12 @@ export class AdbProvider { { device: input.serial, path: devicePath }, selection, adbArguments(input.serial, ["shell", "sha256sum", devicePath]), - { timeoutMs: SHELL_TIMEOUT_MS, maxOutputBytes: 1024 }, + { + timeoutMs: SHELL_TIMEOUT_MS, + // sha256sum echoes the path, escaping special characters, so a + // long path must not exhaust the budget for the digest line. + maxOutputBytes: 1024 + 2 * Buffer.byteLength(devicePath), + }, signal, ); if (!deviceDigest.ok) {