mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-30 01:06:11 +00:00
fix: test browser.request profile body fallback (#28852) (thanks @Sid-Qin)
This commit is contained in:
@@ -39,6 +39,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Security/Prompt spoofing hardening: stop injecting queued runtime events into user-role prompt text, route them through trusted system-prompt context, and neutralize inbound spoof markers like `[System Message]` and line-leading `System:` in untrusted message content. (#30448)
|
||||
- Gateway/Node browser proxy routing: honor `profile` from `browser.request` JSON body when query params omit it, while preserving query-profile precedence when both are present. (#28852) Thanks @Sid-Qin.
|
||||
- Browser/Remote CDP ownership checks: skip local-process ownership errors for non-loopback remote CDP profiles when HTTP is reachable but the websocket handshake fails, and surface the remote websocket attach/retry path instead. (#15582) Landed from contributor (#28780) Thanks @stubbi, @bsormagec, @unblockedgamesstudio and @vincentkoc.
|
||||
- Docker/Image health checks: add Dockerfile `HEALTHCHECK` that probes gateway `GET /healthz` so container runtimes can mark unhealthy instances without requiring auth credentials in the probe command. (#11478) Thanks @U-C4N and @vincentkoc.
|
||||
- Daemon/systemd checks in containers: treat missing `systemctl` invocations (including `spawn systemctl ENOENT`/`EACCES`) as unavailable service state during `is-enabled` checks, preventing container flows from failing with `Gateway service check failed` before install/status handling can continue. (#26089) Thanks @sahilsatralkar and @vincentkoc.
|
||||
|
||||
103
src/gateway/server-methods/browser.profile-from-body.test.ts
Normal file
103
src/gateway/server-methods/browser.profile-from-body.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { loadConfigMock, isNodeCommandAllowedMock, resolveNodeCommandAllowlistMock } = vi.hoisted(
|
||||
() => ({
|
||||
loadConfigMock: vi.fn(),
|
||||
isNodeCommandAllowedMock: vi.fn(),
|
||||
resolveNodeCommandAllowlistMock: vi.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
loadConfig: loadConfigMock,
|
||||
}));
|
||||
|
||||
vi.mock("../node-command-policy.js", () => ({
|
||||
isNodeCommandAllowed: isNodeCommandAllowedMock,
|
||||
resolveNodeCommandAllowlist: resolveNodeCommandAllowlistMock,
|
||||
}));
|
||||
|
||||
import { browserHandlers } from "./browser.js";
|
||||
|
||||
type RespondCall = [boolean, unknown?, { code: number; message: string }?];
|
||||
|
||||
function createContext() {
|
||||
const invoke = vi.fn(async () => ({
|
||||
ok: true,
|
||||
payload: {
|
||||
result: { ok: true },
|
||||
},
|
||||
}));
|
||||
const listConnected = vi.fn(() => [
|
||||
{
|
||||
nodeId: "node-1",
|
||||
caps: ["browser"],
|
||||
commands: ["browser.proxy"],
|
||||
platform: "linux",
|
||||
},
|
||||
]);
|
||||
return {
|
||||
invoke,
|
||||
listConnected,
|
||||
};
|
||||
}
|
||||
|
||||
async function runBrowserRequest(params: Record<string, unknown>) {
|
||||
const respond = vi.fn();
|
||||
const nodeRegistry = createContext();
|
||||
await browserHandlers["browser.request"]({
|
||||
params,
|
||||
respond: respond as never,
|
||||
context: { nodeRegistry } as never,
|
||||
client: null,
|
||||
req: { type: "req", id: "req-1", method: "browser.request" },
|
||||
isWebchatConnect: () => false,
|
||||
});
|
||||
return { respond, nodeRegistry };
|
||||
}
|
||||
|
||||
describe("browser.request profile selection", () => {
|
||||
beforeEach(() => {
|
||||
loadConfigMock.mockReturnValue({
|
||||
gateway: { nodes: { browser: { mode: "auto" } } },
|
||||
});
|
||||
resolveNodeCommandAllowlistMock.mockReturnValue([]);
|
||||
isNodeCommandAllowedMock.mockReturnValue({ ok: true });
|
||||
});
|
||||
|
||||
it("uses profile from request body when query profile is missing", async () => {
|
||||
const { respond, nodeRegistry } = await runBrowserRequest({
|
||||
method: "POST",
|
||||
path: "/act",
|
||||
body: { profile: "work", request: { action: "click", ref: "btn1" } },
|
||||
});
|
||||
|
||||
expect(nodeRegistry.invoke).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
command: "browser.proxy",
|
||||
params: expect.objectContaining({
|
||||
profile: "work",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
const call = respond.mock.calls[0] as RespondCall | undefined;
|
||||
expect(call?.[0]).toBe(true);
|
||||
});
|
||||
|
||||
it("prefers query profile over body profile when both are present", async () => {
|
||||
const { nodeRegistry } = await runBrowserRequest({
|
||||
method: "POST",
|
||||
path: "/act",
|
||||
query: { profile: "chrome" },
|
||||
body: { profile: "work", request: { action: "click", ref: "btn1" } },
|
||||
});
|
||||
|
||||
expect(nodeRegistry.invoke).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
params: expect.objectContaining({
|
||||
profile: "chrome",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user