T-HUB/packages/egress/src/policy.test.ts
glass beadian aa5e262f3a Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives:
publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style
column wall with hostile-content-safe rendering, live control room with Auto
Director, bridged chat governance with polls and quorum, distributed sandboxed
transcode workers, encrypted content-addressed archive, monthly analytics.

MIT licensed. See README.md and docs/.
2026-10-10 11:56:42 +00:00

35 lines
3.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { assertPublicAddress, EgressPolicy, hostBudgetKey, validateUrl } from "./policy.js";
describe("unified public-address policy", () => {
it.each([
"0.0.0.0", "0.1.2.3", "10.0.0.1", "100.64.0.1", "100.127.255.255", "127.0.0.1", "127.255.1.1",
"169.254.169.254", "169.254.1.1", "172.16.0.1", "172.31.255.255", "192.0.0.1", "192.168.1.1",
"192.0.2.1", "198.18.0.1", "198.19.255.255", "198.51.100.1", "203.0.113.1", "224.0.0.1", "239.1.2.3",
"240.0.0.1", "255.255.255.255", "::", "::1", "[::1]", "fc00::1", "fdff::1", "fe80::1", "fec0::1", "ff02::1",
"2001::1", "2001:db8::1", "2002:0808:0808::1", "64:ff9b::808:808", "64:ff9b:1::1",
"::ffff:127.0.0.1", "::ffff:8.8.8.8", "0:0:0:0:0:ffff:0808:0808", "::8.8.8.8",
])("denies %s", (address) => { expect(() => assertPublicAddress(address)).toThrowError(expect.objectContaining({ code: "DENIED_PRIVATE_ADDRESS" })); });
it.each(["8.8.8.8", "1.1.1.1", "100.63.255.255", "100.128.0.1", "172.15.0.1", "172.32.0.1", "192.169.0.1", "2606:4700:4700::1111", "2001:4860:4860::8888"])("allows %s", (address) => { expect(() => assertPublicAddress(address)).not.toThrow(); });
it.each(["http://2130706433", "http://0177.0.0.1", "http://0x7f000001", "http://127.1", "http://[::ffff:0808:0808]", "http://LOCALHOST.", "http://foo.localhost"])("normalizes then denies %s", (url) => { expect(() => validateUrl(url)).toThrowError(expect.objectContaining({ code: "DENIED_PRIVATE_ADDRESS" })); });
it.each(["file:///etc/passwd", "ftp://example.com", "rtmp://example.com", "concat:foo"])("denies scheme %s", (url) => { expect(() => validateUrl(url)).toThrowError(expect.objectContaining({ code: "SCHEME_DENIED" })); });
it.each(["https://user:secret@example.com", " https://example.com", "https://example.com\n", "https:\\example.com", "-https://example.com"])("denies malformed input %s", (url) => { expect(() => validateUrl(url)).toThrow(); });
it("has per-scheme port allowlists and stable IDNA/effective-port keys", () => {
expect(() => validateUrl("https://example.com:80")).toThrowError(expect.objectContaining({ code: "PORT_DENIED" }));
expect(() => validateUrl("http://example.com:443")).toThrowError(expect.objectContaining({ code: "PORT_DENIED" }));
expect(validateUrl("https://example.com:8443", { ports: { "https:": [443, 8443] } }).port).toBe("8443");
expect(hostBudgetKey(validateUrl("https://BÜCHER.Example.:443/a"))).toBe("xn--bcher-kva.example:443");
expect(hostBudgetKey(validateUrl("http://[2606:4700:4700::1111]"))).toBe("[2606:4700:4700::1111]:80");
});
it("pins one validated answer and rejects mixed or invalid DNS results", async () => {
const resolver = vi.fn().mockResolvedValueOnce([{ address: "8.8.8.8", family: 4 }]).mockResolvedValueOnce([{ address: "127.0.0.1", family: 4 }]);
const policy = new EgressPolicy({ resolver });
expect((await policy.validate("https://example.com")).pinnedAddress).toBe("8.8.8.8");
expect(resolver).toHaveBeenCalledTimes(1);
await expect(policy.validate("https://example.com")).rejects.toMatchObject({ code: "DENIED_PRIVATE_ADDRESS" });
await expect(new EgressPolicy({ resolver: async () => [{ address: "8.8.8.8", family: 4 }, { address: "10.0.0.1", family: 4 }] }).validate("https://example.com")).rejects.toMatchObject({ code: "DENIED_PRIVATE_ADDRESS" });
for (const answer of [[], [{ address: "bogus", family: 4 }]]) {
await expect(new EgressPolicy({ resolver: async () => answer }).validate("https://example.com")).rejects.toMatchObject({ code: "DNS_FAILED" });
}
});
});