From c7fce66035a4eba490157b4ec3f43b1a7515aa99 Mon Sep 17 00:00:00 2001 From: xin zhuang <65798732+1052326311@users.noreply.github.com> Date: Thu, 5 Nov 2026 17:38:14 +0800 Subject: [PATCH] test(cli): cover Frida argument admission and spawn ordering (#3356) * fix(cli): reject spawn arguments in Frida attach mode * test(cli): remove redundant Frida recorder assignments --------- Co-authored-by: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> --- tests/boundary/cli/fridaCli.test.ts | 74 +++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/tests/boundary/cli/fridaCli.test.ts b/tests/boundary/cli/fridaCli.test.ts index f6f3c3c7a2..bd535fe344 100644 --- a/tests/boundary/cli/fridaCli.test.ts +++ b/tests/boundary/cli/fridaCli.test.ts @@ -160,7 +160,7 @@ it.each([false, true])( }, ); -it("maps one-shot Frida CLI target, script, duration, and remote options", async () => { +const createFridaRecorder = () => { const calls: unknown[] = []; const provider: FridaInstrumentationPort = { async listDevices() { @@ -228,6 +228,11 @@ it("maps one-shot Frida CLI target, script, duration, and remote options", async }, async closeAll() {}, }; + return { calls, provider }; +}; + +it("maps one-shot Frida CLI target, script, duration, and remote options", async () => { + const { calls, provider } = createFridaRecorder(); const cli = createCli({}, undefined, provider); let stdout = ""; let exitCode = 0; @@ -311,6 +316,51 @@ it("maps one-shot Frida CLI target, script, duration, and remote options", async expect(stdout).not.toContain("synthetic-secret-token"); }); +it("forwards every selected spawn argument through the CLI and shared service", async () => { + const { calls, provider } = createFridaRecorder(); + const cli = createCli({}, undefined, provider); + let stdout = ""; + let exitCode = 0; + await cli.serve( + [ + "instrument-with-frida", + "spawn", + "fixture-program", + "--script", + "send(1)", + "--argument", + "first", + "--argument", + "second", + "--duration-ms", + "0", + "--json", + ], + { + env: {}, + exit: (code) => { + exitCode = code; + }, + stdout: (text) => { + stdout += text; + }, + }, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toHaveProperty("evidence"); + expect(calls).toContainEqual({ + operation: "start", + input: { + mode: "spawn", + program: "fixture-program", + deviceId: "local", + argv: ["first", "second"], + source: { sourceKind: "inline", source: "send(1)" }, + durationMs: 0, + }, + }); +}); + it("keeps Frida script-file identity in original bytes when UTF-8 decoding replaces invalid bytes", async () => { const directory = await mkdtemp(join(tmpdir(), "rea-frida-script-identity-")); const files = [ @@ -531,6 +581,11 @@ it("preserves observed devices when CLI provider cleanup fails", async () => { }); it.each([ + [ + ["attach", "71", "--script", "send(1)", "--argument", ""], + "argument", + "--argument is only valid in spawn mode; remove it when attaching to a process.", + ], [ ["attach", "abc", "--script", "send(1)"], "target", @@ -554,13 +609,16 @@ it.each([ ])( "names the rejected instrument-with-frida argument for %j", async (argv, path, message) => { - let starts = 0; - const provider = { - async startSession() { - starts += 1; - throw new Error("Frida must not start for invalid input"); + const calls: string[] = []; + const provider = new Proxy( + {}, + { + get: (_target, operation: string) => async () => { + calls.push(operation); + throw new Error("Frida must not be called for invalid input"); + }, }, - } as unknown as FridaInstrumentationPort; + ) as FridaInstrumentationPort; const cli = createCli({}, undefined, provider); let stdout = ""; await cli.serve(["instrument-with-frida", ...argv, "--json"], { @@ -576,7 +634,7 @@ it.each([ issues: [{ path: [path], reason: "invalid_value", message }], }, }); - expect(starts).toBe(0); + expect(calls).toEqual([]); }, );