fix(cli,host-service): surface host cloud-registration failures instead of silent "Not found"

Merged
KI
3mo ago
+386-107

Closes #6415.

Problem

A host only becomes visible server-side via host.ensure, called once inside connectRelay at host-service boot. If that call failed (expired token, transient API failure, org mismatch), the failure was swallowed: the service kept running and passed local health checks, superset hosts list returned [], and every automations create variant failed with a bare Error: Not found — the CLI blanked the server's "Host not found" message, and on CLI-only installs the daemon's stdio was ignored, so the registration error was recorded nowhere.

Full diagnosis + verified before/after repro: https://github.com/superset-sh/superset/issues/6415#issuecomment-5276360971

Changes

Make the failure self-diagnosing

  • cli-framework/runner.ts: NOT_FOUND now prints the server's message (extracted a testable formatError)
  • trpc verifyHostAccess: NOT_FOUND message names the host — Host <machineId> is not registered in this organization
  • cli resolveAutomationTarget: preflights the target host against host.list in all modes (including the session-mode early return that previously validated nothing) and raises a CLIError with a restart hint

Stop registration failing silently

  • host-service connectRelay: retries host.ensure with capped backoff (30s → 5min, indefinitely) instead of one-shot; outcome recorded in a registration-state module
  • host-service health.check: now returns cloudRegistered / registrationError
  • cli status: warns when the host is running but not cloud-registered (falls back to the host.list lookup for older host-services)
  • cli spawn: daemon stdio → per-org host-service.log (same rotation convention as desktop; openRotatingLogFd moved to @superset/shared/rotating-log and reused by both)

Verification (E2E on the dev stack, isolated Neon branch)

Staged the reporter's exact state (deleted the v2_hosts row while the host-service kept running) and drove the real CLI + desktop UI over CDP:

  • CLI session-mode create: Error: This machine (host 300d922f…) isn't registered with the cloud + Hint: Restart the host service… (was: Error: Not found)
  • CLI --host create: Error: Host 300d922f… is not registered in this organization + Hint: Run: superset hosts list
  • Desktop UI create (bypasses CLI preflight): server 404 body and inline dialog error both show the new named message
  • Real built host-service (ELECTRON_RUN_AS_NODE) with an invalid token: logs failed to register/connect relay (retrying in 30s): … Failed to mint JWT: 401, health.check returns {"cloudRegistered":false,"registrationError":"Failed to mint JWT: 401"}
  • superset status against that instance:
    Superset: Kiets-Spaceship (300d922f…) running (pid 75054, up 18 seconds)
    Warning: not registered with the cloud for Superset (Failed to mint JWT: 401) — hosts list and automations won't see this machine
    Hint: check host-service.log; registration retries automatically, or run: superset stop && superset start
    
  • Daemon spawn with a stub binary: child stdout/stderr land in ~/.superset/host/<org>/host-service.log
  • Recovery: restored registration → the same create commands and the same UI dialog succeed

Tests: formatError unit tests (mutation-checked), resolveAutomationTarget preflight tests. bun run typecheck clean, bun run lint clean. Pre-existing bun test packages/cli failures (execFileSync mock leak) exist on main and are unrelated (5 fail on HEAD, 4 with this branch).


Summary by cubic

Surfaces host cloud-registration failures instead of a silent “Not found” and keeps retrying registration with backoff. Previously host.ensure failures were swallowed, the host looked healthy locally while hosts list returned [], and automations create failed with a blank “Not found”; now the CLI prints the server message, status reports registration state, daemon output is logged, and the retry timer no longer delays shutdown.

  • @superset/cli-framework: extracted formatError; stop blanking NOT_FOUND messages; add login hint for UNAUTHORIZED.
  • @superset/trpc: automation.verifyHostAccess returns NOT_FOUND with Host <id> is not registered in this organization.
  • @superset/cli: resolveAutomationTarget preflights host against host.list in all modes and raises a CLIError with restart guidance; status warns when running but not cloud-registered, falls back to host.list for older host-services, and clears the health-check timeout on errors.
  • @superset/host-service: connectRelay retries host.ensure with capped backoff (30s → 5min) until success and unrefs the retry timer; track registration state; health.check returns cloudRegistered and registrationError.
  • @superset/shared: new @superset/shared/rotating-log used by CLI daemon spawn to write stdout/stderr to per-org host-service.log; removes the duplicated desktop helper.
  • Tests: unit tests for formatError and resolveAutomationTarget preflight; health smoke tests updated for new fields.

Rollout

  • No migrations required. Ensure all apps consume @superset/shared/rotating-log.

Summary by CodeRabbit

  • New Features

    • Host services now retry cloud registration and relay connections automatically.
    • Added rotating daemon logs with size limits and secure file permissions.
    • Status checks now display cloud registration state and related errors.
  • Bug Fixes

    • Automation commands verify host registration before resolving targets and provide clearer recovery guidance.
    • Host access errors now include the requested host identifier.
  • Improvements

    • CLI errors provide more accurate messages, login guidance, and helpful hints.