diff --git a/server/network-policy.js b/server/network-policy.js index 1bf6457..70bb452 100644 --- a/server/network-policy.js +++ b/server/network-policy.js @@ -63,11 +63,15 @@ const isPublicHost = (host) => { return true; }; -const assertPublicHostAllowed = ({ host, studioAccessToken }) => { +const allowPublicHostWithoutStudioToken = (env = process.env) => + /^(1|true)$/i.test(String(env.ALLOW_PUBLIC_HOST_WITHOUT_STUDIO_TOKEN ?? "").trim()); + +const assertPublicHostAllowed = ({ host, studioAccessToken, env = process.env }) => { if (!isPublicHost(host)) return; const token = String(studioAccessToken ?? "").trim(); if (token) return; + if (allowPublicHostWithoutStudioToken(env)) return; const normalized = normalizeHost(host) || String(host ?? "").trim() || "(unknown)"; throw new Error( @@ -77,6 +81,7 @@ const assertPublicHostAllowed = ({ host, studioAccessToken }) => { }; module.exports = { + allowPublicHostWithoutStudioToken, resolveHosts, resolveHost, isPublicHost, diff --git a/tests/unit/serverNetworkPolicy.test.ts b/tests/unit/serverNetworkPolicy.test.ts index 6351fe8..75fec08 100644 --- a/tests/unit/serverNetworkPolicy.test.ts +++ b/tests/unit/serverNetworkPolicy.test.ts @@ -58,4 +58,17 @@ describe("server network policy", () => { assertPublicHostAllowed({ host: "0.0.0.0", studioAccessToken: "abc" }) ).not.toThrow(); }); + + it("allows public bind when explicitly opted in for managed deployments", async () => { + const { assertPublicHostAllowed } = await import("../../server/network-policy"); + expect(() => + assertPublicHostAllowed({ + host: "0.0.0.0", + studioAccessToken: "", + env: { + ALLOW_PUBLIC_HOST_WITHOUT_STUDIO_TOKEN: "true", + } as unknown as NodeJS.ProcessEnv, + }) + ).not.toThrow(); + }); });