bimr-studio/proxy/proxy.test.mjs
2026-09-21 15:33:30 +02:00

172 lines
5.1 KiB
JavaScript

// SPDX-FileCopyrightText: 2026 Milovann Yanatchkov
// SPDX-License-Identifier: MIT
// proxy/proxy.test.mjs — handler tests. Run with:
//
// node --test proxy/proxy.test.mjs
import test, { after, beforeEach } from "node:test";
import assert from "node:assert/strict";
import { handleFetch } from "./proxy.mjs";
const originalFetch = globalThis.fetch;
function stubFetch(impl) {
globalThis.fetch = async (input, init) => {
if (impl) return impl(input, init);
return new Response("upstream-ok", {
status: 200,
headers: { "content-type": "text/plain" },
});
};
}
function proxyRequest(path, init = {}) {
return new Request(`http://studio.test/forge-proxy/${path}`, init);
}
beforeEach(() => {
process.env.FORGE_ALLOWED_HOSTS = "artefacts.bimr.net,*.example.org";
delete process.env.FORGE_ALLOW_ANY;
stubFetch();
});
after(() => {
globalThis.fetch = originalFetch;
});
test("health endpoint identifies the proxy", async () => {
const res = await handleFetch(proxyRequest("__health"));
assert.equal(res.status, 200);
assert.equal(res.headers.get("x-forge-proxy"), "1");
const body = await res.json();
assert.equal(body.ok, true);
});
test("rejects a host outside the allowlist", async () => {
const res = await handleFetch(proxyRequest("https://evil.test/api"));
assert.equal(res.status, 403);
});
test("rejects plain http to a remote host", async () => {
const res = await handleFetch(proxyRequest("http://artefacts.bimr.net/api"));
assert.equal(res.status, 403);
});
test("rejects a request with no target", async () => {
const res = await handleFetch(proxyRequest(""));
assert.equal(res.status, 400);
});
test("treats an unknown scheme-less segment as a host and denies it", async () => {
const res = await handleFetch(proxyRequest("not-a-url"));
assert.equal(res.status, 403);
});
test("wildcard allowlist matches subdomains", async () => {
const res = await handleFetch(proxyRequest("https://api.example.org/x"));
assert.equal(res.status, 200);
});
test("forwards an allowed request and strips browser credentials", async () => {
let seen;
stubFetch((input, init) => {
seen = { input, init };
return new Response("ok", { status: 200 });
});
const request = proxyRequest("https://artefacts.bimr.net/api/v1/version", {
headers: {
cookie: "session=secret",
origin: "http://studio.test",
referer: "http://studio.test/",
authorization: "token abc",
},
});
const res = await handleFetch(request);
assert.equal(res.status, 200);
assert.equal(String(seen.input), "https://artefacts.bimr.net/api/v1/version");
assert.equal(seen.init.headers.get("cookie"), null);
assert.equal(seen.init.headers.get("origin"), null);
assert.equal(seen.init.headers.get("referer"), null);
assert.equal(seen.init.headers.get("authorization"), "token abc");
});
test("forwards a scheme-less target (isomorphic-git corsProxy form)", async () => {
let seen;
stubFetch((input) => {
seen = input;
return new Response("ok", { status: 200 });
});
const res = await handleFetch(
proxyRequest("artefacts.bimr.net/bot/studio-demo.git/info/refs?service=git-upload-pack"),
);
assert.equal(res.status, 200);
assert.equal(
String(seen),
"https://artefacts.bimr.net/bot/studio-demo.git/info/refs?service=git-upload-pack",
);
});
test("handles the extra slash isomorphic-git inserts", async () => {
let seen;
stubFetch((input) => {
seen = input;
return new Response("ok", { status: 200 });
});
const res = await handleFetch(proxyRequest("/artefacts.bimr.net/x"));
assert.equal(res.status, 200);
assert.equal(String(seen), "https://artefacts.bimr.net/x");
});
test("answers CORS preflight without hitting the forge", async () => {
let called = false;
stubFetch(() => {
called = true;
return new Response("nope", { status: 500 });
});
const request = proxyRequest("https://artefacts.bimr.net/api/v1/version", {
method: "OPTIONS",
headers: {
origin: "http://studio.test",
"access-control-request-method": "GET",
"access-control-request-headers": "authorization",
},
});
const res = await handleFetch(request);
assert.equal(res.status, 204);
assert.equal(res.headers.get("access-control-allow-origin"), "http://studio.test");
assert.match(res.headers.get("access-control-allow-headers"), /authorization/i);
assert.equal(called, false);
});
test("drops set-cookie and adds CORS headers to the response", async () => {
stubFetch(
() =>
new Response("ok", {
status: 200,
headers: { "set-cookie": "a=b", "content-type": "text/plain" },
}),
);
const request = proxyRequest("https://artefacts.bimr.net/x", {
headers: { origin: "http://studio.test" },
});
const res = await handleFetch(request);
assert.equal(res.headers.get("set-cookie"), null);
assert.equal(res.headers.get("access-control-allow-origin"), "http://studio.test");
});
test("FORGE_ALLOW_ANY allows any host", async () => {
process.env.FORGE_ALLOW_ANY = "1";
const res = await handleFetch(proxyRequest("https://anything.test/x"));
assert.equal(res.status, 200);
});