fix(confidence-engine): sanitize public health response
This commit is contained in:
+11
-27
@@ -3,47 +3,31 @@ import { getConfig } from "@/lib/config";
|
|||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
const result = getConfig();
|
const result = getConfig();
|
||||||
|
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
return Response.json({
|
return Response.json({ healthy: false }, { status: 500 });
|
||||||
configPresent: false,
|
|
||||||
baseUrl: null,
|
|
||||||
model: null,
|
|
||||||
reachable: false,
|
|
||||||
error: "Missing or invalid environment configuration",
|
|
||||||
}, { status: 500 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { OLLAMA_BASE_URL, OLLAMA_MODEL } = result.config;
|
const { OLLAMA_BASE_URL, OLLAMA_MODEL } = result.config;
|
||||||
|
|
||||||
// Test reachability with a short timeout
|
// Test reachability with a short timeout
|
||||||
let reachable = false;
|
let reachable = false;
|
||||||
let reachError = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeout = setTimeout(() => controller.abort(), 3000);
|
const timeout = setTimeout(() => controller.abort(), 3000);
|
||||||
|
|
||||||
const res = await fetch(`${OLLAMA_BASE_URL}/api/tags`, {
|
const res = await fetch(`${OLLAMA_BASE_URL}/api/tags`, {
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
});
|
});
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
reachable = res.ok;
|
reachable = res.ok;
|
||||||
} catch (e) {
|
} catch {
|
||||||
reachError = e.message || "Connection failed";
|
reachable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response.json({
|
return Response.json({ healthy: reachable }, { status: reachable ? 200 : 503 });
|
||||||
configPresent: true,
|
} catch {
|
||||||
baseUrl: OLLAMA_BASE_URL,
|
return Response.json({ healthy: false }, { status: 500 });
|
||||||
model: OLLAMA_MODEL,
|
|
||||||
reachable,
|
|
||||||
error: reachable ? null : (`Could not reach Ollama at ${OLLAMA_BASE_URL}: ${reachError || "timeout"}`),
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
return Response.json(
|
|
||||||
{ configPresent: false, error: e.message },
|
|
||||||
{ status: 500 }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,15 +58,30 @@ describe("authenticated product boundary", () => {
|
|||||||
expect(magicLinkRedirectTo("http://localhost:3000")).toBe("http://localhost:3000/auth/callback");
|
expect(magicLinkRedirectTo("http://localhost:3000")).toBe("http://localhost:3000/auth/callback");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps infrastructure health public", async () => {
|
it("keeps infrastructure health public and does not leak config details", async () => {
|
||||||
|
mockGetConfig.mockReturnValue({ ok: true, config: {} });
|
||||||
|
const { GET } = await import("@/app/api/health/route.js");
|
||||||
|
|
||||||
|
const response = await GET();
|
||||||
|
|
||||||
|
expect(mockGetAuthenticatedUser).not.toHaveBeenCalled();
|
||||||
|
const body = await response.json();
|
||||||
|
expect(body).toHaveProperty("healthy");
|
||||||
|
// Must not expose private config details in the public response
|
||||||
|
expect(JSON.stringify(body)).not.toContain("baseUrl");
|
||||||
|
expect(JSON.stringify(body)).not.toContain("model");
|
||||||
|
expect(JSON.stringify(body)).not.toContain("ollama");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports unhealthy generic state when config is missing", async () => {
|
||||||
mockGetConfig.mockReturnValue({ ok: false });
|
mockGetConfig.mockReturnValue({ ok: false });
|
||||||
const { GET } = await import("@/app/api/health/route.js");
|
const { GET } = await import("@/app/api/health/route.js");
|
||||||
|
|
||||||
const response = await GET();
|
const response = await GET();
|
||||||
|
|
||||||
expect(response.status).toBe(500);
|
expect(response.status).toBe(500);
|
||||||
await expect(response.json()).resolves.toMatchObject({ configPresent: false });
|
const body = await response.json();
|
||||||
expect(mockGetAuthenticatedUser).not.toHaveBeenCalled();
|
expect(body).toEqual({ healthy: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not convert /api/health to 401 via middleware when unauthenticated", async () => {
|
it("does not convert /api/health to 401 via middleware when unauthenticated", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user