From 93860a5c063e20a51ceb1560c5404e4dd07ead18 Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 13 Apr 2026 12:38:29 +0000 Subject: [PATCH] all: apply formatter changes --- cmd/headscale/cli/nodes.go | 3 ++ cmd/headscale/cli/policy.go | 1 + .../db/ephemeral_garbage_collector_test.go | 6 ++-- hscontrol/db/node_test.go | 6 ++-- hscontrol/debug.go | 6 ++-- hscontrol/mapper/batcher_concurrency_test.go | 1 + hscontrol/mapper/batcher_test.go | 26 +++++++-------- hscontrol/policy/policyutil/reduce.go | 1 + hscontrol/state/debug.go | 32 +++++++++---------- hscontrol/state/node_store.go | 14 ++++---- hscontrol/state/state.go | 2 ++ hscontrol/types/config.go | 2 +- hscontrol/types/version.go | 8 ++--- hscontrol/util/string.go | 4 +-- integration/helpers.go | 12 +++---- tools/capver/main.go | 12 +++---- 16 files changed, 72 insertions(+), 64 deletions(-) diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 0ed7330c..ec24b7f9 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -175,8 +175,10 @@ Use --disable to disable key expiry (node will never expire).`, now := time.Now() expiryTime := now + if expiry != "" { var err error + expiryTime, err = time.Parse(time.RFC3339, expiry) if err != nil { return fmt.Errorf("parsing expiry time: %w", err) @@ -397,6 +399,7 @@ func nodesToPtables( } var ipBuilder strings.Builder + for _, addr := range node.GetIpAddresses() { ip, err := netip.ParseAddr(addr) if err == nil { diff --git a/cmd/headscale/cli/policy.go b/cmd/headscale/cli/policy.go index 02e91c93..9fda35b2 100644 --- a/cmd/headscale/cli/policy.go +++ b/cmd/headscale/cli/policy.go @@ -63,6 +63,7 @@ var getPolicy = &cobra.Command{ Aliases: []string{"show", "view", "fetch"}, RunE: func(cmd *cobra.Command, args []string) error { var policyData string + if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass { if !confirmAction(cmd, "DO NOT run this command if an instance of headscale is running, are you sure headscale is not running?") { return errAborted diff --git a/hscontrol/db/ephemeral_garbage_collector_test.go b/hscontrol/db/ephemeral_garbage_collector_test.go index 290a6310..10bb235a 100644 --- a/hscontrol/db/ephemeral_garbage_collector_test.go +++ b/hscontrol/db/ephemeral_garbage_collector_test.go @@ -379,7 +379,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) { stopScheduling := make(chan struct{}) // Track how many nodes have been scheduled - var scheduledCount int64 + var scheduledCount atomic.Int64 // Launch goroutines that continuously schedule nodes for schedulerIndex := range numSchedulers { @@ -396,7 +396,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) { default: nodeID := types.NodeID(baseNodeID + j + 1) //nolint:gosec // safe conversion in test gc.Schedule(nodeID, 1*time.Hour) // Long expiry to ensure it doesn't trigger during test - atomic.AddInt64(&scheduledCount, 1) + scheduledCount.Add(1) // Yield to other goroutines to introduce variability runtime.Gosched() @@ -410,7 +410,7 @@ func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) { defer wg.Done() // Wait until enough nodes have been scheduled - for atomic.LoadInt64(&scheduledCount) < int64(numSchedulers*closeAfterNodes) { + for scheduledCount.Load() < int64(numSchedulers*closeAfterNodes) { runtime.Gosched() } diff --git a/hscontrol/db/node_test.go b/hscontrol/db/node_test.go index 128baf5b..9dca9635 100644 --- a/hscontrol/db/node_test.go +++ b/hscontrol/db/node_test.go @@ -633,7 +633,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) { want := 1000 - var deletedCount int64 + var deletedCount atomic.Int64 e := NewEphemeralGarbageCollector(func(ni types.NodeID) { mu.Lock() @@ -644,7 +644,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) { got = append(got, ni) - atomic.AddInt64(&deletedCount, 1) + deletedCount.Add(1) }) go e.Start() @@ -655,7 +655,7 @@ func TestEphemeralGarbageCollectorLoads(t *testing.T) { // Wait for all deletions to complete assert.EventuallyWithT(t, func(c *assert.CollectT) { - count := atomic.LoadInt64(&deletedCount) + count := deletedCount.Load() assert.Equal(c, int64(want), count, "all nodes should be deleted") }, 10*time.Second, 50*time.Millisecond, "waiting for all deletions") diff --git a/hscontrol/debug.go b/hscontrol/debug.go index 3257e494..64c8e0d5 100644 --- a/hscontrol/debug.go +++ b/hscontrol/debug.go @@ -395,13 +395,13 @@ func (h *Headscale) debugBatcher() string { } if node.activeConnections > 0 { - sb.WriteString(fmt.Sprintf("Node %d:\t%s (%d connections)\n", node.id, status, node.activeConnections)) + fmt.Fprintf(&sb, "Node %d:\t%s (%d connections)\n", node.id, status, node.activeConnections) } else { - sb.WriteString(fmt.Sprintf("Node %d:\t%s\n", node.id, status)) + fmt.Fprintf(&sb, "Node %d:\t%s\n", node.id, status) } } - sb.WriteString(fmt.Sprintf("\nSummary: %d connected, %d total\n", connectedCount, totalNodes)) + fmt.Fprintf(&sb, "\nSummary: %d connected, %d total\n", connectedCount, totalNodes) return sb.String() } diff --git a/hscontrol/mapper/batcher_concurrency_test.go b/hscontrol/mapper/batcher_concurrency_test.go index de928929..3ae7d0ee 100644 --- a/hscontrol/mapper/batcher_concurrency_test.go +++ b/hscontrol/mapper/batcher_concurrency_test.go @@ -786,6 +786,7 @@ func TestBug3_CleanupOfflineNodes_TOCTOU(t *testing.T) { entry.lastUsed.Store(time.Now().Unix()) mc.addConnection(entry) mc.markConnected() + lb.channels[targetNode] = newCh // Now run cleanup. Node 3 is in the candidates list (old disconnect diff --git a/hscontrol/mapper/batcher_test.go b/hscontrol/mapper/batcher_test.go index e9fa1f5e..2cfc3018 100644 --- a/hscontrol/mapper/batcher_test.go +++ b/hscontrol/mapper/batcher_test.go @@ -141,9 +141,9 @@ type node struct { ch chan *tailcfg.MapResponse // Update tracking (all accessed atomically for thread safety) - updateCount int64 - patchCount int64 - fullCount int64 + updateCount atomic.Int64 + patchCount atomic.Int64 + fullCount atomic.Int64 maxPeersCount atomic.Int64 lastPeerCount atomic.Int64 stop chan struct{} @@ -404,14 +404,14 @@ func (n *node) start() { for { select { case data := <-n.ch: - atomic.AddInt64(&n.updateCount, 1) + n.updateCount.Add(1) // Parse update and track detailed stats info := parseUpdateAndAnalyze(data) { // Track update types if info.IsFull { - atomic.AddInt64(&n.fullCount, 1) + n.fullCount.Add(1) n.lastPeerCount.Store(int64(info.PeerCount)) // Update max peers seen using compare-and-swap for thread safety for { @@ -427,7 +427,7 @@ func (n *node) start() { } if info.IsPatch { - atomic.AddInt64(&n.patchCount, 1) + n.patchCount.Add(1) // For patches, we track how many patch items using compare-and-swap for { current := n.maxPeersCount.Load() @@ -466,9 +466,9 @@ func (n *node) cleanup() NodeStats { } return NodeStats{ - TotalUpdates: atomic.LoadInt64(&n.updateCount), - PatchUpdates: atomic.LoadInt64(&n.patchCount), - FullUpdates: atomic.LoadInt64(&n.fullCount), + TotalUpdates: n.updateCount.Load(), + PatchUpdates: n.patchCount.Load(), + FullUpdates: n.fullCount.Load(), MaxPeersSeen: int(n.maxPeersCount.Load()), LastPeerCount: int(n.lastPeerCount.Load()), } @@ -509,7 +509,7 @@ func TestEnhancedNodeTracking(t *testing.T) { // Wait for tracking goroutine to process the update assert.EventuallyWithT(t, func(c *assert.CollectT) { - assert.GreaterOrEqual(c, atomic.LoadInt64(&testNode.updateCount), int64(1), "should have processed the update") + assert.GreaterOrEqual(c, testNode.updateCount.Load(), int64(1), "should have processed the update") }, time.Second, 10*time.Millisecond, "waiting for update to be processed") // Check stats @@ -553,7 +553,7 @@ func TestEnhancedTrackingWithBatcher(t *testing.T) { // Wait for updates to be processed (at least 1 update received) assert.EventuallyWithT(t, func(c *assert.CollectT) { - assert.GreaterOrEqual(c, atomic.LoadInt64(&testNode.updateCount), int64(1), "should have received updates") + assert.GreaterOrEqual(c, testNode.updateCount.Load(), int64(1), "should have received updates") }, time.Second, 10*time.Millisecond, "waiting for updates to be processed") // Check stats @@ -2141,8 +2141,8 @@ func TestNodeDeletedWhileChangesPending(t *testing.T) { assert.EventuallyWithT(t, func(c *assert.CollectT) { // Node 1 and 2 should receive updates - stats1 := NodeStats{TotalUpdates: atomic.LoadInt64(&node1.updateCount)} - stats2 := NodeStats{TotalUpdates: atomic.LoadInt64(&node2.updateCount)} + stats1 := NodeStats{TotalUpdates: node1.updateCount.Load()} + stats2 := NodeStats{TotalUpdates: node2.updateCount.Load()} assert.Positive(c, stats1.TotalUpdates, "node1 should have received updates") assert.Positive(c, stats2.TotalUpdates, "node2 should have received updates") }, 5*time.Second, 100*time.Millisecond, "waiting for remaining nodes to receive updates") diff --git a/hscontrol/policy/policyutil/reduce.go b/hscontrol/policy/policyutil/reduce.go index c8b6a437..c62691e0 100644 --- a/hscontrol/policy/policyutil/reduce.go +++ b/hscontrol/policy/policyutil/reduce.go @@ -60,6 +60,7 @@ func ReduceFilterRules(node types.NodeView, rules []tailcfg.FilterRule) []tailcf if tsaddr.IsExitRoute(routableIP) { continue } + if expanded.OverlapsPrefix(routableIP) { dests = append(dests, dest) continue DEST_LOOP diff --git a/hscontrol/state/debug.go b/hscontrol/state/debug.go index d0705d9c..4f817786 100644 --- a/hscontrol/state/debug.go +++ b/hscontrol/state/debug.go @@ -69,7 +69,7 @@ func (s *State) DebugOverview() string { sb.WriteString("=== Headscale State Overview ===\n\n") // Node statistics - sb.WriteString(fmt.Sprintf("Nodes: %d total\n", allNodes.Len())) + fmt.Fprintf(&sb, "Nodes: %d total\n", allNodes.Len()) userNodeCounts := make(map[string]int) onlineCount := 0 @@ -97,26 +97,26 @@ func (s *State) DebugOverview() string { } } - sb.WriteString(fmt.Sprintf(" - Online: %d\n", onlineCount)) - sb.WriteString(fmt.Sprintf(" - Expired: %d\n", expiredCount)) - sb.WriteString(fmt.Sprintf(" - Ephemeral: %d\n", ephemeralCount)) + fmt.Fprintf(&sb, " - Online: %d\n", onlineCount) + fmt.Fprintf(&sb, " - Expired: %d\n", expiredCount) + fmt.Fprintf(&sb, " - Ephemeral: %d\n", ephemeralCount) sb.WriteString("\n") // User statistics - sb.WriteString(fmt.Sprintf("Users: %d total\n", len(users))) + fmt.Fprintf(&sb, "Users: %d total\n", len(users)) for userName, nodeCount := range userNodeCounts { - sb.WriteString(fmt.Sprintf(" - %s: %d nodes\n", userName, nodeCount)) + fmt.Fprintf(&sb, " - %s: %d nodes\n", userName, nodeCount) } sb.WriteString("\n") // Policy information sb.WriteString("Policy:\n") - sb.WriteString(fmt.Sprintf(" - Mode: %s\n", s.cfg.Policy.Mode)) + fmt.Fprintf(&sb, " - Mode: %s\n", s.cfg.Policy.Mode) if s.cfg.Policy.Mode == types.PolicyModeFile { - sb.WriteString(fmt.Sprintf(" - Path: %s\n", s.cfg.Policy.Path)) + fmt.Fprintf(&sb, " - Path: %s\n", s.cfg.Policy.Path) } sb.WriteString("\n") @@ -124,7 +124,7 @@ func (s *State) DebugOverview() string { // DERP information derpMap := s.derpMap.Load() if derpMap != nil { - sb.WriteString(fmt.Sprintf("DERP: %d regions configured\n", len(derpMap.Regions))) + fmt.Fprintf(&sb, "DERP: %d regions configured\n", len(derpMap.Regions)) } else { sb.WriteString("DERP: not configured\n") } @@ -137,7 +137,7 @@ func (s *State) DebugOverview() string { routeCount = 0 } - sb.WriteString(fmt.Sprintf("Primary Routes: %d active\n", routeCount)) + fmt.Fprintf(&sb, "Primary Routes: %d active\n", routeCount) sb.WriteString("\n") // Registration cache @@ -163,18 +163,18 @@ func (s *State) DebugDERPMap() string { sb.WriteString("=== DERP Map Configuration ===\n\n") - sb.WriteString(fmt.Sprintf("Total Regions: %d\n\n", len(derpMap.Regions))) + fmt.Fprintf(&sb, "Total Regions: %d\n\n", len(derpMap.Regions)) for regionID, region := range derpMap.Regions { - sb.WriteString(fmt.Sprintf("Region %d: %s\n", regionID, region.RegionName)) - sb.WriteString(fmt.Sprintf(" - Nodes: %d\n", len(region.Nodes))) + fmt.Fprintf(&sb, "Region %d: %s\n", regionID, region.RegionName) + fmt.Fprintf(&sb, " - Nodes: %d\n", len(region.Nodes)) for _, node := range region.Nodes { - sb.WriteString(fmt.Sprintf(" - %s (%s:%d)\n", - node.Name, node.HostName, node.DERPPort)) + fmt.Fprintf(&sb, " - %s (%s:%d)\n", + node.Name, node.HostName, node.DERPPort) if node.STUNPort != 0 { - sb.WriteString(fmt.Sprintf(" STUN: %d\n", node.STUNPort)) + fmt.Fprintf(&sb, " STUN: %d\n", node.STUNPort) } } diff --git a/hscontrol/state/node_store.go b/hscontrol/state/node_store.go index 460808c1..7956afa1 100644 --- a/hscontrol/state/node_store.go +++ b/hscontrol/state/node_store.go @@ -526,8 +526,8 @@ func (s *NodeStore) DebugString() string { sb.WriteString("=== NodeStore Debug Information ===\n\n") // Basic counts - sb.WriteString(fmt.Sprintf("Total Nodes: %d\n", len(snapshot.nodesByID))) - sb.WriteString(fmt.Sprintf("Users with Nodes: %d\n", len(snapshot.nodesByUser))) + fmt.Fprintf(&sb, "Total Nodes: %d\n", len(snapshot.nodesByID)) + fmt.Fprintf(&sb, "Users with Nodes: %d\n", len(snapshot.nodesByUser)) sb.WriteString("\n") // User distribution (shows internal UserID tracking, not display owner) @@ -541,7 +541,7 @@ func (s *NodeStore) DebugString() string { userName = nodes[0].User().Name() } - sb.WriteString(fmt.Sprintf(" - User %d (%s): %d nodes\n", userID, userName, len(nodes))) + fmt.Fprintf(&sb, " - User %d (%s): %d nodes\n", userID, userName, len(nodes)) } } @@ -557,20 +557,20 @@ func (s *NodeStore) DebugString() string { totalPeers += peerCount if node, exists := snapshot.nodesByID[nodeID]; exists { - sb.WriteString(fmt.Sprintf(" - Node %d (%s): %d peers\n", - nodeID, node.Hostname, peerCount)) + fmt.Fprintf(&sb, " - Node %d (%s): %d peers\n", + nodeID, node.Hostname, peerCount) } } if len(snapshot.peersByNode) > 0 { avgPeers := float64(totalPeers) / float64(len(snapshot.peersByNode)) - sb.WriteString(fmt.Sprintf(" - Average peers per node: %.1f\n", avgPeers)) + fmt.Fprintf(&sb, " - Average peers per node: %.1f\n", avgPeers) } sb.WriteString("\n") // Node key index - sb.WriteString(fmt.Sprintf("NodeKey Index: %d entries\n", len(snapshot.nodesByNodeKey))) + fmt.Fprintf(&sb, "NodeKey Index: %d entries\n", len(snapshot.nodesByNodeKey)) sb.WriteString("\n") return sb.String() diff --git a/hscontrol/state/state.go b/hscontrol/state/state.go index 909bab63..9053735e 100644 --- a/hscontrol/state/state.go +++ b/hscontrol/state/state.go @@ -1790,10 +1790,12 @@ func (s *State) HandleNodeFromAuthPath( // the initial Hostinfo from the cached client-supplied Hostinfo (or // an empty stub if the client did not send one). hostname := regData.Hostname + hostinfo := &tailcfg.Hostinfo{} if regData.Hostinfo != nil { hostinfo = regData.Hostinfo.Clone() } + hostinfo.Hostname = hostname // Lookup existing nodes diff --git a/hscontrol/types/config.go b/hscontrol/types/config.go index 73d5a4dd..849aae85 100644 --- a/hscontrol/types/config.go +++ b/hscontrol/types/config.go @@ -933,7 +933,7 @@ func warnBanner(lines []string) { b.WriteString("### ###\n") for _, line := range lines { - b.WriteString(fmt.Sprintf("### %-54s ###\n", line)) + fmt.Fprintf(&b, "### %-54s ###\n", line) } b.WriteString("### ###\n") diff --git a/hscontrol/types/version.go b/hscontrol/types/version.go index 96dc58a6..62124db1 100644 --- a/hscontrol/types/version.go +++ b/hscontrol/types/version.go @@ -30,10 +30,10 @@ func (v *VersionInfo) String() string { version += "-dirty" } - sb.WriteString(fmt.Sprintf("headscale version %s\n", version)) - sb.WriteString(fmt.Sprintf("commit: %s\n", v.Commit)) - sb.WriteString(fmt.Sprintf("build time: %s\n", v.BuildTime)) - sb.WriteString(fmt.Sprintf("built with: %s %s/%s\n", v.Go.Version, v.Go.OS, v.Go.Arch)) + fmt.Fprintf(&sb, "headscale version %s\n", version) + fmt.Fprintf(&sb, "commit: %s\n", v.Commit) + fmt.Fprintf(&sb, "build time: %s\n", v.BuildTime) + fmt.Fprintf(&sb, "built with: %s %s/%s\n", v.Go.Version, v.Go.OS, v.Go.Arch) return sb.String() } diff --git a/hscontrol/util/string.go b/hscontrol/util/string.go index 4390888d..6fca0257 100644 --- a/hscontrol/util/string.go +++ b/hscontrol/util/string.go @@ -98,12 +98,12 @@ func TailcfgFilterRulesToString(rules []tailcfg.FilterRule) string { var sb strings.Builder for index, rule := range rules { - sb.WriteString(fmt.Sprintf(` + fmt.Fprintf(&sb, ` { SrcIPs: %v DstIPs: %v } -`, rule.SrcIPs, rule.DstPorts)) +`, rule.SrcIPs, rule.DstPorts) if index < len(rules)-1 { sb.WriteString(", ") diff --git a/integration/helpers.go b/integration/helpers.go index aec71a5a..f51f4703 100644 --- a/integration/helpers.go +++ b/integration/helpers.go @@ -341,11 +341,11 @@ func requireAllClientsOnlineWithSingleTimeout(t *testing.T, headscale ControlSer stateStr = stateOnline } - failureReport.WriteString(fmt.Sprintf("node:%d is not fully %s (timestamp: %s):\n", nodeID, stateStr, time.Now().Format(TimestampFormat))) - failureReport.WriteString(fmt.Sprintf(" - batcher: %t (expected: %t)\n", status.Batcher, expectedOnline)) - failureReport.WriteString(fmt.Sprintf(" - conn count: %d\n", status.BatcherConnCount)) - failureReport.WriteString(fmt.Sprintf(" - mapresponses: %t (expected: %t, down with at least one peer)\n", status.MapResponses, expectedOnline)) - failureReport.WriteString(fmt.Sprintf(" - nodestore: %t (expected: %t)\n", status.NodeStore, expectedOnline)) + fmt.Fprintf(&failureReport, "node:%d is not fully %s (timestamp: %s):\n", nodeID, stateStr, time.Now().Format(TimestampFormat)) + fmt.Fprintf(&failureReport, " - batcher: %t (expected: %t)\n", status.Batcher, expectedOnline) + fmt.Fprintf(&failureReport, " - conn count: %d\n", status.BatcherConnCount) + fmt.Fprintf(&failureReport, " - mapresponses: %t (expected: %t, down with at least one peer)\n", status.MapResponses, expectedOnline) + fmt.Fprintf(&failureReport, " - nodestore: %t (expected: %t)\n", status.NodeStore, expectedOnline) } } @@ -359,7 +359,7 @@ func requireAllClientsOnlineWithSingleTimeout(t *testing.T, headscale ControlSer prevReport = failureReport.String() } - failureReport.WriteString(fmt.Sprintf("validation_timestamp: %s\n", time.Now().Format(TimestampFormat))) + fmt.Fprintf(&failureReport, "validation_timestamp: %s\n", time.Now().Format(TimestampFormat)) // Note: timeout_remaining not available in this context assert.Fail(c, failureReport.String()) diff --git a/tools/capver/main.go b/tools/capver/main.go index 80468c4a..21c92d26 100644 --- a/tools/capver/main.go +++ b/tools/capver/main.go @@ -359,7 +359,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport content.WriteString("\t{3, false, []string{") for i, version := range latest3 { - content.WriteString(fmt.Sprintf("\"%s\"", version)) + fmt.Fprintf(&content, "\"%s\"", version) if i < len(latest3)-1 { content.WriteString(", ") @@ -374,7 +374,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport for i, version := range latest2 { // Strip v prefix for this test case verNoV := strings.TrimPrefix(version, "v") - content.WriteString(fmt.Sprintf("\"%s\"", verNoV)) + fmt.Fprintf(&content, "\"%s\"", verNoV) if i < len(latest2)-1 { content.WriteString(", ") @@ -384,11 +384,11 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport content.WriteString("}},\n") // Latest N without v prefix (all supported) - content.WriteString(fmt.Sprintf("\t{%d, true, []string{\n", supportedMajorMinorVersions)) + fmt.Fprintf(&content, "\t{%d, true, []string{\n", supportedMajorMinorVersions) for _, version := range latest10 { verNoV := strings.TrimPrefix(version, "v") - content.WriteString(fmt.Sprintf("\t\t\"%s\",\n", verNoV)) + fmt.Fprintf(&content, "\t\t\"%s\",\n", verNoV) } content.WriteString("\t}},\n") @@ -417,7 +417,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport // Add minimum supported version minVersionString := capVerToTailscaleVer[minSupportedCapVer] - content.WriteString(fmt.Sprintf("\t{%d, \"%s\"},\n", minSupportedCapVer, minVersionString)) + fmt.Fprintf(&content, "\t{%d, \"%s\"},\n", minSupportedCapVer, minVersionString) // Add a few more test cases capsSorted := xmaps.Keys(capVerToTailscaleVer) @@ -431,7 +431,7 @@ func writeTestDataFile(versions map[string]tailcfg.CapabilityVersion, minSupport if capVer != minSupportedCapVer { // Don't duplicate the min version test version := capVerToTailscaleVer[capVer] - content.WriteString(fmt.Sprintf("\t{%d, \"%s\"},\n", capVer, version)) + fmt.Fprintf(&content, "\t{%d, \"%s\"},\n", capVer, version) testCount++ }