From cdd857b28891c98da84d2bb27a1bed19a53072b3 Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Sat, 18 Apr 2026 16:10:29 -0300 Subject: [PATCH] vm run --rm: suppress the still-running reminder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deferred --rm delete fires AFTER runSSHSession returns, but runSSHSession prints "vm X is still running (stop with ...)" before returning. Net effect: the user sees the reminder, then the VM gets deleted behind it — misleading. Thread a skipReminder bool into runSSHSession. `vm run` passes the same value as removeOnExit; other callers (`vm ssh`) pass false. Reinforced by a new assertion in the --rm happy-path test that the reminder string never appears in stderr. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/cli/banger.go | 8 ++++---- internal/cli/cli_test.go | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/internal/cli/banger.go b/internal/cli/banger.go index a55e934..fa313f2 100644 --- a/internal/cli/banger.go +++ b/internal/cli/banger.go @@ -1135,7 +1135,7 @@ func newVMSSHCommand() *cobra.Command { if err != nil { return err } - return runSSHSession(cmd.Context(), layout.SocketPath, result.Name, cmd.InOrStdin(), cmd.OutOrStdout(), cmd.ErrOrStderr(), sshArgs) + return runSSHSession(cmd.Context(), layout.SocketPath, result.Name, cmd.InOrStdin(), cmd.OutOrStdout(), cmd.ErrOrStderr(), sshArgs, false) }, } } @@ -2475,9 +2475,9 @@ func validatePositiveSetting(label string, value int) error { return nil } -func runSSHSession(ctx context.Context, socketPath, vmRef string, stdin io.Reader, stdout, stderr io.Writer, sshArgs []string) error { +func runSSHSession(ctx context.Context, socketPath, vmRef string, stdin io.Reader, stdout, stderr io.Writer, sshArgs []string, skipReminder bool) error { sshErr := sshExecFunc(ctx, stdin, stdout, stderr, sshArgs) - if !shouldCheckSSHReminder(sshErr) || ctx.Err() != nil { + if skipReminder || !shouldCheckSSHReminder(sshErr) || ctx.Err() != nil { return sshErr } pingCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second) @@ -2890,7 +2890,7 @@ func runVMRun(ctx context.Context, socketPath string, cfg model.DaemonConfig, st return nil } progress.render("attaching to guest") - return runSSHSession(ctx, socketPath, vmRef, stdin, stdout, stderr, sshArgs) + return runSSHSession(ctx, socketPath, vmRef, stdin, stdout, stderr, sshArgs, removeOnExit) } func importVMRunRepoToGuest(ctx context.Context, client vmRunGuestClient, spec vmRunRepoSpec, progress *vmRunProgressRenderer) error { diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go index 3711320..469f790 100644 --- a/internal/cli/cli_test.go +++ b/internal/cli/cli_test.go @@ -838,7 +838,7 @@ func TestRunSSHSessionPrintsReminderWhenHealthCheckPasses(t *testing.T) { } var stderr bytes.Buffer - if err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}); err != nil { + if err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}, false); err != nil { t.Fatalf("runSSHSession: %v", err) } if !strings.Contains(stderr.String(), "devbox is still running") { @@ -862,7 +862,7 @@ func TestRunSSHSessionPreservesSSHExitStatusOnHealthWarning(t *testing.T) { } var stderr bytes.Buffer - err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}) + err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}, false) var exitErr *exec.ExitError if !errors.As(err, &exitErr) { t.Fatalf("runSSHSession error = %v, want exit error", err) @@ -890,7 +890,7 @@ func TestRunSSHSessionSkipsReminderOnSSHAuthFailure(t *testing.T) { } var stderr bytes.Buffer - err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}) + err := runSSHSession(context.Background(), "/tmp/bangerd.sock", "devbox", strings.NewReader(""), &bytes.Buffer{}, &stderr, []string{"root@127.0.0.1"}, false) var exitErr *exec.ExitError if !errors.As(err, &exitErr) || exitErr.ExitCode() != 255 { t.Fatalf("runSSHSession error = %v, want exit 255", err) @@ -1670,6 +1670,11 @@ func TestRunVMRunRMDeletesAfterSessionExits(t *testing.T) { if deletedRef != "tmpbox" { t.Fatalf("deletedRef = %q, want tmpbox", deletedRef) } + // The "VM is still running" reminder would be misleading when + // the VM is about to be deleted; it must be suppressed. + if strings.Contains(stderr.String(), "is still running") { + t.Fatalf("stderr = %q, should not print still-running reminder under --rm", stderr.String()) + } } func TestRunVMRunRMSkipsDeleteOnSSHWaitTimeout(t *testing.T) {