This commit is contained in:
Jayden Liang 2026-01-30 17:16:51 +07:00 committed by GitHub
commit 60e41137b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 1 deletions

View File

@ -289,3 +289,35 @@ describe("browser tool snapshot labels", () => {
expect(result?.content?.[1]).toMatchObject({ type: "image" });
});
});
describe("browser tool tab open and close behaviors", () => {
afterEach(() => {
vi.clearAllMocks();
configMocks.loadConfig.mockReturnValue({ browser: {} });
});
it("close a tab by targetId should be allowed in profile = 'clawd'", async () => {
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
await tool.execute?.("", { action: "close", targetId: "a real target id", profile: "clawd" });
expect(browserClientMocks.browserCloseTab).toHaveBeenCalledWith(
"http://127.0.0.1:9999",
"a real target id",
{ profile: "clawd" },
);
});
it("close a tab by targetId should be allowed in profile = 'chrome'", async () => {
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
await tool.execute?.("", { action: "close", targetId: "a real target id", profile: "clawd" });
expect(browserClientMocks.browserCloseTab).toHaveBeenCalledWith(
"http://127.0.0.1:9999",
"a real target id",
{ profile: "clawd" },
);
});
it("close a tab without targetId should throw error", async () => {
const tool = createBrowserTool({ sandboxBridgeUrl: "http://127.0.0.1:9999" });
await expect(tool.execute?.("", { action: "close" })).rejects.toThrow();
});
});

View File

@ -407,7 +407,13 @@ export function createBrowserTool(opts?: {
return jsonResult(result);
}
if (targetId) await browserCloseTab(baseUrl, targetId, { profile });
else await browserAct(baseUrl, { kind: "close" }, { profile });
else {
// Known issue: The 'close' action does not verify the ownership of the current tab before atempting to close it, leading to potential action conflicts in concurrent scenarios. For now, enforce a strict close action with targetId for proxyRequest: path = "/act". The following line is commented out to prevent accidental usage. Instead, we throw an error to inform the user.
// await browserAct(baseUrl, { kind: "close" }, { profile });
throw new Error(
`Closing a tab without providing a targetId is not allowed. (But it was somehow allowed to do so in a previous version!). To avoid closing a tab not belonging to you, ensure you maintain a set of tabs by their targetId and provide a targetId when closing.`,
);
}
return jsonResult({ ok: true });
}
case "snapshot": {