From 16d3cd17954c35ef494e38ea1a88dd74de8a60ca Mon Sep 17 00:00:00 2001 From: Asad Iqbal Date: Tue, 14 Jul 2026 17:08:07 +0500 Subject: [PATCH] fix(cli): home screen renders a nameless env line when no name is cached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The offline-vs-no-env classifier intentionally keeps a provisioned machine with no cached display name on a NAMED offline line (namespace known, name not). But renderHome formatted every env line with %q, so that case printed `Secure environment "" · can't reach it from here` — an empty-quoted name. Build the env label once: `Secure environment %q` when a name exists, else a bare `Secure environment`. Every state (Online/Running/Starting/Offline) now degrades to a clean nameless line. Output is byte-identical when a name is present (the locked-demo test still passes). Adds a regression test across all named states. Fixes the Cursor Bugbot "Empty env name renders badly" finding on #266. Co-Authored-By: Claude Opus 4.8 --- internal/cli/home.go | 26 +++++++++++++++++--------- internal/cli/home_test.go | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/internal/cli/home.go b/internal/cli/home.go index 515cfa0a..71c88da2 100644 --- a/internal/cli/home.go +++ b/internal/cli/home.go @@ -694,9 +694,17 @@ func renderHome(p *ui.Printer, m homeModel) { // Secure-environment axis (the machine) — a separate line, never fused with // sign-in. + // + // Env label. A provisioned machine can reach an offline (or degraded) state + // with no cached display name — namespace known, name not — so render a clean + // nameless line rather than an empty-quoted `Secure environment ""`. + envLabel := "Secure environment" + if m.envName != "" { + envLabel = fmt.Sprintf("Secure environment %q", m.envName) + } switch m.state { case homeOnline: - p.CheckLine("Secure environment %q · Online%s", m.envName, computeParen(m)) + p.CheckLine("%s · Online%s", envLabel, computeParen(m)) case homeRunning: // Two honest flavors of running, split by what we actually KNOW. // Backend positively reported not-online (offline/pending): "hasn't @@ -705,21 +713,21 @@ func renderHome(p *ui.Printer, m homeModel) { // don't claim tracebloc's view — it may be heartbeating fine while only // our probe failed — say we couldn't confirm. if m.confirmedNotOnline { - p.WarnLine("Secure environment %q · running, but tracebloc hasn't heard from it — run %s %s", - m.envName, m.inv, doctorPath) + p.WarnLine("%s · running, but tracebloc hasn't heard from it — run %s %s", + envLabel, m.inv, doctorPath) } else { - p.WarnLine("Secure environment %q · running — couldn't confirm it's connected to tracebloc — run %s %s", - m.envName, m.inv, doctorPath) + p.WarnLine("%s · running — couldn't confirm it's connected to tracebloc — run %s %s", + envLabel, m.inv, doctorPath) } case homeStarting: - p.WarnLine("Secure environment %q · starting up, not ready yet — run %s %s", - m.envName, m.inv, doctorPath) + p.WarnLine("%s · starting up, not ready yet — run %s %s", + envLabel, m.inv, doctorPath) case homeOffline: // One honest line for both causes: a stopped/unreachable cluster AND a // reachable cluster that doesn't host this release from the current // kube-context. "can't reach it from here" is true either way. - p.CrossLine("Secure environment %q · can't reach it from here — run %s %s", - m.envName, m.inv, doctorPath) + p.CrossLine("%s · can't reach it from here — run %s %s", + envLabel, m.inv, doctorPath) case homeNoEnv: p.WarnLine("No secure environment on this machine yet — run the installer to set one up.") } diff --git a/internal/cli/home_test.go b/internal/cli/home_test.go index 470e3cc2..9cf2228e 100644 --- a/internal/cli/home_test.go +++ b/internal/cli/home_test.go @@ -672,6 +672,23 @@ func TestSanitizeInvoked(t *testing.T) { // (not hand-typed) at the same width the renderer uses, so the only thing under // test is that the renderer emits this exact sequence. Any drift in spacing, // copy, glyphs, or blank-line count fails here. +// TestRenderHome_EmptyEnvNameNoEmptyQuotes: a provisioned machine can reach an +// offline (or degraded) state with no cached display name — env.name is "". The +// env line must render a clean nameless "Secure environment · …" rather than an +// empty-quoted `Secure environment "" · …`. Fails before the fix (%q on an empty +// name). Covers every named state, since any could carry an empty name defensively. +func TestRenderHome_EmptyEnvNameNoEmptyQuotes(t *testing.T) { + for _, st := range []homeState{homeOnline, homeRunning, homeStarting, homeOffline} { + out := renderToString(homeModel{state: st, email: "a@b.io", envName: "", inv: binTracebloc, fullMenu: true}) + if strings.Contains(out, `environment ""`) { + t.Errorf("state %d rendered an empty-quoted env name:\n%s", st, out) + } + if !strings.Contains(out, "Secure environment ·") { + t.Errorf("state %d should render a nameless 'Secure environment ·' line:\n%s", st, out) + } + } +} + func TestRenderHome_MatchesLockedDemo(t *testing.T) { // The locked example: signed in, Online, examples rendered in `tb` (a tb // launcher is installed beside the CLI), and a resources command registered —