From c961d580912d25f48f1b916b9b2bc08f394b994d Mon Sep 17 00:00:00 2001 From: Alex Chan Date: Mon, 20 Oct 2025 11:23:35 +0100 Subject: [PATCH] cmd/tailscale: improve the error message for `lock log` with no lock Previously, running `tailscale lock log` in a tailnet without Tailnet Lock enabled would return a potentially confusing error: $ tailscale lock log 2025/10/20 11:07:09 failed to connect to local Tailscale service; is Tailscale running? It would return this error even if Tailscale was running. This patch fixes the error to be: $ tailscale lock log Tailnet Lock is not enabled Fixes #17586 Signed-off-by: Alex Chan --- cmd/tailscale/cli/network-lock.go | 8 ++++++ tstest/integration/integration_test.go | 40 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/cmd/tailscale/cli/network-lock.go b/cmd/tailscale/cli/network-lock.go index f355f99b9..a15d9ab88 100644 --- a/cmd/tailscale/cli/network-lock.go +++ b/cmd/tailscale/cli/network-lock.go @@ -690,6 +690,14 @@ func nlDescribeUpdate(update ipnstate.NetworkLockUpdate, color bool) (string, er } func runNetworkLockLog(ctx context.Context, args []string) error { + st, err := localClient.NetworkLockStatus(ctx) + if err != nil { + return fixTailscaledConnectError(err) + } + if !st.Enabled { + return errors.New("Tailnet Lock is not enabled") + } + updates, err := localClient.NetworkLockLog(ctx, nlLogArgs.limit) if err != nil { return fixTailscaledConnectError(err) diff --git a/tstest/integration/integration_test.go b/tstest/integration/integration_test.go index 2e85bc8be..234bb8c6e 100644 --- a/tstest/integration/integration_test.go +++ b/tstest/integration/integration_test.go @@ -2190,3 +2190,43 @@ func TestC2NDebugNetmap(t *testing.T) { t.Errorf("expected peer to be online; got %+v", nm.Peers[0].AsStruct()) } } + +func TestNetworkLock(t *testing.T) { + + // If you run `tailscale lock log` on a node where Tailnet Lock isn't + // enabled, you get an error explaining that. + t.Run("log-when-not-enabled", func(t *testing.T) { + tstest.Shard(t) + t.Parallel() + + env := NewTestEnv(t) + n1 := NewTestNode(t, env) + d1 := n1.StartDaemon() + defer d1.MustCleanShutdown(t) + + n1.MustUp() + n1.AwaitRunning() + + cmdArgs := []string{"lock", "log"} + t.Logf("Running command: %s", strings.Join(cmdArgs, " ")) + + var outBuf, errBuf bytes.Buffer + + cmd := n1.Tailscale(cmdArgs...) + cmd.Stdout = &outBuf + cmd.Stderr = &errBuf + + if err := cmd.Run(); !isNonZeroExitCode(err) { + t.Fatalf("command did not fail with non-zero exit code: %q", err) + } + + if outBuf.String() != "" { + t.Fatalf("stdout: want '', got %q", outBuf.String()) + } + + wantErr := "Tailnet Lock is not enabled\n" + if errBuf.String() != wantErr { + t.Fatalf("stderr: want %q, got %q", wantErr, errBuf.String()) + } + }) +}