From 43afeedde22dd6d57f3249af93bcf7970ce76f4f Mon Sep 17 00:00:00 2001 From: Kristoffer Dalby Date: Mon, 16 Feb 2026 19:40:02 +0000 Subject: [PATCH] all: apply golangci-lint 2.9.0 fixes Fix issues found by the upgraded golangci-lint: - wsl_v5: add required whitespace in CLI files - staticcheck SA4006: replace new(var.Field) with &localVar pattern since staticcheck does not recognize Go 1.26 new(value) as a use of the variable - staticcheck SA5011: use t.Fatal instead of t.Error for nil guard checks so execution stops - unused: remove dead ptrTo helper function --- cmd/headscale/cli/api_key.go | 3 ++- cmd/headscale/cli/health.go | 1 + cmd/headscale/cli/nodes.go | 15 +++++++++++++++ cmd/headscale/cli/policy.go | 4 ++++ cmd/headscale/cli/preauthkeys.go | 3 ++- cmd/headscale/cli/users.go | 5 +++++ hscontrol/db/node.go | 3 ++- hscontrol/db/node_test.go | 15 +++++++++++---- hscontrol/db/users_test.go | 4 +++- hscontrol/policy/policy_route_approval_test.go | 6 ++++-- hscontrol/state/state.go | 5 ++--- hscontrol/types/change/change.go | 5 ----- hscontrol/util/util_test.go | 8 ++++---- integration/helpers.go | 4 ++-- integration/scenario.go | 1 + 15 files changed, 58 insertions(+), 24 deletions(-) diff --git a/cmd/headscale/cli/api_key.go b/cmd/headscale/cli/api_key.go index 36cd30e2..b0720e0a 100644 --- a/cmd/headscale/cli/api_key.go +++ b/cmd/headscale/cli/api_key.go @@ -71,6 +71,7 @@ var listAPIKeys = &cobra.Command{ tableData := pterm.TableData{ {"ID", "Prefix", "Expiration", "Created"}, } + for _, key := range response.GetApiKeys() { expiration := "-" @@ -84,8 +85,8 @@ var listAPIKeys = &cobra.Command{ expiration, key.GetCreatedAt().AsTime().Format(HeadscaleDateTimeFormat), }) - } + err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render() if err != nil { ErrorOutput( diff --git a/cmd/headscale/cli/health.go b/cmd/headscale/cli/health.go index 864724cc..a0b7b91b 100644 --- a/cmd/headscale/cli/health.go +++ b/cmd/headscale/cli/health.go @@ -15,6 +15,7 @@ var healthCmd = &cobra.Command{ Long: "Check the health of the Headscale server. This command will return an exit code of 0 if the server is healthy, or 1 if it is not.", Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + ctx, client, conn, cancel := newHeadscaleCLIWithConfig() defer cancel() defer conn.Close() diff --git a/cmd/headscale/cli/nodes.go b/cmd/headscale/cli/nodes.go index 827d72e7..642dc1c6 100644 --- a/cmd/headscale/cli/nodes.go +++ b/cmd/headscale/cli/nodes.go @@ -105,6 +105,7 @@ var registerNodeCmd = &cobra.Command{ Short: "Registers a node to your network", Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + user, err := cmd.Flags().GetString("user") if err != nil { ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output) @@ -152,6 +153,7 @@ var listNodesCmd = &cobra.Command{ Aliases: []string{"ls", "show"}, Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + user, err := cmd.Flags().GetString("user") if err != nil { ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output) @@ -200,6 +202,7 @@ var listNodeRoutesCmd = &cobra.Command{ Aliases: []string{"lsr", "routes"}, Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + identifier, err := cmd.Flags().GetUint64("identifier") if err != nil { ErrorOutput( @@ -283,7 +286,9 @@ var expireNodeCmd = &cobra.Command{ return } + now := time.Now() + expiryTime := now if expiry != "" { expiryTime, err = time.Parse(time.RFC3339, expiry) @@ -350,6 +355,7 @@ var renameNodeCmd = &cobra.Command{ if len(args) > 0 { newName = args[0] } + request := &v1.RenameNodeRequest{ NodeId: identifier, NewName: newName, @@ -409,6 +415,7 @@ var deleteNodeCmd = &cobra.Command{ } confirm := false + force, _ := cmd.Flags().GetBool("force") if !force { confirm = util.YesNo(fmt.Sprintf( @@ -424,6 +431,7 @@ var deleteNodeCmd = &cobra.Command{ return } + if err != nil { ErrorOutput( err, @@ -431,6 +439,7 @@ var deleteNodeCmd = &cobra.Command{ output, ) } + SuccessOutput( map[string]string{"Result": "Node deleted"}, "Node deleted", @@ -659,6 +668,7 @@ var tagCmd = &cobra.Command{ Aliases: []string{"tags", "t"}, Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + ctx, client, conn, cancel := newHeadscaleCLIWithConfig() defer cancel() defer conn.Close() @@ -672,6 +682,7 @@ var tagCmd = &cobra.Command{ output, ) } + tagsToSet, err := cmd.Flags().GetStringSlice("tags") if err != nil { ErrorOutput( @@ -686,6 +697,7 @@ var tagCmd = &cobra.Command{ NodeId: identifier, Tags: tagsToSet, } + resp, err := client.SetTags(ctx, request) if err != nil { ErrorOutput( @@ -710,6 +722,7 @@ var approveRoutesCmd = &cobra.Command{ Short: "Manage the approved routes of a node", Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + ctx, client, conn, cancel := newHeadscaleCLIWithConfig() defer cancel() defer conn.Close() @@ -723,6 +736,7 @@ var approveRoutesCmd = &cobra.Command{ output, ) } + routes, err := cmd.Flags().GetStringSlice("routes") if err != nil { ErrorOutput( @@ -737,6 +751,7 @@ var approveRoutesCmd = &cobra.Command{ NodeId: identifier, Routes: routes, } + resp, err := client.SetApprovedRoutes(ctx, request) if err != nil { ErrorOutput( diff --git a/cmd/headscale/cli/policy.go b/cmd/headscale/cli/policy.go index 98e50b1d..95b39fbd 100644 --- a/cmd/headscale/cli/policy.go +++ b/cmd/headscale/cli/policy.go @@ -56,9 +56,12 @@ var getPolicy = &cobra.Command{ Aliases: []string{"show", "view", "fetch"}, Run: func(cmd *cobra.Command, args []string) { output, _ := cmd.Flags().GetString("output") + var policy string + if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass { confirm := false + force, _ := cmd.Flags().GetBool("force") if !force { confirm = util.YesNo("DO NOT run this command if an instance of headscale is running, are you sure headscale is not running?") @@ -134,6 +137,7 @@ var setPolicy = &cobra.Command{ if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass { confirm := false + force, _ := cmd.Flags().GetBool("force") if !force { confirm = util.YesNo("DO NOT run this command if an instance of headscale is running, are you sure headscale is not running?") diff --git a/cmd/headscale/cli/preauthkeys.go b/cmd/headscale/cli/preauthkeys.go index bb909ce2..84e6a7f1 100644 --- a/cmd/headscale/cli/preauthkeys.go +++ b/cmd/headscale/cli/preauthkeys.go @@ -80,6 +80,7 @@ var listPreAuthKeys = &cobra.Command{ "Owner", }, } + for _, key := range response.GetPreAuthKeys() { expiration := "-" if key.GetExpiration() != nil { @@ -105,8 +106,8 @@ var listPreAuthKeys = &cobra.Command{ key.GetCreatedAt().AsTime().Format("2006-01-02 15:04:05"), owner, }) - } + err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render() if err != nil { ErrorOutput( diff --git a/cmd/headscale/cli/users.go b/cmd/headscale/cli/users.go index c1139725..6cd4417e 100644 --- a/cmd/headscale/cli/users.go +++ b/cmd/headscale/cli/users.go @@ -112,10 +112,12 @@ var createUserCmd = &cobra.Command{ output, ) } + request.PictureUrl = pictureURL } log.Trace().Interface(zf.Request, request).Msg("sending CreateUser request") + response, err := client.CreateUser(ctx, request) if err != nil { ErrorOutput( @@ -167,6 +169,7 @@ var destroyUserCmd = &cobra.Command{ user := users.GetUsers()[0] confirm := false + force, _ := cmd.Flags().GetBool("force") if !force { confirm = util.YesNo(fmt.Sprintf( @@ -186,6 +189,7 @@ var destroyUserCmd = &cobra.Command{ output, ) } + SuccessOutput(response, "User destroyed", output) } else { SuccessOutput(map[string]string{"Result": "User not destroyed"}, "User not destroyed", output) @@ -246,6 +250,7 @@ var listUsersCmd = &cobra.Command{ }, ) } + err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render() if err != nil { ErrorOutput( diff --git a/hscontrol/db/node.go b/hscontrol/db/node.go index 98b73551..51bba035 100644 --- a/hscontrol/db/node.go +++ b/hscontrol/db/node.go @@ -682,6 +682,7 @@ func (hsdb *HSDatabase) CreateNodeForTest(user *types.User, hostname ...string) panic(fmt.Sprintf("failed to create preauth key for test node: %v", err)) } + pakID := pak.ID nodeKey := key.NewNode() machineKey := key.NewMachine() discoKey := key.NewDisco() @@ -693,7 +694,7 @@ func (hsdb *HSDatabase) CreateNodeForTest(user *types.User, hostname ...string) Hostname: nodeName, UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pak.ID), + AuthKeyID: &pakID, } err = hsdb.DB.Save(node).Error diff --git a/hscontrol/db/node_test.go b/hscontrol/db/node_test.go index 5991d494..55289ca4 100644 --- a/hscontrol/db/node_test.go +++ b/hscontrol/db/node_test.go @@ -101,6 +101,8 @@ func TestExpireNode(t *testing.T) { pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil) require.NoError(t, err) + pakID := pak.ID + _, err = db.getNode(types.UserID(user.ID), "testnode") require.Error(t, err) @@ -114,7 +116,7 @@ func TestExpireNode(t *testing.T) { Hostname: "testnode", UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pak.ID), + AuthKeyID: &pakID, Expiry: &time.Time{}, } db.DB.Save(node) @@ -145,6 +147,8 @@ func TestSetTags(t *testing.T) { pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil) require.NoError(t, err) + pakID := pak.ID + _, err = db.getNode(types.UserID(user.ID), "testnode") require.Error(t, err) @@ -158,7 +162,7 @@ func TestSetTags(t *testing.T) { Hostname: "testnode", UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pak.ID), + AuthKeyID: &pakID, } trx := db.DB.Save(node) @@ -652,6 +656,9 @@ func TestListEphemeralNodes(t *testing.T) { pakEph, err := db.CreatePreAuthKey(user.TypedID(), false, true, nil, nil) require.NoError(t, err) + pakID := pak.ID + pakEphID := pakEph.ID + node := types.Node{ ID: 0, MachineKey: key.NewMachine().Public(), @@ -659,7 +666,7 @@ func TestListEphemeralNodes(t *testing.T) { Hostname: "test", UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pak.ID), + AuthKeyID: &pakID, } nodeEph := types.Node{ @@ -669,7 +676,7 @@ func TestListEphemeralNodes(t *testing.T) { Hostname: "ephemeral", UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pakEph.ID), + AuthKeyID: &pakEphID, } err = db.DB.Save(&node).Error diff --git a/hscontrol/db/users_test.go b/hscontrol/db/users_test.go index bbb8e4d4..284ca639 100644 --- a/hscontrol/db/users_test.go +++ b/hscontrol/db/users_test.go @@ -73,12 +73,14 @@ func TestDestroyUserErrors(t *testing.T) { pak, err := db.CreatePreAuthKey(user.TypedID(), false, false, nil, nil) require.NoError(t, err) + pakID := pak.ID + node := types.Node{ ID: 0, Hostname: "testnode", UserID: &user.ID, RegisterMethod: util.RegisterMethodAuthKey, - AuthKeyID: new(pak.ID), + AuthKeyID: &pakID, } trx := db.DB.Save(&node) require.NoError(t, trx.Error) diff --git a/hscontrol/policy/policy_route_approval_test.go b/hscontrol/policy/policy_route_approval_test.go index 816a121d..9e56337f 100644 --- a/hscontrol/policy/policy_route_approval_test.go +++ b/hscontrol/policy/policy_route_approval_test.go @@ -330,6 +330,8 @@ func TestApproveRoutesWithPolicy_NilPolicyManagerCase(t *testing.T) { Name: "test", } + userID := user.ID + currentApproved := []netip.Prefix{ netip.MustParsePrefix("10.0.0.0/24"), } @@ -342,8 +344,8 @@ func TestApproveRoutesWithPolicy_NilPolicyManagerCase(t *testing.T) { MachineKey: key.NewMachine().Public(), NodeKey: key.NewNode().Public(), Hostname: "testnode", - UserID: new(user.ID), - User: new(user), + UserID: &userID, + User: &user, RegisterMethod: util.RegisterMethodAuthKey, Hostinfo: &tailcfg.Hostinfo{ RoutableIPs: announcedRoutes, diff --git a/hscontrol/state/state.go b/hscontrol/state/state.go index 65ebf905..e421d5bd 100644 --- a/hscontrol/state/state.go +++ b/hscontrol/state/state.go @@ -502,10 +502,9 @@ func (s *State) Connect(id types.NodeID) []change.Change { // Disconnect marks a node as disconnected and updates its primary routes in the state. func (s *State) Disconnect(id types.NodeID) ([]change.Change, error) { - now := time.Now() - node, ok := s.nodeStore.UpdateNode(id, func(n *types.Node) { - n.LastSeen = new(now) + now := time.Now() + n.LastSeen = &now // NodeStore is the source of truth for all node state including online status. n.IsOnline = new(false) }) diff --git a/hscontrol/types/change/change.go b/hscontrol/types/change/change.go index cd7e99d7..37a63e80 100644 --- a/hscontrol/types/change/change.go +++ b/hscontrol/types/change/change.go @@ -365,11 +365,6 @@ func KeyExpiry(nodeID types.NodeID, expiry *time.Time) Change { } } -// ptrTo returns a pointer to the given value. -func ptrTo[T any](v T) *T { - return new(v) -} - // High-level change constructors // NodeAdded returns a Change for when a node is added or updated. diff --git a/hscontrol/util/util_test.go b/hscontrol/util/util_test.go index 2dafc921..5cca4990 100644 --- a/hscontrol/util/util_test.go +++ b/hscontrol/util/util_test.go @@ -1207,10 +1207,10 @@ func TestEnsureHostnameWithHostinfo(t *testing.T) { wantHostname: "test", checkHostinfo: func(t *testing.T, hi *tailcfg.Hostinfo) { //nolint:thelper if hi == nil { - t.Error("hostinfo should not be nil") + t.Fatal("hostinfo should not be nil") } - if hi.Hostname != "test" { //nolint:staticcheck // SA5011: nil check is above + if hi.Hostname != "test" { t.Errorf("hostname = %v, want test", hi.Hostname) } @@ -1241,10 +1241,10 @@ func TestEnsureHostnameWithHostinfo(t *testing.T) { wantHostname: "123456789012345678901234567890123456789012345678901234567890123", checkHostinfo: func(t *testing.T, hi *tailcfg.Hostinfo) { //nolint:thelper if hi == nil { - t.Error("hostinfo should not be nil") + t.Fatal("hostinfo should not be nil") } - if len(hi.Hostname) != 63 { //nolint:staticcheck // SA5011: nil check is above + if len(hi.Hostname) != 63 { t.Errorf("hostname length = %v, want 63", len(hi.Hostname)) } }, diff --git a/integration/helpers.go b/integration/helpers.go index 3bc1db55..9969416b 100644 --- a/integration/helpers.go +++ b/integration/helpers.go @@ -929,8 +929,8 @@ func tagp(name string) policyv2.Alias { // prefixp returns a pointer to a Prefix from a CIDR string for policy v2 configurations. // Converts CIDR notation to policy prefix format for network range specifications. func prefixp(cidr string) policyv2.Alias { - prefix := netip.MustParsePrefix(cidr) - return new(policyv2.Prefix(prefix)) + p := policyv2.Prefix(netip.MustParsePrefix(cidr)) + return &p } // aliasWithPorts creates an AliasWithPorts structure from an alias and port ranges. diff --git a/integration/scenario.go b/integration/scenario.go index dd07f50b..cd43b78f 100644 --- a/integration/scenario.go +++ b/integration/scenario.go @@ -1485,6 +1485,7 @@ func (s *Scenario) runMockOIDC(accessTTL time.Duration, users []mockoidc.MockUse httpClient := &http.Client{} ctx := context.Background() req, _ := http.NewRequestWithContext(ctx, http.MethodGet, oidcConfigURL, nil) + resp, err := httpClient.Do(req) if err != nil { log.Printf("headscale mock OIDC tests is not ready: %s\n", err)