openclaw/src/config/config.gateway-tailscale-bind.test.ts
Peter Steinberger 53d10f8688 fix(gateway): land access/auth/config migration cluster
Land #28960 by @Glucksberg (Tailscale origin auto-allowlist).
Land #29394 by @synchronic1 (allowedOrigins upgrade migration).
Land #29198 by @Mariana-Codebase (plugin HTTP auth guard + route precedence).
Land #30910 by @liuxiaopai-ai (tailscale bind/config.patch guard).

Co-authored-by: Glucksberg <markuscontasul@gmail.com>
Co-authored-by: synchronic1 <synchronic1@users.noreply.github.com>
Co-authored-by: Mariana Sinisterra <mariana.data@outlook.com>
Co-authored-by: liuxiaopai-ai <73659136+liuxiaopai-ai@users.noreply.github.com>
2026-03-02 00:10:51 +00:00

80 lines
2.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { validateConfigObject } from "./config.js";
describe("gateway tailscale bind validation", () => {
it("accepts loopback bind when tailscale serve/funnel is enabled", () => {
const serveRes = validateConfigObject({
gateway: {
bind: "loopback",
tailscale: { mode: "serve" },
},
});
expect(serveRes.ok).toBe(true);
const funnelRes = validateConfigObject({
gateway: {
bind: "loopback",
tailscale: { mode: "funnel" },
},
});
expect(funnelRes.ok).toBe(true);
});
it("accepts custom loopback bind host with tailscale serve/funnel", () => {
const res = validateConfigObject({
gateway: {
bind: "custom",
customBindHost: "127.0.0.1",
tailscale: { mode: "serve" },
},
});
expect(res.ok).toBe(true);
});
it("rejects IPv6 custom bind host for tailscale serve/funnel", () => {
const res = validateConfigObject({
gateway: {
bind: "custom",
customBindHost: "::1",
tailscale: { mode: "serve" },
},
});
expect(res.ok).toBe(false);
if (!res.ok) {
expect(res.issues.some((issue) => issue.path === "gateway.bind")).toBe(true);
}
});
it("rejects non-loopback bind when tailscale serve/funnel is enabled", () => {
const lanRes = validateConfigObject({
gateway: {
bind: "lan",
tailscale: { mode: "serve" },
},
});
expect(lanRes.ok).toBe(false);
if (!lanRes.ok) {
expect(lanRes.issues).toEqual(
expect.arrayContaining([
expect.objectContaining({
path: "gateway.bind",
message: expect.stringContaining("gateway.bind must resolve to loopback"),
}),
]),
);
}
const customRes = validateConfigObject({
gateway: {
bind: "custom",
customBindHost: "10.0.0.5",
tailscale: { mode: "funnel" },
},
});
expect(customRes.ok).toBe(false);
if (!customRes.ok) {
expect(customRes.issues.some((issue) => issue.path === "gateway.bind")).toBe(true);
}
});
});