mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 05:27:39 +00:00
feat(gateway): add trusted-proxy auth mode (#15940)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 279d4b304f
Co-authored-by: nickytonline <833231+nickytonline@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
This commit is contained in:
@@ -97,4 +97,99 @@ describe("promptGatewayConfig", () => {
|
||||
expect(call?.password).not.toBe("undefined");
|
||||
expect(call?.password).toBe("");
|
||||
});
|
||||
|
||||
it("prompts for trusted-proxy configuration when trusted-proxy mode selected", async () => {
|
||||
vi.clearAllMocks();
|
||||
mocks.resolveGatewayPort.mockReturnValue(18789);
|
||||
// Flow: loopback bind → trusted-proxy auth → tailscale off
|
||||
const selectQueue = ["loopback", "trusted-proxy", "off"];
|
||||
mocks.select.mockImplementation(async () => selectQueue.shift());
|
||||
// Port prompt, userHeader, requiredHeaders, allowUsers, trustedProxies
|
||||
const textQueue = [
|
||||
"18789",
|
||||
"x-forwarded-user",
|
||||
"x-forwarded-proto,x-forwarded-host",
|
||||
"nick@example.com",
|
||||
"10.0.1.10,192.168.1.5",
|
||||
];
|
||||
mocks.text.mockImplementation(async () => textQueue.shift());
|
||||
mocks.buildGatewayAuthConfig.mockImplementation(({ mode, trustedProxy }) => ({
|
||||
mode,
|
||||
trustedProxy,
|
||||
}));
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
|
||||
const result = await promptGatewayConfig({}, runtime);
|
||||
const call = mocks.buildGatewayAuthConfig.mock.calls[0]?.[0];
|
||||
|
||||
expect(call?.mode).toBe("trusted-proxy");
|
||||
expect(call?.trustedProxy).toEqual({
|
||||
userHeader: "x-forwarded-user",
|
||||
requiredHeaders: ["x-forwarded-proto", "x-forwarded-host"],
|
||||
allowUsers: ["nick@example.com"],
|
||||
});
|
||||
expect(result.config.gateway?.bind).toBe("lan");
|
||||
expect(result.config.gateway?.trustedProxies).toEqual(["10.0.1.10", "192.168.1.5"]);
|
||||
});
|
||||
|
||||
it("handles trusted-proxy with no optional fields", async () => {
|
||||
vi.clearAllMocks();
|
||||
mocks.resolveGatewayPort.mockReturnValue(18789);
|
||||
const selectQueue = ["loopback", "trusted-proxy", "off"];
|
||||
mocks.select.mockImplementation(async () => selectQueue.shift());
|
||||
// Port prompt, userHeader (only required), empty requiredHeaders, empty allowUsers, trustedProxies
|
||||
const textQueue = ["18789", "x-remote-user", "", "", "10.0.0.1"];
|
||||
mocks.text.mockImplementation(async () => textQueue.shift());
|
||||
mocks.buildGatewayAuthConfig.mockImplementation(({ mode, trustedProxy }) => ({
|
||||
mode,
|
||||
trustedProxy,
|
||||
}));
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
|
||||
const result = await promptGatewayConfig({}, runtime);
|
||||
const call = mocks.buildGatewayAuthConfig.mock.calls[0]?.[0];
|
||||
|
||||
expect(call?.mode).toBe("trusted-proxy");
|
||||
expect(call?.trustedProxy).toEqual({
|
||||
userHeader: "x-remote-user",
|
||||
// requiredHeaders and allowUsers should be undefined when empty
|
||||
});
|
||||
expect(result.config.gateway?.bind).toBe("lan");
|
||||
expect(result.config.gateway?.trustedProxies).toEqual(["10.0.0.1"]);
|
||||
});
|
||||
|
||||
it("forces tailscale off when trusted-proxy is selected", async () => {
|
||||
vi.clearAllMocks();
|
||||
mocks.resolveGatewayPort.mockReturnValue(18789);
|
||||
const selectQueue = ["loopback", "trusted-proxy", "serve"];
|
||||
mocks.select.mockImplementation(async () => selectQueue.shift());
|
||||
const textQueue = ["18789", "x-forwarded-user", "", "", "10.0.0.1"];
|
||||
mocks.text.mockImplementation(async () => textQueue.shift());
|
||||
mocks.confirm.mockResolvedValue(true);
|
||||
mocks.buildGatewayAuthConfig.mockImplementation(({ mode, trustedProxy }) => ({
|
||||
mode,
|
||||
trustedProxy,
|
||||
}));
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
|
||||
const result = await promptGatewayConfig({}, runtime);
|
||||
expect(result.config.gateway?.bind).toBe("lan");
|
||||
expect(result.config.gateway?.tailscale?.mode).toBe("off");
|
||||
expect(result.config.gateway?.tailscale?.resetOnExit).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user