all: upgrade to Go 1.26rc2 and modernize codebase

This commit upgrades the codebase from Go 1.25.5 to Go 1.26rc2 and
adopts new language features.

Toolchain updates:
- go.mod: go 1.25.5 → go 1.26rc2
- flake.nix: buildGo125Module → buildGo126Module, go_1_25 → go_1_26
- flake.nix: build golangci-lint from source with Go 1.26
- Dockerfile.integration: golang:1.25-trixie → golang:1.26rc2-trixie
- Dockerfile.tailscale-HEAD: golang:1.25-alpine → golang:1.26rc2-alpine
- Dockerfile.derper: golang:alpine → golang:1.26rc2-alpine
- .goreleaser.yml: go mod tidy -compat=1.25 → -compat=1.26
- cmd/hi/run.go: fallback Go version 1.25 → 1.26rc2
- .pre-commit-config.yaml: simplify golangci-lint hook entry

Code modernization using Go 1.26 features:
- Replace tsaddr.SortPrefixes with slices.SortFunc + netip.Prefix.Compare
- Replace ptr.To(x) with new(x) syntax
- Replace errors.As with errors.AsType[T]

Lint rule updates:
- Add forbidigo rules to prevent regression to old patterns
This commit is contained in:
Kristoffer Dalby
2026-02-06 21:39:35 +00:00
parent 20dff82f95
commit 0f6d312ada
50 changed files with 508 additions and 521 deletions

View File

