From d1ba71d9c6debd47479a17d336868f8a6b0520be Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Thu, 23 Apr 2026 10:19:26 -0700 Subject: [PATCH 1/4] fix(desktop): fail closed when adopted host-service has no version The version gate only killed the host when fetchHostVersion returned a string less than MIN_HOST_SERVICE_VERSION. If the host lacked the host.info route entirely (older releases), the helper returned null and we silently adopted it, producing 404s on project.findByPath and other new routes. Flip the guard to fail-closed: any host that can't prove it meets the minimum version is killed and the manifest removed so the next spawn brings up a compatible service. --- apps/desktop/src/main/lib/host-service-coordinator.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/main/lib/host-service-coordinator.ts b/apps/desktop/src/main/lib/host-service-coordinator.ts index fea4a1d2973..44a4ca24545 100644 --- a/apps/desktop/src/main/lib/host-service-coordinator.ts +++ b/apps/desktop/src/main/lib/host-service-coordinator.ts @@ -294,9 +294,11 @@ export class HostServiceCoordinator extends EventEmitter { manifest.endpoint, manifest.authToken, ); - if (version && version < MIN_HOST_SERVICE_VERSION) { + if (!version || version < MIN_HOST_SERVICE_VERSION) { console.log( - `[host-service:${organizationId}] Adopted service version ${version} < ${MIN_HOST_SERVICE_VERSION}, killing`, + `[host-service:${organizationId}] Adopted service version ${ + version ?? "unknown" + } < ${MIN_HOST_SERVICE_VERSION}, killing`, ); try { process.kill(manifest.pid, "SIGTERM"); From ac2d8454df388291ea76c556b98cd6102a251c9b Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Thu, 23 Apr 2026 11:52:40 -0700 Subject: [PATCH 2/4] fix(desktop): compare host-service versions numerically String comparison made "0.10.0" < "0.2.0" evaluate to true, which would have killed any future double-digit minor version. Split the version on dots and compare segments as integers. Also split the adopt-killing log into two branches so the null case reads "version unknown" instead of "version unknown < 0.2.0". --- .../src/main/lib/host-service-coordinator.ts | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/main/lib/host-service-coordinator.ts b/apps/desktop/src/main/lib/host-service-coordinator.ts index 44a4ca24545..943c0195c52 100644 --- a/apps/desktop/src/main/lib/host-service-coordinator.ts +++ b/apps/desktop/src/main/lib/host-service-coordinator.ts @@ -38,6 +38,22 @@ import { HOOK_PROTOCOL_VERSION } from "./terminal/env"; */ const MIN_HOST_SERVICE_VERSION = "0.2.0"; +function isHostServiceVersionSupported(version: string | null): boolean { + if (!version) return false; + const current = version.split(".").map((n) => Number.parseInt(n, 10)); + const minimum = MIN_HOST_SERVICE_VERSION.split(".").map((n) => + Number.parseInt(n, 10), + ); + for (let i = 0; i < Math.max(current.length, minimum.length); i++) { + const a = current[i] ?? 0; + const b = minimum[i] ?? 0; + if (!Number.isFinite(a)) return false; + if (a > b) return true; + if (a < b) return false; + } + return true; +} + export type HostServiceStatus = "starting" | "running" | "stopped"; export interface Connection { @@ -294,11 +310,12 @@ export class HostServiceCoordinator extends EventEmitter { manifest.endpoint, manifest.authToken, ); - if (!version || version < MIN_HOST_SERVICE_VERSION) { + if (!isHostServiceVersionSupported(version)) { + const reason = version + ? `version ${version} < ${MIN_HOST_SERVICE_VERSION}` + : "version unknown"; console.log( - `[host-service:${organizationId}] Adopted service version ${ - version ?? "unknown" - } < ${MIN_HOST_SERVICE_VERSION}, killing`, + `[host-service:${organizationId}] Adopted service ${reason}, killing`, ); try { process.kill(manifest.pid, "SIGTERM"); From 113f86501e121d4359b61a155158b0a7901dc6ff Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Thu, 23 Apr 2026 13:16:24 -0700 Subject: [PATCH 3/4] refactor(desktop): use semver library for host-service version check Replace the hand-rolled split-and-compare with `semver.satisfies`, which already handles malformed input by returning false. The `semver` package is already a dependency. --- .../src/main/lib/host-service-coordinator.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/main/lib/host-service-coordinator.ts b/apps/desktop/src/main/lib/host-service-coordinator.ts index 943c0195c52..93396a24c8f 100644 --- a/apps/desktop/src/main/lib/host-service-coordinator.ts +++ b/apps/desktop/src/main/lib/host-service-coordinator.ts @@ -7,6 +7,7 @@ import { settings } from "@superset/local-db"; import { getDeviceName, getHashedDeviceId } from "@superset/shared/device-info"; import { app } from "electron"; import { env } from "main/env.main"; +import semver from "semver"; import { env as sharedEnv } from "shared/env.shared"; import { getProcessEnvWithShellPath } from "../../lib/trpc/routers/workspaces/utils/shell-env"; import { SUPERSET_HOME_DIR } from "./app-environment"; @@ -39,19 +40,9 @@ import { HOOK_PROTOCOL_VERSION } from "./terminal/env"; const MIN_HOST_SERVICE_VERSION = "0.2.0"; function isHostServiceVersionSupported(version: string | null): boolean { - if (!version) return false; - const current = version.split(".").map((n) => Number.parseInt(n, 10)); - const minimum = MIN_HOST_SERVICE_VERSION.split(".").map((n) => - Number.parseInt(n, 10), + return ( + !!version && semver.satisfies(version, `>=${MIN_HOST_SERVICE_VERSION}`) ); - for (let i = 0; i < Math.max(current.length, minimum.length); i++) { - const a = current[i] ?? 0; - const b = minimum[i] ?? 0; - if (!Number.isFinite(a)) return false; - if (a > b) return true; - if (a < b) return false; - } - return true; } export type HostServiceStatus = "starting" | "running" | "stopped"; From 8ec6d077fc9a774a120d487a971a8089bac8661c Mon Sep 17 00:00:00 2001 From: Satya Patel Date: Thu, 23 Apr 2026 13:19:20 -0700 Subject: [PATCH 4/4] refactor(desktop): inline host-service version check --- apps/desktop/src/main/lib/host-service-coordinator.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/main/lib/host-service-coordinator.ts b/apps/desktop/src/main/lib/host-service-coordinator.ts index 93396a24c8f..b61fcf3f279 100644 --- a/apps/desktop/src/main/lib/host-service-coordinator.ts +++ b/apps/desktop/src/main/lib/host-service-coordinator.ts @@ -39,12 +39,6 @@ import { HOOK_PROTOCOL_VERSION } from "./terminal/env"; */ const MIN_HOST_SERVICE_VERSION = "0.2.0"; -function isHostServiceVersionSupported(version: string | null): boolean { - return ( - !!version && semver.satisfies(version, `>=${MIN_HOST_SERVICE_VERSION}`) - ); -} - export type HostServiceStatus = "starting" | "running" | "stopped"; export interface Connection { @@ -301,7 +295,10 @@ export class HostServiceCoordinator extends EventEmitter { manifest.endpoint, manifest.authToken, ); - if (!isHostServiceVersionSupported(version)) { + if ( + !version || + !semver.satisfies(version, `>=${MIN_HOST_SERVICE_VERSION}`) + ) { const reason = version ? `version ${version} < ${MIN_HOST_SERVICE_VERSION}` : "version unknown";