fix(frida): preserve session refusal and close execution effects

This commit is contained in:
morluto
2026-10-24 03:08:22 +08:00
parent 79323128f2
commit 3a62b96194
3 changed files with 65 additions and 3 deletions
+1
View File
@@ -244,6 +244,7 @@ export const TOOL_EFFECTS: Readonly<Record<string, ToolEffects>> = {
mutatesSession: true,
launchesProcess: true,
accessesNetwork: true,
executesForeignCode: true,
idempotent: false,
}),
instrument_with_frida: effects({
+12 -3
View File
@@ -588,10 +588,19 @@ export class FridaInstrumentationManager implements FridaInstrumentationPort {
return err(unknownFridaSession("resume_frida_session", sessionId));
if (managed.mode !== "spawn" || managed.targetResumeObserved)
return err(
new AnalysisCapabilityUnavailableError(
"frida",
new AnalysisInputError(
"resume_frida_session",
"Only a paused process spawned by this session can be resumed.",
{
userMessage:
"Only a paused process spawned by this session can be resumed.",
},
[
{
path: ["session_id"],
reason: "invalid_value",
message: "Select a paused process spawned by this session.",
},
],
),
);
const pendingScripts = [...managed.scripts.values()].filter(
@@ -298,6 +298,26 @@ it.each(["attached", "during-resume", "after-resume"] as const)(
it("retains detached state and resume evidence when remote cleanup needs retry", async () => {
const fixture = await connectedFixture();
expect(
(await fixture.client.listTools()).tools.find(
(tool) => tool.name === "close_frida_session",
)?.annotations?.destructiveHint,
).toBe(true);
const inventory = await fixture.client.callTool({
name: "binary_session",
arguments: {},
});
const availability = expandToolAvailability(
toolContract("binary_session").outputSchema.parse(
inventory.structuredContent,
).result.tool_availability,
);
expect(
availability.find((tool) => tool.name === "close_frida_session"),
).toMatchObject({
effects: { executesForeignCode: true },
annotations: { destructive: true },
});
const started = await fixture.client.callTool({
name: "start_frida_session",
arguments: {
@@ -1434,3 +1454,35 @@ it.each([0, 1, 2, 3, 4, 8])(
}
},
);
it.each(["attached", "resumed"] as const)(
"reports %s Frida resume refusal as selected session input",
async (state) => {
const fixture = await connectedFixture();
const started =
state === "attached"
? await fixture.manager.startSession({ mode: "attach", pid: 512 })
: await fixture.manager.startSession({
mode: "spawn",
program: "/fixture",
});
if (!started.ok) throw started.error;
const id = started.value.session_id;
if (state === "resumed")
expect((await fixture.manager.resumeSession(id)).ok).toBe(true);
const result = await fixture.client.callTool({
name: "resume_frida_session",
arguments: { session_id: id },
});
expect(result.isError).toBe(true);
expect(parseMcpToolError(result)).toMatchObject({
error: {
code: "invalid_request",
details: {
issues: [{ path: ["session_id"], reason: "invalid_value" }],
},
},
});
expect(fixture.controls.resumes).toBe(state === "resumed" ? 1 : 0);
},
);