fix: seed control UI origins for bind aliases · openclaw/openclaw@b0b18d1
steipete
·
2026-05-18
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -51,6 +51,7 @@ Docs: https://docs.openclaw.ai
|
51 | 51 | - Agents/OpenAI streams: yield via `setTimeout(0)` instead of `setImmediate` between bursty Responses chunks so abort timers can fire during the yield, keeping cancel-on-timeout responsive on hot streams. Refs #82462. |
52 | 52 | - Agents/Codex: keep legacy `oauthRef`-backed OAuth profiles usable while `openclaw doctor --fix` migrates them back to inline credentials, without creating new sidecar credentials. (#83312) Thanks @joshavant. |
53 | 53 | - CLI/config: send SecretRef diagnostics to stderr so JSON command stdout remains parseable. |
| 54 | +- CLI/doctor: seed Control UI allowed origins when migrating legacy non-loopback gateway bind host aliases like `0.0.0.0`. Fixes #83286. Thanks @giodl73-repo. |
54 | 55 | - CLI/plugins: ship the bundled memory CLI as a package entry so package-installed `openclaw memory` commands register correctly. |
55 | 56 | - CLI/update: defer doctor-time plugin package installs during package swaps and seed post-core repair from the updated install registry, preventing duplicate reinstall failures. |
56 | 57 | - Feishu: detect SecretRef top-level credentials as a configured default account instead of treating object-backed app secrets as missing. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -945,4 +945,34 @@ describe("legacy migrate controlUi.allowedOrigins seed (issue #29385)", () => {
|
945 | 945 | "http://127.0.0.1:18789", |
946 | 946 | ]); |
947 | 947 | }); |
| 948 | + |
| 949 | +it("seeds allowedOrigins for non-loopback host aliases before normalizing bind", () => { |
| 950 | +const res = migrateLegacyConfigForTest({ |
| 951 | +gateway: { |
| 952 | +bind: "0.0.0.0", |
| 953 | +auth: { mode: "token", token: "tok" }, |
| 954 | +}, |
| 955 | +}); |
| 956 | +expect(res.config?.gateway?.bind).toBe("lan"); |
| 957 | +expect(res.config?.gateway?.controlUi?.allowedOrigins).toEqual([ |
| 958 | +"http://localhost:18789", |
| 959 | +"http://127.0.0.1:18789", |
| 960 | +]); |
| 961 | +expect(res.changes).toStrictEqual([ |
| 962 | +'Seeded gateway.controlUi.allowedOrigins ["http://localhost:18789","http://127.0.0.1:18789"] for bind=lan. Required since v2026.2.26. Add other machine origins to gateway.controlUi.allowedOrigins if needed.', |
| 963 | +'Normalized gateway.bind "0.0.0.0" → "lan".', |
| 964 | +]); |
| 965 | +}); |
| 966 | + |
| 967 | +it("does not seed allowedOrigins for loopback host aliases", () => { |
| 968 | +const res = migrateLegacyConfigForTest({ |
| 969 | +gateway: { |
| 970 | +bind: "localhost", |
| 971 | +auth: { mode: "token", token: "tok" }, |
| 972 | +}, |
| 973 | +}); |
| 974 | +expect(res.config?.gateway?.bind).toBe("loopback"); |
| 975 | +expect(res.config?.gateway?.controlUi).toBeUndefined(); |
| 976 | +expect(res.changes).toStrictEqual(['Normalized gateway.bind "localhost" → "loopback".']); |
| 977 | +}); |
948 | 978 | }); |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -22,9 +22,13 @@ const GATEWAY_BIND_RULE: LegacyConfigRule = {
|
22 | 22 | }; |
23 | 23 | |
24 | 24 | function isLegacyGatewayBindHostAlias(value: unknown): boolean { |
| 25 | +return normalizeLegacyGatewayBindHostAlias(value) !== null; |
| 26 | +} |
| 27 | + |
| 28 | +function normalizeLegacyGatewayBindHostAlias(value: unknown): "lan" | "loopback" | null { |
25 | 29 | const normalized = normalizeOptionalLowercaseString(value); |
26 | 30 | if (!normalized) { |
27 | | -return false; |
| 31 | +return null; |
28 | 32 | } |
29 | 33 | if ( |
30 | 34 | normalized === "auto" || |
@@ -33,18 +37,25 @@ function isLegacyGatewayBindHostAlias(value: unknown): boolean {
|
33 | 37 | normalized === "tailnet" || |
34 | 38 | normalized === "custom" |
35 | 39 | ) { |
36 | | -return false; |
| 40 | +return null; |
37 | 41 | } |
38 | | -return ( |
| 42 | +if ( |
39 | 43 | normalized === "0.0.0.0" || |
40 | 44 | normalized === "::" || |
41 | 45 | normalized === "[::]" || |
42 | | -normalized === "*" || |
| 46 | +normalized === "*" |
| 47 | +) { |
| 48 | +return "lan"; |
| 49 | +} |
| 50 | +if ( |
43 | 51 | normalized === "127.0.0.1" || |
44 | 52 | normalized === "localhost" || |
45 | 53 | normalized === "::1" || |
46 | 54 | normalized === "[::1]" |
47 | | -); |
| 55 | +) { |
| 56 | +return "loopback"; |
| 57 | +} |
| 58 | +return null; |
48 | 59 | } |
49 | 60 | |
50 | 61 | function escapeControlForLog(value: string): string { |
@@ -60,7 +71,7 @@ export const LEGACY_CONFIG_MIGRATIONS_RUNTIME_GATEWAY: LegacyConfigMigrationSpec
|
60 | 71 | if (!gateway) { |
61 | 72 | return; |
62 | 73 | } |
63 | | -const bind = gateway.bind; |
| 74 | +const bind = normalizeLegacyGatewayBindHostAlias(gateway.bind) ?? gateway.bind; |
64 | 75 | if (!isGatewayNonLoopbackBindMode(bind)) { |
65 | 76 | return; |
66 | 77 | } |
@@ -107,22 +118,7 @@ export const LEGACY_CONFIG_MIGRATIONS_RUNTIME_GATEWAY: LegacyConfigMigrationSpec
|
107 | 118 | if (!normalized) { |
108 | 119 | return; |
109 | 120 | } |
110 | | -let mapped: "lan" | "loopback" | undefined; |
111 | | -if ( |
112 | | -normalized === "0.0.0.0" || |
113 | | -normalized === "::" || |
114 | | -normalized === "[::]" || |
115 | | -normalized === "*" |
116 | | -) { |
117 | | -mapped = "lan"; |
118 | | -} else if ( |
119 | | -normalized === "127.0.0.1" || |
120 | | -normalized === "localhost" || |
121 | | -normalized === "::1" || |
122 | | -normalized === "[::1]" |
123 | | -) { |
124 | | -mapped = "loopback"; |
125 | | -} |
| 121 | +const mapped = normalizeLegacyGatewayBindHostAlias(bindRaw); |
126 | 122 | |
127 | 123 | if (!mapped || normalized === mapped) { |
128 | 124 | return; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。