fix(studio): keep AI provider and model details private
This commit is contained in:
1 parent
5aec369054
commit
6d0c47fba7
5 files changed
+65
-51
No files matched your search
+40
-18
@@ -86,8 +86,9 @@ test("AI proposals use engine validation, preserve draft source, locks and revis
|
||||
const response = await handler(await request());
|
||||
const batch = await response!.json();
|
||||
expect(batch.alternatives).toHaveLength(3);
|
||||
expect(batch.provenance.provider).toBe("APIMart");
|
||||
expect(batch.provenance.model).toBe("gpt-5-mini");
|
||||
expect(batch.provenance.provider).toBe("AI");
|
||||
expect(batch.provenance.model).toBeUndefined();
|
||||
expect(JSON.stringify(batch)).not.toMatch(/APIMart|gpt-5-mini|custom-model/i);
|
||||
expect(JSON.stringify(system)).toBe(original);
|
||||
const locked = await handler(
|
||||
await request(await input(["/tokens/shape.control"])),
|
||||
@@ -114,7 +115,7 @@ test("metadata and errors never contain the key or raw upstream response", async
|
||||
new Request("https://components.example/design-studio/api/generation"),
|
||||
);
|
||||
const text = await meta!.text();
|
||||
expect(text).toContain("gpt-5-mini");
|
||||
expect(text).not.toMatch(/apimart|gpt-5-mini/i);
|
||||
expect(JSON.parse(text).timeoutMs).toBe(AI_TIMEOUT_MS);
|
||||
expect(AI_TIMEOUT_MS).toBe(60_000);
|
||||
expect(text).not.toContain("test-secret");
|
||||
@@ -122,6 +123,7 @@ test("metadata and errors never contain the key or raw upstream response", async
|
||||
const body = await failure!.text();
|
||||
expect(body).not.toContain("test-secret");
|
||||
expect(body).not.toContain("upstream credentials");
|
||||
expect(body).not.toMatch(/APIMart|APIMART_API_KEY|gpt-5-mini/i);
|
||||
expect(body).toContain("WRN-STUDIO-PROVIDER");
|
||||
});
|
||||
|
||||
@@ -139,7 +141,7 @@ test("a completion beyond the old 20-second deadline produces three validated al
|
||||
expect(response!.status).toBe(200);
|
||||
const batch = await response!.json();
|
||||
expect(batch.alternatives).toHaveLength(3);
|
||||
expect(batch.provenance.provider).toBe("APIMart");
|
||||
expect(batch.provenance.provider).toBe("AI");
|
||||
expect(JSON.stringify(system)).toBe(original);
|
||||
}, 30_000);
|
||||
|
||||
@@ -186,9 +188,9 @@ test("same-origin checks, body bounds and local fallback remain enforced", async
|
||||
'<head><script type="module"></script></head><div id="diagnostics"></div>',
|
||||
false,
|
||||
),
|
||||
).toContain("APIMART_API_KEY");
|
||||
).not.toMatch(/APIMART|gpt-/i);
|
||||
expect(addStudioGuide('<div id="diagnostics"></div>', true)).toContain(
|
||||
"APIMart AI is enabled",
|
||||
"AI design assistance is available",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -225,9 +227,9 @@ test("temporary APIMart failures retry once and return three validated designs",
|
||||
|
||||
test("authentication and quota failures provide actionable redacted diagnostics without retrying", async () => {
|
||||
for (const [status, code, hint] of [
|
||||
[401, "invalid_api_key", "server API key"],
|
||||
[402, "insufficient_quota", "credit or quota"],
|
||||
[404, "model_not_found", "configured model"],
|
||||
[401, "invalid_api_key", "server configuration issue"],
|
||||
[402, "insufficient_quota", "service usage limit"],
|
||||
[404, "model_not_found", "server configuration issue"],
|
||||
] as const) {
|
||||
let calls = 0;
|
||||
const handler = studioAI(
|
||||
@@ -296,7 +298,7 @@ test("network and repeated rate failures remain bounded and describe the actual
|
||||
const body = await (await handler(await request()))!.text();
|
||||
expect(calls).toBe(2);
|
||||
expect(body).toContain(
|
||||
network ? "could not reach APIMart" : "rate limiting",
|
||||
network ? "could not reach the AI service" : "rate limiting",
|
||||
);
|
||||
expect(body).not.toContain("test-secret");
|
||||
}
|
||||
@@ -421,14 +423,34 @@ test("the configured model is used consistently for metadata and upstream reques
|
||||
const metadata = await (await handler(
|
||||
new Request("https://components.example/design-studio/api/generation"),
|
||||
))!.json();
|
||||
expect(metadata.model).toBe("custom-model");
|
||||
expect(metadata.model).toBeUndefined();
|
||||
const batch = await (await handler(await request()))!.json();
|
||||
expect(selected).toBe("custom-model");
|
||||
expect(batch.provenance.model).toBe("custom-model");
|
||||
expect(
|
||||
addStudioGuide('<div id="diagnostics"></div>', true, "custom-model"),
|
||||
).toContain("custom-model");
|
||||
expect(
|
||||
addStudioGuide('<div id="diagnostics"></div>', true, "<script>"),
|
||||
).not.toContain("with <script>");
|
||||
expect(batch.provenance.model).toBeUndefined();
|
||||
expect(JSON.stringify(batch)).not.toMatch(/APIMart|gpt-5-mini|custom-model/i);
|
||||
expect(addStudioGuide('<div id="diagnostics"></div>', true)).not.toMatch(
|
||||
/APIMart|custom-model|gpt-/i,
|
||||
);
|
||||
});
|
||||
|
||||
test("all public AI failure categories hide provider and model configuration", async () => {
|
||||
for (const status of [400, 401, 402, 403, 404, 429, 500]) {
|
||||
const handler = studioAI(
|
||||
"test-secret",
|
||||
mockFetch(
|
||||
async () =>
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
error: { message: "APIMart custom-secret-model" },
|
||||
}),
|
||||
{ status },
|
||||
),
|
||||
),
|
||||
"custom-secret-model",
|
||||
);
|
||||
const response = await handler(await request());
|
||||
expect(await response!.text()).not.toMatch(
|
||||
/APIMart|custom-secret-model|test-secret/i,
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user