fix(runtime): eliminate hardcoded 20128 port remnants and make loopback URLs dynamic (#13533)

* fix(runtime): eliminate hardcoded 20128 port remnants and make loopback URLs dynamic

- Make model assessment probe base URL resolve dynamically from getRuntimePorts() / env
- Support dynamic loopback in traffic inspector replay route and MITM handlers
- Make WebSocket live server allowlist dynamically include runtime PORT/DASHBOARD_PORT loopback origins
- Update CLI tools config/apply/letta-settings and tool-detector to adapt to configured runtime port
- Update client UI components (EndpointPageClient, ApiExplorerClient, RelayProxyClient) to use current window origin or dynamic port
- Make resolveOmniRouteBaseUrl, useDisplayBaseUrl, and wellKnown.ts respect configured port
- Update package.json electron:dev wait-on to use ${PORT:-20128}
- Add test coverage for custom port in resolveOmniRouteBaseUrl and liveServerAllowList
- Add changelog fragment for PR #13533

* fix(runtime): complete the truncated fallback comment in wellKnown.ts

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
ggdayup
2026-09-19 11:04:02 +08:00
committed by GitHub
parent bf0f213cf0
commit d715190bb0
25 changed files with 139 additions and 45 deletions

View File

@@ -3,10 +3,7 @@ import { PEER_IP_HEADER } from "@/server/authz/headers";
import { resolveStampedPeer } from "@/server/authz/peerStamp";
export type PublicOriginSource =
| "configured"
| "trusted-forwarded"
| "request-url"
| "direct-local-host";
"configured" | "trusted-forwarded" | "request-url" | "direct-local-host";
export interface PublicOriginCandidate {
origin: string;
@@ -200,7 +197,7 @@ function directLocalHostOrigin(request: Request): string | null {
if (classifyHostLocality(peer) === "remote") return null;
const rawHost = trustsForwardedHeaders(request)
? firstHeaderValue(request.headers.get("x-forwarded-host")) ?? request.headers.get("host")
? (firstHeaderValue(request.headers.get("x-forwarded-host")) ?? request.headers.get("host"))
: request.headers.get("host");
const host = sanitizeForwardedHost(rawHost);
if (!host) return null;
@@ -246,7 +243,8 @@ export function resolvePublicOrigin(request: Request): PublicOriginCandidate {
const requestOrigin = requestUrlOrigin(request);
if (requestOrigin) return { origin: requestOrigin, source: "request-url" };
return { origin: "http://localhost:20128", source: "request-url" };
const defaultPort = process.env.PORT || process.env.DASHBOARD_PORT || "20128";
return { origin: `http://localhost:${defaultPort}`, source: "request-url" };
}
export function validateBrowserMutationOrigin(request: Request): BrowserMutationOriginVerdict {

View File

@@ -45,7 +45,17 @@ export function parseCsvEnv(value: string | undefined | null): Set<string> {
*/
export function buildAllowedOrigins(env: NodeJS.ProcessEnv = process.env): Set<string> {
const extra = parseCsvEnv(env.LIVE_WS_ALLOWED_ORIGINS);
return new Set([...DEFAULT_ALLOWED_ORIGINS, ...extra]);
const runtimePort = env.PORT || env.DASHBOARD_PORT;
const dynamicDefaults: string[] = [];
if (runtimePort && runtimePort !== "20128") {
dynamicDefaults.push(
`http://127.0.0.1:${runtimePort}`,
`http://localhost:${runtimePort}`,
`http://[::1]:${runtimePort}`,
`http://0.0.0.0:${runtimePort}`
);
}
return new Set([...DEFAULT_ALLOWED_ORIGINS, ...dynamicDefaults, ...extra]);
}
/**