fix(openrouter): forward safe music request policy (#104835)

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Alix-007
2026-07-16 00:40:45 -07:00
committed by GitHub
co-authored by Peter Steinberger
parent e868a1dbd1
commit 1c7ad75966
3 changed files with 140 additions and 0 deletions
@@ -297,6 +297,45 @@ describe("openrouter music generation provider", () => {
);
});
it("applies configured OpenRouter request policy without allowing private networks", async () => {
const requestPolicy = {
allowPrivateNetwork: true,
headers: { "X-OpenRouter-Trace": "trace-1" },
proxy: { mode: "env-proxy" as const },
};
postJsonRequestMock.mockResolvedValue({
response: sseResponse([
`data: ${JSON.stringify({ choices: [{ delta: { audio: { data: Buffer.from("wav").toString("base64") } } }] })}\n`,
"data: [DONE]\n",
]),
release: vi.fn(async () => {}),
});
await buildOpenRouterMusicGenerationProvider().generateMusic({
provider: "openrouter",
model: "google/lyria-3-pro-preview",
prompt: "policy soundtrack",
cfg: {
models: {
providers: {
openrouter: {
request: requestPolicy,
},
},
},
} as never,
});
expect(resolveProviderHttpRequestConfigMock).toHaveBeenCalledWith(
expect.objectContaining({
provider: "openrouter",
capability: "audio",
allowPrivateNetwork: false,
request: requestPolicy,
}),
);
});
it("times out stalled OpenRouter audio streams after headers", async () => {
postJsonRequestMock.mockResolvedValue({
response: stalledSseResponse(
@@ -0,0 +1,97 @@
// OpenRouter transport tests cover real provider-http request policy enforcement.
import { createServer, type Server } from "node:http";
import type { AddressInfo } from "node:net";
import { afterEach, describe, expect, it, vi } from "vitest";
const resolveApiKeyForProviderMock = vi.hoisted(() =>
vi.fn(async () => ({
apiKey: "test",
source: "profile",
mode: "api-key",
})),
);
vi.mock("openclaw/plugin-sdk/provider-auth-runtime", () => ({
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
}));
async function buildTransportProofProvider() {
vi.resetModules();
vi.doUnmock("openclaw/plugin-sdk/provider-http");
vi.doMock("openclaw/plugin-sdk/provider-auth-runtime", () => ({
resolveApiKeyForProvider: resolveApiKeyForProviderMock,
}));
const { buildOpenRouterMusicGenerationProvider } = await import("./music-generation-provider.js");
return buildOpenRouterMusicGenerationProvider();
}
const openServers: Server[] = [];
async function startPrivateMusicServer(): Promise<{
baseUrl: string;
requestCount: () => number;
}> {
let requests = 0;
const server = createServer((_request, response) => {
requests += 1;
response.writeHead(204);
response.end();
});
openServers.push(server);
await new Promise<void>((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
server.off("error", reject);
resolve();
});
});
const address = server.address() as AddressInfo;
return {
baseUrl: `http://127.0.0.1:${address.port}/api/v1`,
requestCount: () => requests,
};
}
async function closeOpenServers() {
await Promise.all(
openServers.splice(0).map(
(server) =>
new Promise<void>((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
}),
),
);
}
describe("openrouter music generation provider transport", () => {
afterEach(async () => {
await closeOpenServers();
});
it("denies private destinations even when the configured request policy opts in", async () => {
const server = await startPrivateMusicServer();
const provider = await buildTransportProofProvider();
await expect(
provider.generateMusic({
provider: "openrouter",
model: "google/lyria-3-pro-preview",
prompt: "transport denial proof",
cfg: {
models: {
providers: {
openrouter: {
baseUrl: server.baseUrl,
request: {
allowPrivateNetwork: true,
headers: { "X-OpenRouter-Trace": "transport-proof" },
},
},
},
},
} as never,
}),
).rejects.toThrow(/private|internal|blocked/i);
expect(server.requestCount()).toBe(0);
});
});
@@ -15,6 +15,7 @@ import {
postJsonRequest,
resolveProviderHttpRequestConfig,
resolveProviderOperationTimeoutMs,
sanitizeConfiguredModelProviderRequest,
type ProviderOperationDeadline,
} from "openclaw/plugin-sdk/provider-http";
import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -393,6 +394,9 @@ export function buildOpenRouterMusicGenerationProvider(): MusicGenerationProvide
"HTTP-Referer": "https://openclaw.ai",
"X-OpenRouter-Title": "OpenClaw",
},
request: sanitizeConfiguredModelProviderRequest(
req.cfg?.models?.providers?.openrouter?.request,
),
provider: "openrouter",
capability: "audio",
transport: "http",