mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 21:14:31 +00:00
gateway: harden shared auth resolution across systemd, discord, and node host
This commit is contained in:
@@ -10,19 +10,17 @@ type GatewayClientAuth = {
|
||||
token?: string;
|
||||
password?: string;
|
||||
};
|
||||
type ResolveGatewayCredentialsWithSecretInputs = (params: unknown) => Promise<GatewayClientAuth>;
|
||||
type ResolveGatewayConnectionAuth = (params: unknown) => Promise<GatewayClientAuth>;
|
||||
|
||||
const mockState = {
|
||||
gateways: [] as MockGatewayClient[],
|
||||
gatewayAuth: [] as GatewayClientAuth[],
|
||||
agentSideConnectionCtor: vi.fn(),
|
||||
agentStart: vi.fn(),
|
||||
resolveGatewayCredentialsWithSecretInputs: vi.fn<ResolveGatewayCredentialsWithSecretInputs>(
|
||||
async (_params) => ({
|
||||
token: undefined,
|
||||
password: undefined,
|
||||
}),
|
||||
),
|
||||
resolveGatewayConnectionAuth: vi.fn<ResolveGatewayConnectionAuth>(async (_params) => ({
|
||||
token: undefined,
|
||||
password: undefined,
|
||||
})),
|
||||
};
|
||||
|
||||
class MockGatewayClient {
|
||||
@@ -72,11 +70,22 @@ vi.mock("../gateway/auth.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../gateway/call.js", () => ({
|
||||
buildGatewayConnectionDetails: () => ({
|
||||
url: "ws://127.0.0.1:18789",
|
||||
}),
|
||||
resolveGatewayCredentialsWithSecretInputs: (params: unknown) =>
|
||||
mockState.resolveGatewayCredentialsWithSecretInputs(params),
|
||||
buildGatewayConnectionDetails: ({ url }: { url?: string }) => {
|
||||
if (typeof url === "string" && url.trim().length > 0) {
|
||||
return {
|
||||
url: url.trim(),
|
||||
urlSource: "cli --url",
|
||||
};
|
||||
}
|
||||
return {
|
||||
url: "ws://127.0.0.1:18789",
|
||||
urlSource: "local loopback",
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../gateway/connection-auth.js", () => ({
|
||||
resolveGatewayConnectionAuth: (params: unknown) => mockState.resolveGatewayConnectionAuth(params),
|
||||
}));
|
||||
|
||||
vi.mock("../gateway/client.js", () => ({
|
||||
@@ -129,8 +138,8 @@ describe("serveAcpGateway startup", () => {
|
||||
mockState.gatewayAuth.length = 0;
|
||||
mockState.agentSideConnectionCtor.mockReset();
|
||||
mockState.agentStart.mockReset();
|
||||
mockState.resolveGatewayCredentialsWithSecretInputs.mockReset();
|
||||
mockState.resolveGatewayCredentialsWithSecretInputs.mockResolvedValue({
|
||||
mockState.resolveGatewayConnectionAuth.mockReset();
|
||||
mockState.resolveGatewayConnectionAuth.mockResolvedValue({
|
||||
token: undefined,
|
||||
password: undefined,
|
||||
});
|
||||
@@ -178,7 +187,7 @@ describe("serveAcpGateway startup", () => {
|
||||
});
|
||||
|
||||
it("passes resolved SecretInput gateway credentials to the ACP gateway client", async () => {
|
||||
mockState.resolveGatewayCredentialsWithSecretInputs.mockResolvedValue({
|
||||
mockState.resolveGatewayConnectionAuth.mockResolvedValue({
|
||||
token: undefined,
|
||||
password: "resolved-secret-password", // pragma: allowlist secret
|
||||
});
|
||||
@@ -188,7 +197,7 @@ describe("serveAcpGateway startup", () => {
|
||||
const servePromise = serveAcpGateway({});
|
||||
await Promise.resolve();
|
||||
|
||||
expect(mockState.resolveGatewayCredentialsWithSecretInputs).toHaveBeenCalledWith(
|
||||
expect(mockState.resolveGatewayConnectionAuth).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
env: process.env,
|
||||
}),
|
||||
@@ -209,4 +218,33 @@ describe("serveAcpGateway startup", () => {
|
||||
onceSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it("passes CLI URL override context into shared gateway auth resolution", async () => {
|
||||
const { signalHandlers, onceSpy } = captureProcessSignalHandlers();
|
||||
|
||||
try {
|
||||
const servePromise = serveAcpGateway({
|
||||
gatewayUrl: "wss://override.example/ws",
|
||||
});
|
||||
await Promise.resolve();
|
||||
|
||||
expect(mockState.resolveGatewayConnectionAuth).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
env: process.env,
|
||||
urlOverride: "wss://override.example/ws",
|
||||
urlOverrideSource: "cli",
|
||||
}),
|
||||
);
|
||||
|
||||
const gateway = getMockGateway();
|
||||
gateway.emitHello();
|
||||
await vi.waitFor(() => {
|
||||
expect(mockState.agentSideConnectionCtor).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
signalHandlers.get("SIGINT")?.();
|
||||
await servePromise;
|
||||
} finally {
|
||||
onceSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,11 +3,9 @@ import { Readable, Writable } from "node:stream";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import {
|
||||
buildGatewayConnectionDetails,
|
||||
resolveGatewayCredentialsWithSecretInputs,
|
||||
} from "../gateway/call.js";
|
||||
import { buildGatewayConnectionDetails } from "../gateway/call.js";
|
||||
import { GatewayClient } from "../gateway/client.js";
|
||||
import { resolveGatewayConnectionAuth } from "../gateway/connection-auth.js";
|
||||
import { isMainModule } from "../infra/is-main.js";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
|
||||
import { readSecretFromFile } from "./secret-file.js";
|
||||
@@ -20,13 +18,21 @@ export async function serveAcpGateway(opts: AcpServerOptions = {}): Promise<void
|
||||
config: cfg,
|
||||
url: opts.gatewayUrl,
|
||||
});
|
||||
const creds = await resolveGatewayCredentialsWithSecretInputs({
|
||||
const gatewayUrlOverrideSource =
|
||||
connection.urlSource === "cli --url"
|
||||
? "cli"
|
||||
: connection.urlSource === "env OPENCLAW_GATEWAY_URL"
|
||||
? "env"
|
||||
: undefined;
|
||||
const creds = await resolveGatewayConnectionAuth({
|
||||
config: cfg,
|
||||
explicitAuth: {
|
||||
token: opts.gatewayToken,
|
||||
password: opts.gatewayPassword,
|
||||
},
|
||||
env: process.env,
|
||||
urlOverride: gatewayUrlOverrideSource ? connection.url : undefined,
|
||||
urlOverrideSource: gatewayUrlOverrideSource,
|
||||
});
|
||||
|
||||
let agent: AcpGatewayAgent | null = null;
|
||||
|
||||
Reference in New Issue
Block a user