mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
refactor(tests): dedupe openresponses http fixtures
This commit is contained in:
@@ -90,6 +90,67 @@ async function ensureResponseConsumed(res: Response) {
|
||||
}
|
||||
}
|
||||
|
||||
const WEATHER_TOOL = [
|
||||
{
|
||||
type: "function",
|
||||
function: { name: "get_weather", description: "Get weather" },
|
||||
},
|
||||
] as const;
|
||||
|
||||
function buildUrlInputMessage(params: {
|
||||
kind: "input_file" | "input_image";
|
||||
url: string;
|
||||
text?: string;
|
||||
}) {
|
||||
return [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: params.text ?? "read this" },
|
||||
{
|
||||
type: params.kind,
|
||||
source: { type: "url", url: params.url },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function buildResponsesUrlPolicyConfig(maxUrlParts: number) {
|
||||
return {
|
||||
gateway: {
|
||||
http: {
|
||||
endpoints: {
|
||||
responses: {
|
||||
enabled: true,
|
||||
maxUrlParts,
|
||||
files: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["cdn.example.com", "*.assets.example.com"],
|
||||
},
|
||||
images: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["images.example.com"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function expectInvalidRequest(
|
||||
res: Response,
|
||||
messagePattern: RegExp,
|
||||
): Promise<{ type?: string; message?: string } | undefined> {
|
||||
expect(res.status).toBe(400);
|
||||
const json = (await res.json()) as { error?: { type?: string; message?: string } };
|
||||
expect(json.error?.type).toBe("invalid_request_error");
|
||||
expect(json.error?.message ?? "").toMatch(messagePattern);
|
||||
return json.error;
|
||||
}
|
||||
|
||||
describe("OpenResponses HTTP API (e2e)", () => {
|
||||
it("rejects when disabled (default + config)", { timeout: 15_000 }, async () => {
|
||||
const port = await getFreePort();
|
||||
@@ -324,12 +385,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
||||
const resToolNone = await postResponses(port, {
|
||||
model: "openclaw",
|
||||
input: "hi",
|
||||
tools: [
|
||||
{
|
||||
type: "function",
|
||||
function: { name: "get_weather", description: "Get weather" },
|
||||
},
|
||||
],
|
||||
tools: WEATHER_TOOL,
|
||||
tool_choice: "none",
|
||||
});
|
||||
expect(resToolNone.status).toBe(200);
|
||||
@@ -367,12 +423,7 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
||||
const resUnknownTool = await postResponses(port, {
|
||||
model: "openclaw",
|
||||
input: "hi",
|
||||
tools: [
|
||||
{
|
||||
type: "function",
|
||||
function: { name: "get_weather", description: "Get weather" },
|
||||
},
|
||||
],
|
||||
tools: WEATHER_TOOL,
|
||||
tool_choice: { type: "function", function: { name: "unknown_tool" } },
|
||||
});
|
||||
expect(resUnknownTool.status).toBe(400);
|
||||
@@ -536,100 +587,35 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
||||
|
||||
const blockedPrivate = await postResponses(port, {
|
||||
model: "openclaw",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "read this" },
|
||||
{
|
||||
type: "input_file",
|
||||
source: { type: "url", url: "http://127.0.0.1:6379/info" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
input: buildUrlInputMessage({
|
||||
kind: "input_file",
|
||||
url: "http://127.0.0.1:6379/info",
|
||||
}),
|
||||
});
|
||||
expect(blockedPrivate.status).toBe(400);
|
||||
const blockedPrivateJson = (await blockedPrivate.json()) as {
|
||||
error?: { type?: string; message?: string };
|
||||
};
|
||||
expect(blockedPrivateJson.error?.type).toBe("invalid_request_error");
|
||||
expect(blockedPrivateJson.error?.message ?? "").toMatch(
|
||||
/invalid request|private|internal|blocked/i,
|
||||
);
|
||||
await expectInvalidRequest(blockedPrivate, /invalid request|private|internal|blocked/i);
|
||||
|
||||
const blockedMetadata = await postResponses(port, {
|
||||
model: "openclaw",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "read this" },
|
||||
{
|
||||
type: "input_image",
|
||||
source: { type: "url", url: "http://metadata.google.internal/computeMetadata/v1" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
input: buildUrlInputMessage({
|
||||
kind: "input_image",
|
||||
url: "http://metadata.google.internal/computeMetadata/v1",
|
||||
}),
|
||||
});
|
||||
expect(blockedMetadata.status).toBe(400);
|
||||
const blockedMetadataJson = (await blockedMetadata.json()) as {
|
||||
error?: { type?: string; message?: string };
|
||||
};
|
||||
expect(blockedMetadataJson.error?.type).toBe("invalid_request_error");
|
||||
expect(blockedMetadataJson.error?.message ?? "").toMatch(
|
||||
/invalid request|blocked|metadata|internal/i,
|
||||
);
|
||||
await expectInvalidRequest(blockedMetadata, /invalid request|blocked|metadata|internal/i);
|
||||
|
||||
const blockedScheme = await postResponses(port, {
|
||||
model: "openclaw",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "read this" },
|
||||
{
|
||||
type: "input_file",
|
||||
source: { type: "url", url: "file:///etc/passwd" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
input: buildUrlInputMessage({
|
||||
kind: "input_file",
|
||||
url: "file:///etc/passwd",
|
||||
}),
|
||||
});
|
||||
expect(blockedScheme.status).toBe(400);
|
||||
const blockedSchemeJson = (await blockedScheme.json()) as {
|
||||
error?: { type?: string; message?: string };
|
||||
};
|
||||
expect(blockedSchemeJson.error?.type).toBe("invalid_request_error");
|
||||
expect(blockedSchemeJson.error?.message ?? "").toMatch(/invalid request|http or https/i);
|
||||
await expectInvalidRequest(blockedScheme, /invalid request|http or https/i);
|
||||
expect(agentCommand).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("enforces URL allowlist and URL part cap for responses inputs", async () => {
|
||||
const allowlistConfig = {
|
||||
gateway: {
|
||||
http: {
|
||||
endpoints: {
|
||||
responses: {
|
||||
enabled: true,
|
||||
maxUrlParts: 1,
|
||||
files: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["cdn.example.com", "*.assets.example.com"],
|
||||
},
|
||||
images: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["images.example.com"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const allowlistConfig = buildResponsesUrlPolicyConfig(1);
|
||||
await writeGatewayConfig(allowlistConfig);
|
||||
|
||||
const allowlistPort = await getFreePort();
|
||||
@@ -639,52 +625,18 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
||||
|
||||
const allowlistBlocked = await postResponses(allowlistPort, {
|
||||
model: "openclaw",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "fetch this" },
|
||||
{
|
||||
type: "input_file",
|
||||
source: { type: "url", url: "https://evil.example.org/secret.txt" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
input: buildUrlInputMessage({
|
||||
kind: "input_file",
|
||||
text: "fetch this",
|
||||
url: "https://evil.example.org/secret.txt",
|
||||
}),
|
||||
});
|
||||
expect(allowlistBlocked.status).toBe(400);
|
||||
const allowlistBlockedJson = (await allowlistBlocked.json()) as {
|
||||
error?: { type?: string; message?: string };
|
||||
};
|
||||
expect(allowlistBlockedJson.error?.type).toBe("invalid_request_error");
|
||||
expect(allowlistBlockedJson.error?.message ?? "").toMatch(
|
||||
/invalid request|allowlist|blocked/i,
|
||||
);
|
||||
await expectInvalidRequest(allowlistBlocked, /invalid request|allowlist|blocked/i);
|
||||
} finally {
|
||||
await allowlistServer.close({ reason: "responses allowlist hardening test done" });
|
||||
}
|
||||
|
||||
const capConfig = {
|
||||
gateway: {
|
||||
http: {
|
||||
endpoints: {
|
||||
responses: {
|
||||
enabled: true,
|
||||
maxUrlParts: 0,
|
||||
files: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["cdn.example.com", "*.assets.example.com"],
|
||||
},
|
||||
images: {
|
||||
allowUrl: true,
|
||||
urlAllowlist: ["images.example.com"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const capConfig = buildResponsesUrlPolicyConfig(0);
|
||||
await writeGatewayConfig(capConfig);
|
||||
|
||||
const capPort = await getFreePort();
|
||||
@@ -693,26 +645,14 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
||||
agentCommand.mockClear();
|
||||
const maxUrlBlocked = await postResponses(capPort, {
|
||||
model: "openclaw",
|
||||
input: [
|
||||
{
|
||||
type: "message",
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: "input_text", text: "fetch this" },
|
||||
{
|
||||
type: "input_file",
|
||||
source: { type: "url", url: "https://cdn.example.com/file-1.txt" },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
input: buildUrlInputMessage({
|
||||
kind: "input_file",
|
||||
text: "fetch this",
|
||||
url: "https://cdn.example.com/file-1.txt",
|
||||
}),
|
||||
});
|
||||
expect(maxUrlBlocked.status).toBe(400);
|
||||
const maxUrlBlockedJson = (await maxUrlBlocked.json()) as {
|
||||
error?: { type?: string; message?: string };
|
||||
};
|
||||
expect(maxUrlBlockedJson.error?.type).toBe("invalid_request_error");
|
||||
expect(maxUrlBlockedJson.error?.message ?? "").toMatch(
|
||||
await expectInvalidRequest(
|
||||
maxUrlBlocked,
|
||||
/invalid request|Too many URL-based input sources/i,
|
||||
);
|
||||
expect(agentCommand).not.toHaveBeenCalled();
|
||||
|
||||
Reference in New Issue
Block a user