Allow manual remote URL after trust decline

This commit is contained in:
Tak Hoffman 2026-03-27 15:11:35 -05:00
parent c3d45fbb19
commit 8bcab7ec6f
No known key found for this signature in database
2 changed files with 26 additions and 19 deletions

View File

@ -119,7 +119,7 @@ describe("promptRemoteGatewayConfig", () => {
);
});
it("rejects discovery endpoint when trust confirmation is declined", async () => {
it("falls back to manual URL entry when discovery trust is declined", async () => {
detectBinary.mockResolvedValue(true);
discoverGatewayBeacons.mockResolvedValue([
{
@ -135,6 +135,14 @@ describe("promptRemoteGatewayConfig", () => {
"Select gateway": "0",
"Connection method": "direct",
});
const manualUrl = "wss://manual.example.com:18789";
const text: WizardPrompter["text"] = vi.fn(async (params) => {
if (params.message === "Gateway WebSocket URL") {
expect(params.initialValue).toBe("wss://evil.example:443");
return manualUrl;
}
return "";
}) as WizardPrompter["text"];
const confirm: WizardPrompter["confirm"] = vi.fn(async (params) => {
if (params.message.startsWith("Discover gateway")) {
return true;
@ -148,12 +156,14 @@ describe("promptRemoteGatewayConfig", () => {
const prompter = createPrompter({
confirm,
select,
text: vi.fn(async () => "") as WizardPrompter["text"],
text,
});
await expect(promptRemoteGatewayConfig({} as OpenClawConfig, prompter)).rejects.toThrow(
"not trusted",
);
const next = await promptRemoteGatewayConfig({} as OpenClawConfig, prompter);
expect(next.gateway?.mode).toBe("remote");
expect(next.gateway?.remote?.url).toBe(manualUrl);
expect(next.gateway?.remote?.tlsFingerprint).toBeUndefined();
});
it("trusts discovery endpoint without fingerprint and omits tlsFingerprint", async () => {

View File

@ -120,22 +120,19 @@ export async function promptRemoteGatewayConfig(
message: `Trust this gateway? Host: ${host}:${port} TLS fingerprint: ${fingerprint ?? "not advertised (connection will not be pinned)"}`,
initialValue: false,
});
if (!trusted) {
throw new Error(
`Discovery endpoint ${host}:${port} not trusted. Re-run onboarding or enter the URL manually.`,
if (trusted) {
discoveryTlsFingerprint = fingerprint;
trustedDiscoveryUrl = suggestedUrl;
await prompter.note(
[
"Direct remote access defaults to TLS.",
`Using: ${suggestedUrl}`,
...(fingerprint ? [`TLS pin: ${fingerprint}`] : []),
"If your gateway is loopback-only, choose SSH tunnel and keep ws://127.0.0.1:18789.",
].join("\n"),
"Direct remote",
);
}
discoveryTlsFingerprint = fingerprint;
trustedDiscoveryUrl = suggestedUrl;
await prompter.note(
[
"Direct remote access defaults to TLS.",
`Using: ${suggestedUrl}`,
...(fingerprint ? [`TLS pin: ${fingerprint}`] : []),
"If your gateway is loopback-only, choose SSH tunnel and keep ws://127.0.0.1:18789.",
].join("\n"),
"Direct remote",
);
} else {
suggestedUrl = DEFAULT_GATEWAY_URL;
await prompter.note(