@@ -20,7 +20,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"tailscale.com/types/ptr"
)
var veryLargeDestination = []policyv2.AliasWithPorts{
@@ -1284,9 +1283,9 @@ func TestACLAutogroupMember(t *testing.T) {
ACLs: []policyv2.ACL{
{
Action: "accept",
Sources: []policyv2.Alias{ptr.To(policyv2.AutoGroupMember)},
Sources: []policyv2.Alias{new(policyv2.AutoGroupMember)},
Destinations: []policyv2.AliasWithPorts{
aliasWithPorts(ptr.To(policyv2.AutoGroupMember), tailcfg.PortRangeAny),
aliasWithPorts(new(policyv2.AutoGroupMember), tailcfg.PortRangeAny),
},
},
},
@@ -1372,9 +1371,9 @@ func TestACLAutogroupTagged(t *testing.T) {
ACLs: []policyv2.ACL{
{
Action: "accept",
Sources: []policyv2.Alias{ptr.To(policyv2.AutoGroupTagged)},
Sources: []policyv2.Alias{new(policyv2.AutoGroupTagged)},
Destinations: []policyv2.AliasWithPorts{
aliasWithPorts(ptr.To(policyv2.AutoGroupTagged), tailcfg.PortRangeAny),
aliasWithPorts(new(policyv2.AutoGroupTagged), tailcfg.PortRangeAny),
},
},
},
@@ -1657,9 +1656,9 @@ func TestACLAutogroupSelf(t *testing.T) {
ACLs: []policyv2.ACL{
{
Action: "accept",
Sources: []policyv2.Alias{ptr.To(policyv2.AutoGroupMember)},
Sources: []policyv2.Alias{new(policyv2.AutoGroupMember)},
Destinations: []policyv2.AliasWithPorts{
aliasWithPorts(ptr.To(policyv2.AutoGroupSelf), tailcfg.PortRangeAny),
aliasWithPorts(new(policyv2.AutoGroupSelf), tailcfg.PortRangeAny),
},
},
{
@@ -1957,9 +1956,9 @@ func TestACLPolicyPropagationOverTime(t *testing.T) {
ACLs: []policyv2.ACL{
{
Action: "accept",
Sources: []policyv2.Alias{ptr.To(policyv2.AutoGroupMember)},
Sources: []policyv2.Alias{new(policyv2.AutoGroupMember)},
Destinations: []policyv2.AliasWithPorts{
aliasWithPorts(ptr.To(policyv2.AutoGroupSelf), tailcfg.PortRangeAny),
aliasWithPorts(new(policyv2.AutoGroupSelf), tailcfg.PortRangeAny),
},
},
},

View File

@@ -17,7 +17,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"tailscale.com/types/ptr"
)
func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) {
@@ -634,7 +633,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
},
AutoApprovers: policyv2.AutoApproverPolicy{
Routes: map[netip.Prefix]policyv2.AutoApprovers{
netip.MustParsePrefix(advertiseRoute): {ptr.To(policyv2.Username(user + "@test.no"))},
netip.MustParsePrefix(advertiseRoute): {new(policyv2.Username(user + "@test.no"))},
},
},
},

View File

@@ -27,7 +27,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"tailscale.com/types/ptr"
)
const (
@@ -906,32 +905,32 @@ func wildcard() policyv2.Alias {
// usernamep returns a pointer to a Username as an Alias for policy v2 configurations.
// Used in ACL rules to reference specific users in network access policies.
func usernamep(name string) policyv2.Alias {
return ptr.To(policyv2.Username(name))
return new(policyv2.Username(name))
}
// hostp returns a pointer to a Host as an Alias for policy v2 configurations.
// Used in ACL rules to reference specific hosts in network access policies.
func hostp(name string) policyv2.Alias {
return ptr.To(policyv2.Host(name))
return new(policyv2.Host(name))
}
// groupp returns a pointer to a Group as an Alias for policy v2 configurations.
// Used in ACL rules to reference user groups in network access policies.
func groupp(name string) policyv2.Alias {
return ptr.To(policyv2.Group(name))
return new(policyv2.Group(name))
}
// tagp returns a pointer to a Tag as an Alias for policy v2 configurations.
// Used in ACL rules to reference node tags in network access policies.
func tagp(name string) policyv2.Alias {
return ptr.To(policyv2.Tag(name))
return new(policyv2.Tag(name))
}
// 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 ptr.To(policyv2.Prefix(prefix))
return new(policyv2.Prefix(prefix))
}
// aliasWithPorts creates an AliasWithPorts structure from an alias and port ranges.
@@ -947,7 +946,7 @@ func aliasWithPorts(alias policyv2.Alias, ports ...tailcfg.PortRange) policyv2.A
// usernameOwner returns a Username as an Owner for use in TagOwners policies.
// Specifies which users can assign and manage specific tags in ACL configurations.
func usernameOwner(name string) policyv2.Owner {
return ptr.To(policyv2.Username(name))
return new(policyv2.Username(name))
}
// groupOwner returns a Group as an Owner for use in TagOwners policies.
@@ -955,25 +954,25 @@ func usernameOwner(name string) policyv2.Owner {
//
//nolint:unused
func groupOwner(name string) policyv2.Owner {
return ptr.To(policyv2.Group(name))
return new(policyv2.Group(name))
}
// usernameApprover returns a Username as an AutoApprover for subnet route policies.
// Specifies which users can automatically approve subnet route advertisements.
func usernameApprover(name string) policyv2.AutoApprover {
return ptr.To(policyv2.Username(name))
return new(policyv2.Username(name))
}
// groupApprover returns a Group as an AutoApprover for subnet route policies.
// Specifies which groups can automatically approve subnet route advertisements.
func groupApprover(name string) policyv2.AutoApprover {
return ptr.To(policyv2.Group(name))
return new(policyv2.Group(name))
}
// tagApprover returns a Tag as an AutoApprover for subnet route policies.
// Specifies which tagged nodes can automatically approve subnet route advertisements.
func tagApprover(name string) policyv2.AutoApprover {
return ptr.To(policyv2.Tag(name))
return new(policyv2.Tag(name))
}
// oidcMockUser creates a MockUser for OIDC authentication testing.

View File

@@ -13,7 +13,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"tailscale.com/types/ptr"
)
func isSSHNoAccessStdError(stderr string) bool {
@@ -85,8 +84,8 @@ func TestSSHOneUserToAll(t *testing.T) {
// Use autogroup:member and autogroup:tagged instead of wildcard
// since wildcard (*) is no longer supported for SSH destinations
Destinations: policyv2.SSHDstAliases{
ptr.To(policyv2.AutoGroupMember),
ptr.To(policyv2.AutoGroupTagged),
new(policyv2.AutoGroupMember),
new(policyv2.AutoGroupTagged),
},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},
@@ -160,7 +159,7 @@ func TestSSHMultipleUsersAllToAll(t *testing.T) {
// Username destinations (e.g., "user1@") now require the source
// to be that exact same user only. For group-to-group SSH access,
// use autogroup:self instead.
Destinations: policyv2.SSHDstAliases{ptr.To(policyv2.AutoGroupSelf)},
Destinations: policyv2.SSHDstAliases{new(policyv2.AutoGroupSelf)},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},
},
@@ -285,7 +284,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
{
Action: "accept",
Sources: policyv2.SSHSrcAliases{groupp("group:integration-test")},
Destinations: policyv2.SSHDstAliases{ptr.To(policyv2.AutoGroupSelf)},
Destinations: policyv2.SSHDstAliases{new(policyv2.AutoGroupSelf)},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},
},
@@ -340,13 +339,13 @@ func TestSSHUserOnlyIsolation(t *testing.T) {
{
Action: "accept",
Sources: policyv2.SSHSrcAliases{groupp("group:ssh1")},
Destinations: policyv2.SSHDstAliases{ptr.To(policyv2.AutoGroupSelf)},
Destinations: policyv2.SSHDstAliases{new(policyv2.AutoGroupSelf)},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},
{
Action: "accept",
Sources: policyv2.SSHSrcAliases{groupp("group:ssh2")},
Destinations: policyv2.SSHDstAliases{ptr.To(policyv2.AutoGroupSelf)},
Destinations: policyv2.SSHDstAliases{new(policyv2.AutoGroupSelf)},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},
},
@@ -522,10 +521,10 @@ func TestSSHAutogroupSelf(t *testing.T) {
{
Action: "accept",
Sources: policyv2.SSHSrcAliases{
ptr.To(policyv2.AutoGroupMember),
new(policyv2.AutoGroupMember),
},
Destinations: policyv2.SSHDstAliases{
ptr.To(policyv2.AutoGroupSelf),
new(policyv2.AutoGroupSelf),
},
Users: []policyv2.SSHUser{policyv2.SSHUser("ssh-it-user")},
},

View File

@@ -13,7 +13,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"tailscale.com/tailcfg"
"tailscale.com/types/ptr"
)
const tagTestUser = "taguser"
@@ -30,9 +29,9 @@ const tagTestUser = "taguser"
func tagsTestPolicy() *policyv2.Policy {
return &policyv2.Policy{
TagOwners: policyv2.TagOwners{
"tag:valid-owned": policyv2.Owners{ptr.To(policyv2.Username(tagTestUser + "@"))},
"tag:second": policyv2.Owners{ptr.To(policyv2.Username(tagTestUser + "@"))},
"tag:valid-unowned": policyv2.Owners{ptr.To(policyv2.Username("other-user@"))},
"tag:valid-owned": policyv2.Owners{new(policyv2.Username(tagTestUser + "@"))},
"tag:second": policyv2.Owners{new(policyv2.Username(tagTestUser + "@"))},
"tag:valid-unowned": policyv2.Owners{new(policyv2.Username("other-user@"))},
// Note: tag:nonexistent deliberately NOT defined
},
ACLs: []policyv2.ACL{