Files
claw3d/tests/unit/customRuntimeRoute.test.ts
gsknnft 051d0ce469 security: harden gateway proxy, custom runtime proxy, and media routes (#95)
* security hardening pass 1 - otel removed

* hardening pass #2

* feat security hardening pass

* chore: trim unrelated docs from security hardening pr

* fix: address security hardening review findings

* address findings
2026-04-03 17:02:06 -05:00

87 lines
2.6 KiB
TypeScript

// @vitest-environment node
import { afterEach, describe, expect, it, vi } from "vitest";
describe("/api/runtime/custom route", () => {
const originalEnv = { ...process.env };
afterEach(() => {
process.env = { ...originalEnv };
vi.restoreAllMocks();
});
it("blocks custom runtime proxying in production when no allowlist is configured", async () => {
Object.assign(process.env, { NODE_ENV: "production" });
delete process.env.CUSTOM_RUNTIME_ALLOWLIST;
delete process.env.UPSTREAM_ALLOWLIST;
const { POST } = await import("@/app/api/runtime/custom/route");
const response = await POST(
new Request("http://localhost/api/runtime/custom", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
runtimeUrl: "http://127.0.0.1:7770",
pathname: "/health",
method: "GET",
}),
})
);
expect(response.status).toBe(400);
await expect(response.json()).resolves.toMatchObject({
error: "runtimeUrl is not in the allowed hosts list.",
});
});
it("allows only listed hosts when a custom runtime allowlist is configured", async () => {
Object.assign(process.env, {
NODE_ENV: "production",
CUSTOM_RUNTIME_ALLOWLIST: "127.0.0.1",
});
const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValueOnce(
new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
);
const { POST } = await import("@/app/api/runtime/custom/route");
const response = await POST(
new Request("http://localhost/api/runtime/custom", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
runtimeUrl: "http://127.0.0.1:7770",
pathname: "/health",
method: "GET",
}),
})
);
expect(response.status).toBe(200);
expect(fetchSpy).toHaveBeenCalledWith(
"http://127.0.0.1:7770/health",
expect.objectContaining({ method: "GET" })
);
});
it("returns 400 for malformed JSON request bodies", async () => {
Object.assign(process.env, { NODE_ENV: "production" });
const { POST } = await import("@/app/api/runtime/custom/route");
const response = await POST(
new Request("http://localhost/api/runtime/custom", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: "{bad json",
})
);
expect(response.status).toBe(400);
await expect(response.json()).resolves.toMatchObject({
error: "Invalid JSON request body.",
});
});
});