mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 20:05:46 -06:00
fix(openai): preserve Azure embedding index across key rotation (#129516)
This commit is contained in:
committed by
GitHub
parent
4f18aeabf3
commit
858d95fa4d
@@ -105,68 +105,94 @@ describe("OpenAI memory embedding adapter", () => {
|
||||
expect(JSON.stringify(current.cacheKeyData)).not.toContain("fixture-secret");
|
||||
});
|
||||
|
||||
it("keeps rotated proxy credentials out of tenant-specific embedding cache identity", async () => {
|
||||
const createForTenant = async (
|
||||
tenant: string,
|
||||
proxyApiKey: string,
|
||||
proxyHeaderName = "X-Api-Key",
|
||||
) => {
|
||||
const client = await resolveRemoteEmbeddingBearerClient({
|
||||
provider: "bailian-embedding",
|
||||
defaultBaseUrl: "https://embeddings.example/v1",
|
||||
options: {
|
||||
config: { models: {} } as never,
|
||||
model: "text-embedding-v3",
|
||||
remote: {
|
||||
apiKey: "fixture-secret",
|
||||
headers: {
|
||||
[proxyHeaderName]: proxyApiKey,
|
||||
"X-Deployment": tenant,
|
||||
"X-Tenant": tenant,
|
||||
version: "tenant-api-v2",
|
||||
"User-Agent": "tenant-client/2",
|
||||
it.each([
|
||||
{
|
||||
name: "proxy",
|
||||
providerId: "bailian-embedding",
|
||||
baseUrl: "https://embeddings.example/v1",
|
||||
headerName: "X-Api-Key",
|
||||
rotatedHeaderName: "x-aPI-kEY",
|
||||
},
|
||||
{
|
||||
name: "Azure OpenAI",
|
||||
providerId: "openai",
|
||||
baseUrl: "https://qa-resource.openai.azure.com/openai/v1",
|
||||
headerName: "api-key",
|
||||
rotatedHeaderName: "Api-Key",
|
||||
},
|
||||
])(
|
||||
"keeps rotated $name credentials out of tenant-specific embedding cache identity",
|
||||
async ({ providerId, baseUrl, headerName, rotatedHeaderName }) => {
|
||||
const createForTenant = async (
|
||||
tenant: string,
|
||||
proxyApiKey: string,
|
||||
proxyHeaderName = headerName,
|
||||
) => {
|
||||
const client = await resolveRemoteEmbeddingBearerClient({
|
||||
provider: providerId,
|
||||
defaultBaseUrl: baseUrl,
|
||||
options: {
|
||||
config: { models: {} } as never,
|
||||
model: "text-embedding-v3",
|
||||
remote: {
|
||||
baseUrl,
|
||||
apiKey: "fixture-secret",
|
||||
headers: {
|
||||
[proxyHeaderName]: proxyApiKey,
|
||||
"X-Deployment": tenant,
|
||||
"X-Tenant": tenant,
|
||||
version: "tenant-api-v2",
|
||||
"User-Agent": "tenant-client/2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(client.headers).toMatchObject({
|
||||
Authorization: "Bearer fixture-secret",
|
||||
[proxyHeaderName]: proxyApiKey,
|
||||
"X-Deployment": tenant,
|
||||
});
|
||||
mocks.createOpenAiEmbeddingProvider.mockResolvedValueOnce({
|
||||
provider,
|
||||
client: { ...client, model: "text-embedding-v3" },
|
||||
});
|
||||
return await openAiMemoryEmbeddingProviderAdapter.create({
|
||||
config: {} as never,
|
||||
provider: "bailian-embedding",
|
||||
model: "text-embedding-v3",
|
||||
fallback: "none",
|
||||
});
|
||||
};
|
||||
});
|
||||
expect(client.headers).toMatchObject({
|
||||
Authorization: "Bearer fixture-secret",
|
||||
[proxyHeaderName]: proxyApiKey,
|
||||
"X-Deployment": tenant,
|
||||
});
|
||||
mocks.createOpenAiEmbeddingProvider.mockResolvedValueOnce({
|
||||
provider,
|
||||
client: { ...client, model: "text-embedding-v3" },
|
||||
});
|
||||
return await openAiMemoryEmbeddingProviderAdapter.create({
|
||||
config: {} as never,
|
||||
provider: providerId,
|
||||
model: "text-embedding-v3",
|
||||
fallback: "none",
|
||||
});
|
||||
};
|
||||
|
||||
const first = await createForTenant("tenant-a", "proxy-key-before-rotation");
|
||||
const rotated = await createForTenant("tenant-a", "proxy-key-after-rotation", "x-aPI-kEY");
|
||||
const second = await createForTenant("tenant-b", "proxy-key-after-rotation");
|
||||
const headers = first.runtime?.cacheKeyData?.headers;
|
||||
const first = await createForTenant("tenant-a", "proxy-key-before-rotation");
|
||||
const rotated = await createForTenant(
|
||||
"tenant-a",
|
||||
"proxy-key-after-rotation",
|
||||
rotatedHeaderName,
|
||||
);
|
||||
const second = await createForTenant("tenant-b", "proxy-key-after-rotation");
|
||||
const headers = first.runtime?.cacheKeyData?.headers;
|
||||
|
||||
expect(headers).toEqual(
|
||||
expect.arrayContaining([
|
||||
["X-Deployment", "tenant-a"],
|
||||
["X-Tenant", "tenant-a"],
|
||||
["version", "tenant-api-v2"],
|
||||
["User-Agent", "tenant-client/2"],
|
||||
]),
|
||||
);
|
||||
expect(first.runtime?.cacheKeyData).toEqual(rotated.runtime?.cacheKeyData);
|
||||
expect(hashText(JSON.stringify(first.runtime?.cacheKeyData))).toBe(
|
||||
hashText(JSON.stringify(rotated.runtime?.cacheKeyData)),
|
||||
);
|
||||
expect(first.runtime?.cacheKeyData).not.toEqual(second.runtime?.cacheKeyData);
|
||||
expect(JSON.stringify(first.runtime?.cacheKeyData)).not.toContain("fixture-secret");
|
||||
expect(JSON.stringify(first.runtime?.cacheKeyData)).not.toContain("proxy-key-before-rotation");
|
||||
});
|
||||
expect(headers).toEqual(
|
||||
expect.arrayContaining([
|
||||
["X-Deployment", "tenant-a"],
|
||||
["X-Tenant", "tenant-a"],
|
||||
["version", "tenant-api-v2"],
|
||||
["User-Agent", "tenant-client/2"],
|
||||
]),
|
||||
);
|
||||
expect(first.runtime?.cacheKeyData).toEqual(rotated.runtime?.cacheKeyData);
|
||||
expect(hashText(JSON.stringify(first.runtime?.cacheKeyData))).toBe(
|
||||
hashText(JSON.stringify(rotated.runtime?.cacheKeyData)),
|
||||
);
|
||||
expect(first.runtime?.cacheKeyData).not.toEqual(second.runtime?.cacheKeyData);
|
||||
expect(JSON.stringify(first.runtime?.cacheKeyData)).not.toContain("fixture-secret");
|
||||
expect(JSON.stringify(first.runtime?.cacheKeyData)).not.toContain(
|
||||
"proxy-key-before-rotation",
|
||||
);
|
||||
expect(first.runtime?.cacheKeyData).toMatchObject({ provider: providerId, baseUrl });
|
||||
},
|
||||
);
|
||||
|
||||
it("sends document input_type in OpenAI batch embedding requests", async () => {
|
||||
const result = await openAiMemoryEmbeddingProviderAdapter.create({
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "./embedding-provider.js";
|
||||
|
||||
function resolveEmbeddingCacheExcludedHeaders(providerId: string, baseUrl: string): string[] {
|
||||
const excludedHeaders = ["authorization", "x-api-key"];
|
||||
const excludedHeaders = ["authorization", "x-api-key", "api-key"];
|
||||
if (providerId !== "openai") {
|
||||
return excludedHeaders;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user