Strider report

Strider corpus: tailscale

623 msformat3166 mscheck 31152total 4193errors 13668warnings 13291notes

Showing 1000 of 31152 detailed findings. The summary includes all 31152 findings.

appc/appconnector_test.go1

56:13add-constantstring literal "example.com" appears more than twice; define a constant

appc/appconnector_test.go:56:13

55 addr := netip.MustParseAddr("192.0.0.8")
56 a.domains["example.com"] = append(a.domains["example.com"], addr)
57 a.UpdateDomains([]string{"example.com"})

client/tailscale/tailscale.go1

83:17append-to-sized-sliceelem already has a positive length; use make with length zero and capacity, or reslice to zero before append

client/tailscale/tailscale.go:83:17

82 } else {
83 elem = append(elem, url.PathEscape(fmt.Sprint(pathElement)))
84 }

client/systray/startup-creator.go1

12:2blank-importsblank import should be justified by a comment

client/systray/startup-creator.go:12:2

11 "bytes"
12 _ "embed"
13 "fmt"

client/web/auth.go1

264:6boolean-literal-comparisonomit the boolean literal from the logical expression

client/web/auth.go:264:6

263 for _, v := range p {
264 if v == true {
265 return false

control/controlbase/conn_test.go1

241:2call-to-gcavoid explicit garbage collection

control/controlbase/conn_test.go:241:2

240
241 runtime.GC()
242 var ms0 runtime.MemStats

appc/appconnector.go2

303:24cognitive-complexityfunction has cognitive complexity 22; maximum is 7

appc/appconnector.go:303:24

302
303func (e *AppConnector) updateDomains(domains []string) {
304 e.mu.Lock()
303:24confusing-namingname updateDomains differs from UpdateDomains only by capitalization

appc/appconnector.go:303:24

302
303func (e *AppConnector) updateDomains(domains []string) {
304 e.mu.Lock()

cmd/containerboot/egressservices.go1

271:134confusing-resultsadjacent unnamed results of the same type should be named

cmd/containerboot/egressservices.go:271:134

270// updatesForCfg calculates any rules that need to be added or deleted for an individucal egress service config.
271func updatesForCfg(svcName string, cfg egressservices.Config, status *egressservices.Status, tailnetTargetIPs []netip.Addr) ([]rule, []rule, error) {
272 rulesToAdd := make([]rule, 0)

cmd/derper/cert.go1

75:6constructor-interface-returnNewManualCertManager returns interface certProvider although its concrete result is consistently *manualCertManager; return the concrete type

cmd/derper/cert.go:75:6

74// NewManualCertManager returns a cert provider which read certificate by given hostname on create.
75func NewManualCertManager(certdir, hostname string) (certProvider, error) {
76 keyname := unsafeHostnameCharacters.ReplaceAllString(hostname, "")

cmd/sniproxy/sniproxy_test.go1

91:34context-as-argumentcontext.Context should be the first parameter

cmd/sniproxy/sniproxy_test.go:91:34

90
91func startNode(t *testing.T, ctx context.Context, controlURL, hostname string) (*tsnet.Server, key.NodePublic, netip.Addr) {
92 t.Helper()

derp/derp_test.go1

125:3context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

derp/derp_test.go:125:3

124 ctx, cancel := context.WithCancel(context.Background())
125 defer cancel()
126

client/local/local.go1

1346:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

client/local/local.go:1346:2

1345type IPNBusWatcher struct {
1346 ctx context.Context // from original WatchIPNBus call
1347 httpRes *http.Response

tsweb/varz/varz_test.go1

113:10copy-lock-valuecomposite literal copies expvar.Map by value; it contains sync.RWMutex

tsweb/varz/varz_test.go:113:10

112 &metrics.Set{
113 Map: *(func() *expvar.Map {
114 m := new(expvar.Map)

appc/appconnector.go1

303:24cyclomatic-complexityfunction complexity is 11; maximum is 10

appc/appconnector.go:303:24

302
303func (e *AppConnector) updateDomains(domains []string) {
304 e.mu.Lock()

client/systray/systray.go1

492:5deep-exitprocess-exit calls should be confined to main or init

client/systray/systray.go:492:5

491 // reconnect to IPN bus, so exit the process.
492 log.Fatalf("watchIPNBus: %v", err)
493 }

derp/derphttp/derphttp_test.go1

623:2defer-close-before-error-checkcheck the error from derphttp.NewClient before deferring c.Close

derp/derphttp/derphttp_test.go:623:2

622 c, err := derphttp.NewClient(key.NewNode(), "https://"+hostname+"/", t.Logf, netMon)
623 defer c.Close()
624

client/tailscale/cert.go1

19:9deprecated-api-usagetailscale.com/client/local.GetCertificate is deprecated: use [Client.GetCertificate].

client/tailscale/cert.go:19:9

18func GetCertificate(hi *tls.ClientHelloInfo) (*tls.Certificate, error) {
19 return local.GetCertificate(hi)
20}

appc/appconnector.go1

288:2discarded-error-resulterror result returned by e.queue.Wait is discarded

appc/appconnector.go:288:2

287func (e *AppConnector) Wait(ctx context.Context) {
288 e.queue.Wait(ctx)
289}

appc/appctest/appctest.go1

12:1doc-comment-perioddocumentation comment should end with punctuation

appc/appctest/appctest.go:12:1

11
12// RouteCollector is a test helper that collects the list of routes advertised
13type RouteCollector struct {

tailcfg/tailcfg_test.go1

16:2dot-importsdot imports obscure where identifiers come from

tailcfg/tailcfg_test.go:16:2

15
16 . "tailscale.com/tailcfg"
17 "tailscale.com/tstest/deptest"

cmd/k8s-operator/operator_test.go1

28:2duplicated-importspackage tailscale.com/k8s-operator/apis/v1alpha1 is imported more than once

cmd/k8s-operator/operator_test.go:28:2

27 "tailscale.com/k8s-operator/apis/v1alpha1"
28 tsapi "tailscale.com/k8s-operator/apis/v1alpha1"
29 "tailscale.com/kube/kubetypes"

wgengine/watchdog_test.go1

37:33duration-multiplied-by-durationmultiplying two time.Duration values produces squared time units; multiply a duration by a unitless count

wgengine/watchdog_test.go:37:33

36 e = NewWatchdog(e)
37 e.(*watchdogEngine).maxWait = maxWaitMultiple * 150 * time.Millisecond
38 e.(*watchdogEngine).logf = t.Logf

cmd/containerboot/settings.go1

195:9early-returninvert the condition and return early to reduce nesting

cmd/containerboot/settings.go:195:9

194 acceptDNSFromExtraArgsS = keyval[1]
195 } else if len(keyval) == 1 && keyval[0] == "--accept-dns" {
196 // If the arg is just --accept-dns, we assume it means true.

derp/derpserver/derpserver.go1

677:16empty-conditional-blockempty block should be removed or documented

derp/derpserver/derpserver.go:677:16

676 was := cs.activeClient.Load()
677 if was == nil {
678 // Common case.

cmd/ssh-auth-none-demo/ssh-auth-none-demo.go1

172:2enforce-switch-styledefault clause should be the last switch clause

cmd/ssh-auth-none-demo/ssh-auth-none-demo.go:172:2

171 switch typ {
172 default:
173 return nil, fmt.Errorf("unsupported key type %q", typ)

net/sockopts/sockopts_default.go1

19:93error-last-resulterror should be the last returned value

net/sockopts/sockopts_default.go:19:93

18// If pconn is not a [*net.UDPConn], then SetBufferSize is no-op.
19func SetBufferSize(pconn nettype.PacketConn, direction BufferDirection, size int) (errForce error, errPortable error) {
20 return nil, portableSetBufferSize(pconn, direction, size)

cmd/testwrapper/testwrapper_test.go1

21:2error-namingpackage error variable should be named errFoo or ErrFoo

cmd/testwrapper/testwrapper_test.go:21:2

20 buildPath string
21 buildErr error
22 buildOnce sync.Once

appc/appconnector_test.go1

97:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:97:13

96 if err := a.ObserveDNSResponse(dnsResponse("a.example.com.", "192.0.2.1")); err != nil {
97 t.Errorf("ObserveDNSResponse: %v", err)
98 }

client/tailscale/tailscale.go1

186:6error-type-namingerror implementation type should have an Error suffix

client/tailscale/tailscale.go:186:6

185// ErrResponse is the HTTP error returned by the Tailscale server.
186type ErrResponse struct {
187 Status int

cmd/k8s-operator/operator_test.go1

2012:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

cmd/k8s-operator/operator_test.go:2012:2

2011 // NOTE: creating proxygroup stuff just to be sure that it's all ignored
2012 _, _, fc, _, _ := setupServiceTest(t)
2013

appc/appconnector.go2

74:6exported-declaration-commentexported type should have a comment beginning with its name

appc/appconnector.go:74:6

73// newly discovered routes that need to be served through the AppConnector.
74type RouteAdvertiser interface {
75 // AdvertiseRoute adds one or more route advertisements skipping any that
1:1file-length-limitfile has 541 lines; maximum is 500

appc/appconnector.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

client/tailscale/acl.go1

187:67flag-parameterboolean parameter avoidCollisions controls function flow

client/tailscale/acl.go:187:67

186
187func (c *Client) aclPOSTRequest(ctx context.Context, body []byte, avoidCollisions bool, etag, acceptHeader string) ([]byte, string, error) {
188 path := c.BuildTailnetURL("acl")

appc/appconnector.go1

1:1formatfile is not formatted

appc/appconnector.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt appc/appconnector.go`

appc/appconnector_test.go1

229:6function-lengthfunction has 57 statements and 113 lines; maximum is 50 statements or 75 lines

appc/appconnector_test.go:229:6

228
229func TestObserveDNSResponse(t *testing.T) {
230 ctx := t.Context()

client/web/auth.go1

108:18function-result-limitfunction returns 4 values; maximum is 3

client/web/auth.go:108:18

107// unless getTailscaleBrowserSession reports errNotUsingTailscale.
108func (s *Server) getSession(r *http.Request) (*browserSession, *apitype.WhoIsResponse, *ipnstate.Status, error) {
109 whoIs, whoIsErr := s.lc.WhoIs(r.Context(), r.RemoteAddr)

wgengine/filter/filter_test.go1

186:11identical-branchesif and else branches are identical

wgengine/filter/filter_test.go:186:11

185 got = filt.CheckTCP(test.p.Src.Addr(), test.p.Dst.Addr(), test.p.Dst.Port())
186 } else {
187 got = filt.CheckTCP(test.p.Src.Addr(), test.p.Dst.Addr(), test.p.Dst.Port())

derp/derpserver/derpserver.go1

1469:28identical-if-chain-branchesif-else-if chain repeats a branch body

derp/derpserver/derpserver.go:1469:28

1468 cs.activeClient.Store(c)
1469 } else if dup.last == nil {
1470 // If we didn't have a primary, let the current

client/web/auth.go1

54:2identical-switch-branchesswitch repeats a case body

client/web/auth.go:54:2

53 return false
54 case !s.Authenticated:
55 return false // awaiting auth

ipn/store/awsstore/store_aws.go1

21:2import-alias-namingimport alias should contain lower-case letters and digits

ipn/store/awsstore/store_aws.go:21:2

20 "github.com/aws/aws-sdk-go-v2/service/ssm"
21 ssmTypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
22 "tailscale.com/ipn"

client/local/local.go1

335:53import-shadowingidentifier key shadows an imported package

client/local/local.go:335:53

334// If not found, the error is ErrPeerNotFound.
335func (lc *Client) WhoIsNodeKey(ctx context.Context, key key.NodePublic) (*apitype.WhoIsResponse, error) {
336 body, err := lc.get200(ctx, "/localapi/v0/whois?addr="+url.QueryEscape(key.String()))

cmd/k8s-operator/nodeport-services-ports_test.go1

273:34impossible-integer-comparisoncomparison is always false for type uint16

cmd/k8s-operator/nodeport-services-ports_test.go:273:34

272 port := getRandomPort()
273 if port < tailscaledPortMin || port > tailscaledPortMax {
274 t.Errorf("generated port %d which is out of range [%d, %d]", port, tailscaledPortMin, tailscaledPortMax)

ssh/tailssh/incubator.go1

92:5impossible-platform-comparisonruntime.GOOS can never equal "windows" under this file's build constraints

ssh/tailssh/incubator.go:92:5

91 // immediately return.
92 if runtime.GOOS == windows {
93 windir := os.Getenv("windir")

control/controlbase/noiseexplorer_test.go1

420:2increment-decrementuse ++ or -- instead of assigning an addition or subtraction of one

control/controlbase/noiseexplorer_test.go:420:2

419 }
420 session.mc = session.mc + 1
421 return session, messageBuffer

cmd/k8s-operator/proxygroup.go1

534:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

cmd/k8s-operator/proxygroup.go:534:4

533 if _, ok := svcToNodePorts[pgNodePortServiceName(pg.Name, i)]; !ok {
534 svcToNodePorts[pgNodePortServiceName(pg.Name, i)] = 0
535 } else {

cmd/derper/derper.go1

393:48inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

cmd/derper/derper.go:393:48

392 port80srv := &http.Server{
393 Addr: net.JoinHostPort(listenHost, fmt.Sprintf("%d", *httpPort)),
394 Handler: port80mux,

client/local/debugportmapper.go1

69:53insecure-url-schemeURL uses insecure http scheme

client/local/debugportmapper.go:69:53

68
69 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-portmap?"+vals.Encode(), nil)
70 if err != nil {

cmd/k8s-operator/sts.go1

1133:23interface-method-limitinterface has 32 methods, exceeding the configured design limit of 10

cmd/k8s-operator/sts.go:1133:23

1132// client.Object.
1133type ptrObject[T any] interface {
1134 client.Object

feature/taildrop/resume.go1

43:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

feature/taildrop/resume.go:43:7

42}
43func (cs *checksum) UnmarshalText(b []byte) error {
44 if len(b) != 2*len(cs.cs) {

client/systray/systray.go1

654:7max-control-nestingcontrol-flow nesting exceeds 5 levels

client/systray/systray.go:654:7

653 for _, city := range country.cities {
654 for _, ps := range city.peers {
655 if status.ExitNodeStatus.ID == ps.ID {

net/portmapper/legacy_upnp.go1

36:40max-parametersfunction has 9 parameters; maximum is 8

net/portmapper/legacy_upnp.go:36:40

35// AddPortMapping implements upnpClient
36func (client *legacyWANPPPConnection1) AddPortMapping(
37 ctx context.Context,

client/local/local.go1

1345:6max-public-structsfile declares more than 5 exported structs

client/local/local.go:1345:6

1344// It must be closed when done.
1345type IPNBusWatcher struct {
1346 ctx context.Context // from original WatchIPNBus call

appc/appconnector.go1

460:3modifies-parameterassignment modifies parameter domain

appc/appconnector.go:460:3

459 }
460 domain = next
461 }

feature/taildrop/taildrop.go1

119:3modifies-value-receiverassignment modifies value receiver opts

feature/taildrop/taildrop.go:119:3

118 if opts.Logf == nil {
119 opts.Logf = logger.Discard
120 }

chirp/chirp_test.go2

119:12nested-structsmove nested anonymous struct types to named declarations

chirp/chirp_test.go:119:12

118 t *testing.T
119 done chan struct{}
120 wg sync.WaitGroup
47:5nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

chirp/chirp_test.go:47:5

46 if errors.Is(err, net.ErrClosed) {
47 return nil
48 }

client/tailscale/acl.go1

512:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

client/tailscale/acl.go:512:3

511 if len(b) == 0 {
512 return nil, nil
513 }

cmd/k8s-operator/testutils_test.go1

805:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

cmd/k8s-operator/testutils_test.go:805:3

804 timer := time.NewTimer(time.Second * 5)
805 defer timer.Stop()
806 select {

chirp/chirp.go1

71:4no-else-after-returnremove else and unindent its body after the return

chirp/chirp.go:71:4

70 return nil
71 } else if strings.Contains(out, fmt.Sprintf("%s: disabled", protocol)) {
72 return nil

assert_ts_toolchain_match.go1

14:6no-initreplace init with explicit initialization

assert_ts_toolchain_match.go:14:6

13
14func init() {
15 tsRev, ok := tailscaleToolchainRev()

client/local/local.go1

1103:3no-naked-returnreturn values must be explicit

client/local/local.go:1103:3

1102 if err != nil {
1103 return
1104 }

appc/appconnector.go1

84:2no-package-varpackage variables introduce mutable global state

appc/appconnector.go:84:2

83var (
84 metricStoreRoutesRateBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000}
85 metricStoreRoutesNBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000, 10000}

cmd/tailscaled/install_darwin.go1

58:2overwritten-before-usethis value of plist is overwritten before use

cmd/tailscaled/install_darwin.go:58:2

57
58 plist, err := exec.Command("launchctl", "list", "com.tailscale.tailscaled").Output()
59 _ = plist // parse it? https://github.com/DHowett/go-plist if we need something.

appc/observe.go1

6:9package-commentspackage should have a documentation comment

appc/observe.go:6:9

5
6package appc
7

assert_ts_toolchain_match.go1

6:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

assert_ts_toolchain_match.go:6:9

5
6package tailscaleroot
7

types/prefs/prefs_example/prefs_test.go1

4:9package-namingpackage name should be short, lower-case, and contain no separators

types/prefs/prefs_example/prefs_test.go:4:9

3
4package prefs_example
5

client/web/web.go1

1094:33range-value-addresstaking the address of range value ps can be misleading

client/web/web.go:1094:33

1093 }
1094 exitNodes = append(exitNodes, &exitNode{
1095 ID: ps.ID,

cmd/containerboot/settings.go1

290:7receiver-namingreceiver name cfg is inconsistent with s

cmd/containerboot/settings.go:290:7

289// Kubernetes.
290func (cfg *settings) setupKube(ctx context.Context, kc *kubeClient) error {
291 if cfg.KubeSecret == "" {

client/web/auth.go1

332:4redefines-builtin-ididentifier cap shadows a predeclared identifier

client/web/auth.go:332:4

331 for _, f := range c.CanEdit {
332 cap := capFeature(strings.ToLower(f))
333 if slices.Contains(validCaps, cap) {

client/systray/systray.go1

557:75redundant-conversionconversion from uint32 to the identical type is redundant

client/systray/systray.go:557:75

556 obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
557 call := obj.Call("org.freedesktop.Notifications.Notify", 0, "Tailscale", uint32(0),
558 menu.notificationIcon.Name(), title, content, []string{}, map[string]dbus.Variant{}, int32(timeout.Milliseconds()))

cmd/tailscale/cli/syspolicy.go1

114:2redundant-final-returnomit the unnecessary return at the end of a resultless function

cmd/tailscale/cli/syspolicy.go:114:2

113 fmt.Println()
114 return
115}

cmd/sync-containers/main.go1

30:2redundant-import-aliasimport alias is identical to the package name

cmd/sync-containers/main.go:30:2

29 "github.com/google/go-containerregistry/pkg/name"
30 v1 "github.com/google/go-containerregistry/pkg/v1"
31 "github.com/google/go-containerregistry/pkg/v1/remote"

ipn/ipnlocal/network-lock.go1

220:8separate-byte-string-map-keyinline this byte-to-string conversion in each map lookup to avoid an allocation

ipn/ipnlocal/network-lock.go:220:8

219 }
220 wp := string(d.InitialSig.WrappingPubkey)
221 r.byWrappingKey[wp] = append(r.byWrappingKey[wp], rd)

util/osdiag/osdiag_windows_test.go1

18:9simplify-rangeomit the blank range value

util/osdiag/osdiag_windows_test.go:18:9

17 buf := make([]byte, maxBinaryValueLen*2)
18 for i, _ := range buf {
19 buf[i] = byte(i % 0xFF)

cmd/tailscaled/tailscaled.go1

84:3single-case-switchswitch with one case can be replaced by an if statement

cmd/tailscaled/tailscaled.go:84:3

83 case "linux":
84 switch distro.Get() {
85 case distro.Synology:

client/web/web.go1

1089:6slice-preallocationpreallocate exitNodes with capacity len(range source) before appending once per iteration

client/web/web.go:1089:6

1088 }
1089 var exitNodes []*exitNode
1090 for _, ps := range st.Peer {

client/local/debugportmapper.go1

69:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/local/debugportmapper.go:69:46

68
69 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-portmap?"+vals.Encode(), nil)
70 if err != nil {

appc/appconnector.go1

247:2task-commentTODO comment should be resolved or linked to an owned work item

appc/appconnector.go:247:2

246
247 // TODO(creachdair): Remove this once it's delivered over the event bus.
248 return e.storeRoutesFunc(&appctype.RouteInfo{

tstime/jitter.go1

13:28time-namingtime.Duration name should not include a unit suffix

tstime/jitter.go:13:28

12// If panics if max < min.
13func RandomDurationBetween(min, max time.Duration) time.Duration {
14 diff := max - min

cmd/natc/ippool/consensusippool_test.go1

184:5time-value-equalitycompare time.Time values with Time.Equal instead of == or !=

cmd/natc/ippool/consensusippool_test.go:184:5

183 }
184 if ww.LastUsed != time1 {
185 t.Fatalf("expected %s, got %s", time1, ww.LastUsed)

appc/appconnector.go1

74:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

appc/appconnector.go:74:1

73// newly discovered routes that need to be served through the AppConnector.
74type RouteAdvertiser interface {
75 // AdvertiseRoute adds one or more route advertisements skipping any that

client/web/auth.go1

138:14unchecked-type-assertionuse the checked two-result form of the type assertion

client/web/auth.go:138:14

137 }
138 session := v.(*browserSession)
139 if session.SrcNode != srcNode || session.SrcUser != srcUser {

clientupdate/distsign/distsign.go1

341:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

clientupdate/distsign/distsign.go:341:2

340
341 res, err := hc.Do(headReq)
342 if err != nil {

atomicfile/atomicfile_windows_test.go1

14:5unexported-namingunexported identifier should not begin with an underscore

atomicfile/atomicfile_windows_test.go:14:5

13
14var _SECURITY_RESOURCE_MANAGER_AUTHORITY = windows.SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 9}}
15

cmd/derper/cert.go1

75:54unexported-returnexported function returns an unexported type

cmd/derper/cert.go:75:54

74// NewManualCertManager returns a cert provider which read certificate by given hostname on create.
75func NewManualCertManager(certdir, hostname string) (certProvider, error) {
76 keyname := unsafeHostnameCharacters.ReplaceAllString(hostname, "")

cmd/omitsize/omitsize.go1

82:3unnecessary-formatformatting call has no formatting directive

cmd/omitsize/omitsize.go:82:3

81
82 fmt.Printf("Starting with everything and removing a feature...\n\n")
83

clientupdate/clientupdate_windows.go1

166:2unreachable-codestatement is unreachable after unconditional control flow

clientupdate/clientupdate_windows.go:166:2

165 os.Exit(0)
166 panic("unreachable")
167}

cmd/k8s-operator/e2e/ingress_test.go1

115:54unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

cmd/k8s-operator/e2e/ingress_test.go:115:54

114 // a -N suffix.
115 req, err := http.NewRequest(httpm.GET, fmt.Sprintf("http://%s-%s:80", svc.Namespace, svc.Name), nil)
116 if err != nil {

net/portmapper/upnp.go1

498:18unused-append-resultresult of append is never used or observed

net/portmapper/upnp.go:498:18

497 if err != nil {
498 errs = append(errs, err)
499 continue

appc/observe_disabled.go2

8:43unused-parameterparameter res is unused

appc/observe_disabled.go:8:43

7
8func (e *AppConnector) ObserveDNSResponse(res []byte) error { return nil }
9
8:7unused-receiverreceiver e is unused

appc/observe_disabled.go:8:7

7
8func (e *AppConnector) ObserveDNSResponse(res []byte) error { return nil }
9

ipn/ipnlocal/cert_disabled.go1

32:16use-anyuse any instead of interface{}

ipn/ipnlocal/cert_disabled.go:32:16

31
32type certStore interface{}
33

client/local/cert.go1

78:20use-errors-newreplace fmt.Errorf with errors.New for a static message

client/local/cert.go:78:20

77 if i == -1 {
78 return nil, nil, fmt.Errorf("unexpected output: no delimiter")
79 }

cmd/tailscale/cli/file.go1

230:2use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tailscale/cli/file.go:230:2

229 defer tc.Stop()
230 print()
231 for {

cmd/k8s-operator/nodeport-service-ports.go1

164:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/k8s-operator/nodeport-service-ports.go:164:2

163
164 sort.Slice(portRanges, func(i, j int) bool {
165 return portRanges[i].Port < portRanges[j].Port

cmd/tailscale/cli/serve_legacy_test.go1

745:30var-declarationomit the explicit zero value from the variable declaration

cmd/tailscale/cli/serve_legacy_test.go:745:30

744 }
745 var got *ipn.ServeConfig = nil
746 if lc.setCount > lastCount {

atomicfile/atomicfile_windows_test.go1

14:5var-namingidentifier should use MixedCaps rather than underscores

atomicfile/atomicfile_windows_test.go:14:5

13
14var _SECURITY_RESOURCE_MANAGER_AUTHORITY = windows.SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 9}}
15

tempfork/gliderlabs/ssh/agent.go1

69:4waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/gliderlabs/ssh/agent.go:69:4

68 var wg sync.WaitGroup
69 wg.Add(2)
70 go func() {

packages/deb/deb.go1

55:18weak-cryptographydeprecated cryptographic primitive crypto/md5.New should not protect new data

packages/deb/deb.go:55:18

54
55 m5, s1, s256 := md5.New(), sha1.New(), sha256.New()
56 summers := io.MultiWriter(m5, s1, s256)

appc/appconnector_test.go1

68:13add-constantstring literal "got %v; want %v" appears more than twice; define a constant

appc/appconnector_test.go:68:13

67 if got, want := slicesx.MapKeys(a.domains), []string{"up.example.com"}; !slices.Equal(got, want) {
68 t.Errorf("got %v; want %v", got, want)
69 }

client/tailscale/tailscale.go1

104:22append-to-sized-sliceallElements already has a positive length; use make with length zero and capacity, or reslice to zero before append

client/tailscale/tailscale.go:104:22

103 allElements[1] = c.tailnet
104 allElements = append(allElements, pathElements...)
105 return c.BuildURL(allElements...)

cmd/tailscale/cli/debug.go1

35:2blank-importsblank import should be justified by a comment

cmd/tailscale/cli/debug.go:35:2

34 "tailscale.com/feature"
35 _ "tailscale.com/feature/condregister/useproxy"
36 "tailscale.com/health"

cmd/k8s-operator/sts.go1

622:31boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/k8s-operator/sts.go:622:31

621 ss := new(appsv1.StatefulSet)
622 if sts.ServeConfig != nil && sts.ForwardClusterTrafficViaL7IngressProxy != true { // If forwarding cluster traffic via is required we need non-userspace + NET_ADMIN + forwarding
623 if err := yaml.Unmarshal(userspaceProxyYaml, &ss); err != nil {

control/controlbase/conn_test.go1

267:3call-to-gcavoid explicit garbage collection

control/controlbase/conn_test.go:267:3

266 for time.Now().Before(deadline) {
267 runtime.GC()
268 ngo = runtime.NumGoroutine()

appc/appconnector.go1

361:24cognitive-complexityfunction has cognitive complexity 14; maximum is 7

appc/appconnector.go:361:24

360// covered by new ranges.
361func (e *AppConnector) updateRoutes(routes []netip.Prefix) {
362 e.mu.Lock()

client/local/local.go1

654:19confusing-namingname status differs from Status only by capitalization

client/local/local.go:654:19

653
654func (lc *Client) status(ctx context.Context, queryString string) (*ipnstate.Status, error) {
655 body, err := lc.get200(ctx, "/localapi/v0/status"+queryString)

cmd/k8s-operator/dnsrecords.go1

396:134confusing-resultsadjacent unnamed results of the same type should be named

cmd/k8s-operator/dnsrecords.go:396:134

395// for the given proxy Service.
396func (dnsRR *dnsRecordsReconciler) getTargetIPs(ctx context.Context, proxySvc *corev1.Service, logger *zap.SugaredLogger) ([]string, []string, error) {
397 if dnsRR.isProxyGroupEgressService(proxySvc) {

ipn/auditlog/auditlog.go1

424:6constructor-interface-returnNewLogStore returns interface LogStore although its concrete result is consistently *logStateStore; return the concrete type

ipn/auditlog/auditlog.go:424:6

423// NewLogStore creates a new LogStateStore with the given [ipn.StateStore].
424func NewLogStore(store ipn.StateStore) LogStore {
425 return &logStateStore{

cmd/tailscaled/debug.go1

123:50context-as-argumentcontext.Context should be the first parameter

cmd/tailscaled/debug.go:123:50

122
123func changeDeltaWatcher(ec *eventbus.Client, ctx context.Context, dump func(st *netmon.State)) func(*eventbus.Client) {
124 changeSub := eventbus.Subscribe[netmon.ChangeDelta](ec)

feature/taildrop/ext.go1

296:3context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

feature/taildrop/ext.go:296:3

295 gotFile, gotFileCancel := context.WithCancel(context.Background())
296 defer gotFileCancel()
297

client/systray/systray.go1

89:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

client/systray/systray.go:89:2

88
89 bgCtx context.Context // ctx for background tasks not involving menu item clicks
90 bgCancel context.CancelFunc

tsweb/varz/varz_test.go1

127:10copy-lock-valuecomposite literal copies expvar.Map by value; it contains sync.RWMutex

tsweb/varz/varz_test.go:127:10

126 &metrics.Set{
127 Map: *(func() *expvar.Map {
128 m := new(expvar.Map)

appc/appconnector_test.go1

229:6cyclomatic-complexityfunction complexity is 19; maximum is 10

appc/appconnector_test.go:229:6

228
229func TestObserveDNSResponse(t *testing.T) {
230 ctx := t.Context()

client/web/assets.go1

87:3deep-exitprocess-exit calls should be confined to main or init

client/web/assets.go:87:3

86 if err != nil {
87 log.Fatalf("error running tailscale web's yarn install: %v, %s", err, out)
88 }

client/tailscale/cert.go1

26:9deprecated-api-usagetailscale.com/client/local.CertPair is deprecated: use [Client.CertPair].

client/tailscale/cert.go:26:9

25func CertPair(ctx context.Context, domain string) (certPEM, keyPEM []byte, err error) {
26 return local.CertPair(ctx, domain)
27}

appc/appconnector_test.go1

116:3discarded-error-resulterror result returned by rc.SetRoutes is discarded

appc/appconnector_test.go:116:3

115 slices.SortFunc(rc.Routes(), prefixCompare)
116 rc.SetRoutes(slices.Compact(rc.Routes()))
117 slices.SortFunc(routes, prefixCompare)

client/local/local.go1

435:1doc-comment-perioddocumentation comment should end with punctuation

client/local/local.go:435:1

434// EventBusGraph returns a graph of active publishers and subscribers in the eventbus
435// as a [eventbus.DebugTopics]
436func (lc *Client) EventBusGraph(ctx context.Context) ([]byte, error) {

util/deephash/tailscale_types_test.go1

25:2dot-importsdot imports obscure where identifiers come from

util/deephash/tailscale_types_test.go:25:2

24
25 . "tailscale.com/util/deephash"
26)

cmd/k8s-operator/proxygroup_test.go1

32:2duplicated-importspackage tailscale.com/k8s-operator is imported more than once

cmd/k8s-operator/proxygroup_test.go:32:2

31 kube "tailscale.com/k8s-operator"
32 tsoperator "tailscale.com/k8s-operator"
33 tsapi "tailscale.com/k8s-operator/apis/v1alpha1"

cmd/derper/derper.go1

120:3early-returninvert the condition and return early to reduce nesting

cmd/derper/derper.go:120:3

119 if *configPath == "" {
120 if os.Getuid() == 0 {
121 *configPath = "/var/lib/derper/derper.key"

ipn/ipnauth/ipnauth_unix_creds.go1

24:46empty-conditional-blockempty block should be removed or documented

ipn/ipnauth/ipnauth_unix_creds.go:24:46

23 ci.pid, _ = ci.creds.PID()
24 } else if err == peercred.ErrNotImplemented {
25 // peercred.Get is not implemented on this OS (such as OpenBSD)

cmd/tailscale/cli/debug.go1

929:2enforce-switch-styledefault clause should be the last switch clause

cmd/tailscale/cli/debug.go:929:2

928 switch len(args) {
929 default:
930 return errors.New("expect either <site-id> <v4-cidr> or <v6-route>")

net/sockopts/sockopts_linux.go1

22:93error-last-resulterror should be the last returned value

net/sockopts/sockopts_linux.go:22:93

21// If pconn is not a [*net.UDPConn], then SetBufferSize is no-op.
22func SetBufferSize(pconn nettype.PacketConn, direction BufferDirection, size int) (errForce error, errPortable error) {
23 opt := syscall.SO_RCVBUFFORCE

envknob/envknob.go1

521:5error-namingpackage error variable should be named errFoo or ErrFoo

envknob/envknob.go:521:5

520
521var applyDiskConfigErr error
522

appc/appconnector_test.go1

107:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:107:13

106 if err := a.ObserveDNSResponse(dnsResponse("b.example.com.", "192.0.0.1")); err != nil {
107 t.Errorf("ObserveDNSResponse: %v", err)
108 }

cmd/k8s-operator/proxygroup.go1

516:6error-type-namingerror implementation type should have an Error suffix

cmd/k8s-operator/proxygroup.go:516:6

515
516type allocatePortsErr struct {
517 msg string

cmd/tailscale/cli/serve_legacy_test.go1

73:3excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

cmd/tailscale/cli/serve_legacy_test.go:73:3

72 add := func(s step) {
73 _, _, s.line, _ = runtime.Caller(1)
74 steps = append(steps, s)

appc/appconnector.go1

128:6exported-declaration-commentexported type should have a comment beginning with its name

appc/appconnector.go:128:6

127// updated to advertise the new route.
128type AppConnector struct {
129 // These fields are immutable after initialization.

appc/appconnector_test.go1

1:1file-length-limitfile has 931 lines; maximum is 500

appc/appconnector_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

client/web/assets.go1

24:20flag-parameterboolean parameter devMode controls function flow

client/web/assets.go:24:20

23
24func assetsHandler(devMode bool) (_ http.Handler, cleanup func()) {
25 if devMode {

appc/appconnector_test.go2

1:1formatfile is not formatted

appc/appconnector_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt appc/appconnector_test.go`
571:6function-lengthfunction has 33 statements and 80 lines; maximum is 50 statements or 75 lines

appc/appconnector_test.go:571:6

570
571func TestUpdateDomainRouteRemoval(t *testing.T) {
572 ctx := t.Context()

cmd/k8s-operator/svc-for-pg_test.go1

115:6function-result-limitfunction returns 5 values; maximum is 3

cmd/k8s-operator/svc-for-pg_test.go:115:6

114
115func setupServiceTest(t *testing.T) (*HAServiceReconciler, *corev1.Secret, client.Client, *fakeTSClient, *tstest.Clock) {
116 // Pre-create the ProxyGroup

client/web/auth.go1

56:2identical-switch-branchesswitch repeats a case body

client/web/auth.go:56:2

55 return false // awaiting auth
56 case s.isExpired(now):
57 return false // expired

ipn/store/awsstore/store_aws_test.go1

15:2import-alias-namingimport alias should contain lower-case letters and digits

ipn/store/awsstore/store_aws_test.go:15:2

14 "github.com/aws/aws-sdk-go-v2/service/ssm"
15 ssmTypes "github.com/aws/aws-sdk-go-v2/service/ssm/types"
16 "tailscale.com/ipn"

client/local/local.go1

598:60import-shadowingidentifier key shadows an imported package

client/local/local.go:598:60

597// The schema (including when keys are re-read) is not a stable interface.
598func (lc *Client) SetDevStoreKeyValue(ctx context.Context, key, value string) error {
599 body, err := lc.send(ctx, "POST", "/localapi/v0/dev-set-state-store?"+(url.Values{

ssh/tailssh/tailssh.go1

1526:5impossible-platform-comparisonruntime.GOOS can never equal "windows" under this file's build constraints

ssh/tailssh/tailssh.go:1526:5

1525 //lint:ignore SA4032 in case this func moves elsewhere, permit the GOOS check
1526 if runtime.GOOS == "windows" {
1527 return strings.EqualFold(a, b)

control/controlbase/noiseexplorer_test.go1

441:2increment-decrementuse ++ or -- instead of assigning an addition or subtraction of one

control/controlbase/noiseexplorer_test.go:441:2

440 }
441 session.mc = session.mc + 1
442 return session, plaintext, valid

cmd/tsidp/tsidp.go1

734:6inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

cmd/tsidp/tsidp.go:734:6

733 if _, seen := isSlice[claim]; !seen {
734 isSlice[claim] = false
735 }

cmd/k8s-operator/egress-services-readiness.go1

122:37inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatInt with base 10

cmd/k8s-operator/egress-services-readiness.go:122:37

121 for i := range replicas {
122 podLabels[appsv1.PodIndexLabel] = fmt.Sprintf("%d", i)
123 pod, err := getSingleObject[corev1.Pod](ctx, esrr.Client, esrr.tsNamespace, podLabels)

client/local/local.go1

263:54insecure-url-schemeURL uses insecure http scheme

client/local/local.go:263:54

262 }
263 req, err := http.NewRequestWithContext(ctx, method, "http://"+apitype.LocalAPIHost+path, body)
264 if err != nil {

tempfork/gliderlabs/ssh/context.go1

65:14interface-method-limitinterface has 14 methods, exceeding the configured design limit of 10

tempfork/gliderlabs/ssh/context.go:65:14

64// embedded in the context to make it easier to limit operations per-connection.
65type Context interface {
66 context.Context

ipn/ipnauth/actor.go1

108:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

ipn/ipnauth/actor.go:108:7

107// It is primarily used for testing.
108func (id *ClientID) UnmarshalJSON(b []byte) error {
109 return json.Unmarshal(b, &id.v)

client/systray/systray.go1

655:8max-control-nestingcontrol-flow nesting exceeds 5 levels

client/systray/systray.go:655:8

654 for _, ps := range city.peers {
655 if status.ExitNodeStatus.ID == ps.ID {
656 mullvadMenu.Check()

net/portmapper/legacy_upnp.go1

175:39max-parametersfunction has 9 parameters; maximum is 8

net/portmapper/legacy_upnp.go:175:39

174// AddPortMapping implements upnpClient
175func (client *legacyWANIPConnection1) AddPortMapping(
176 ctx context.Context,

client/tailscale/acl.go1

70:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:70:6

69// ACLHuJSON contains the HuJSON string of the ACL and metadata.
70type ACLHuJSON struct {
71 ACL string

client/local/debugportmapper.go1

56:3modifies-parameterassignment modifies parameter opts

client/local/debugportmapper.go:56:3

55 if opts == nil {
56 opts = &DebugPortmapOpts{}
57 }

feature/taildrop/taildrop.go1

122:3modifies-value-receiverassignment modifies value receiver opts

feature/taildrop/taildrop.go:122:3

121 if opts.SendFileNotify == nil {
122 opts.SendFileNotify = func() {}
123 }

chirp/chirp_test.go2

133:23nested-structsmove nested anonymous struct types to named declarations

chirp/chirp_test.go:133:23

132 t: t,
133 done: make(chan struct{}),
134 sock: sock,
149:5nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

chirp/chirp_test.go:149:5

148 if errors.Is(err, net.ErrClosed) {
149 return nil
150 }

cmd/k8s-operator/ingress-for-pg.go1

921:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/k8s-operator/ingress-for-pg.go:921:3

920 if tsSvc.Annotations == nil || tsSvc.Annotations[ownerAnnotation] == "" {
921 return nil, nil
922 }

cmd/tailscale/cli/file.go1

156:4no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

cmd/tailscale/cli/file.go:156:4

155 }
156 defer f.Close()
157 fi, err := f.Stat()

chirp/chirp.go1

85:4no-else-after-returnremove else and unindent its body after the return

chirp/chirp.go:85:4

84 return nil
85 } else if strings.Contains(out, fmt.Sprintf("%s: enabled", protocol)) {
86 return nil

client/systray/systray.go1

128:6no-initreplace init with explicit initialization

client/systray/systray.go:128:6

127
128func init() {
129 if runtime.GOOS != "linux" {

client/local/local.go1

1107:3no-naked-returnreturn values must be explicit

client/local/local.go:1107:3

1106 if err != nil {
1107 return
1108 }

appc/appconnector.go1

85:2no-package-varpackage variables introduce mutable global state

appc/appconnector.go:85:2

84 metricStoreRoutesRateBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000}
85 metricStoreRoutesNBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000, 10000}
86 metricStoreRoutesRate []*clientmetric.Metric

control/controlbase/noiseexplorer_test.go1

172:2overwritten-before-usethis value of err is overwritten before use

control/controlbase/noiseexplorer_test.go:172:2

171 var plaintext []byte
172 enc, err := chacha20poly1305.New(k[:])
173 binary.LittleEndian.PutUint32(nonce[4:], n)

appc/observe_disabled.go1

6:9package-commentspackage should have a documentation comment

appc/observe_disabled.go:6:9

5
6package appc
7

gomod_test.go1

4:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

gomod_test.go:4:9

3
4package tailscaleroot
5

types/prefs/prefs_example/prefs_types.go1

11:9package-namingpackage name should be short, lower-case, and contain no separators

types/prefs/prefs_example/prefs_types.go:11:9

10// generating code for test packages.
11package prefs_example
12

client/web/web_test.go1

419:9range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:419:9

418 selfNode = tt.selfNode
419 r := &http.Request{RemoteAddr: tt.remoteAddr, Header: http.Header{}}
420 if tt.cookie != "" {

cmd/containerboot/settings.go1

382:7receiver-namingreceiver name cfg is inconsistent with s

cmd/containerboot/settings.go:382:7

381
382func (cfg *settings) localMetricsEnabled() bool {
383 return cfg.LocalAddrPort != "" && cfg.MetricsEnabled

clientupdate/clientupdate_windows.go1

86:3redefines-builtin-ididentifier close shadows a predeclared identifier

clientupdate/clientupdate_windows.go:86:3

85 // output to debug with in case update fails.
86 close, err := up.switchOutputToFile()
87 if err != nil {

client/tailscale/keys.go1

96:10redundant-conversionconversion from int64 to the identical type is redundant

client/tailscale/keys.go:96:10

95 ExpirySeconds int64 `json:"expirySeconds,omitempty"`
96 }{caps, int64(expirySeconds)}
97 bs, err := json.Marshal(keyRequest)

derp/derpserver/derpserver_default.go1

12:2redundant-final-returnomit the unnecessary return at the end of a resultless function

derp/derpserver/derpserver_default.go:12:2

11 // Nothing to do
12 return
13}

util/goroutines/goroutines.go1

46:12separate-byte-string-map-keyinline this byte-to-string conversion in each map lookup to avoid an allocation

util/goroutines/goroutines.go:46:12

45 }
46 inStr := string(in)
47 u64, err := strconv.ParseUint(string(in[2:]), 16, 64)

derp/derp_test.go1

786:3single-case-switchswitch with one case can be replaced by an if statement

derp/derp_test.go:786:3

785 }
786 switch m := m.(type) {
787 case derp.PongMessage:

client/web/web.go1

1134:6slice-preallocationpreallocate currNonExitRoutes with capacity len(range source) before appending once per iteration

client/web/web.go:1134:6

1133 }
1134 var currNonExitRoutes []string
1135 var currAdvertisingExitNode bool

client/local/local.go1

420:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/local/local.go:420:46

419func (lc *Client) TailDaemonLogs(ctx context.Context) (io.Reader, error) {
420 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/logtap", nil)
421 if err != nil {

appc/appconnector.go1

299:21task-commentTODO comment should be resolved or linked to an owned work item

appc/appconnector.go:299:21

298 defer e.mu.Unlock()
299 e.queue.Shutdown() // TODO(creachadair): Should we wait for it too?
300 e.pubClient.Close()

cmd/natc/ippool/consensusippool_test.go1

201:5time-value-equalitycompare time.Time values with Time.Equal instead of == or !=

cmd/natc/ippool/consensusippool_test.go:201:5

200 }
201 if ww.LastUsed != time2 {
202 t.Fatalf("expected %s, got %s", time2, ww.LastUsed)

appc/appconnector_test.go1

903:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

appc/appconnector_test.go:903:1

902
903type textUpdate struct {
904 Advertise []string

client/web/web_test.go1

821:18unchecked-type-assertionuse the checked two-result form of the type assertion

client/web/web_test.go:821:18

820 if s, ok := s.browserSessions.Load(sessionID); ok {
821 gotSesson = s.(*browserSession)
822 }

cmd/checkmetrics/checkmetrics.go1

107:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

cmd/checkmetrics/checkmetrics.go:107:2

106
107 resp, err := http.DefaultClient.Do(req)
108 if err != nil {

cmd/natc/natc_test.go1

93:53unexported-namingunexported identifier should not begin with an underscore

cmd/natc/natc_test.go:93:53

92
93func (r *resolver) LookupNetIP(ctx context.Context, _net, host string) ([]netip.Addr, error) {
94 if addrs, ok := r.resolves[host]; ok {

cmd/k8s-operator/sts.go1

513:125unexported-returnexported function returns an unexported type

cmd/k8s-operator/sts.go:513:125

512// returned capver is -1. Either of device ID, hostname and IPs can be empty string if not found in the Secret.
513func (a *tailscaleSTSReconciler) DeviceInfo(ctx context.Context, childLabels map[string]string, logger *zap.SugaredLogger) ([]*device, error) {
514 var secrets corev1.SecretList

cmd/omitsize/omitsize.go1

102:2unnecessary-formatformatting call has no formatting directive

cmd/omitsize/omitsize.go:102:2

101
102 fmt.Printf("\nStarting at a minimal binary and adding one feature back...\n\n")
103 fmt.Printf("%9s %9s %9s\n", "tailscaled", "tailscale", "combined (linux/amd64)")

cmd/tailscale/cli/debug.go1

734:2unreachable-codestatement is unreachable after unconditional control flow

cmd/tailscale/cli/debug.go:734:2

733 os.Exit(1)
734 panic("unreachable")
735}

cmd/k8s-operator/egress-services.go1

797:21unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

cmd/k8s-operator/egress-services.go:797:21

796 }
797 return fmt.Sprintf("http://%s.%s.svc.%s:%d/healthz", svc.Name, svc.Namespace, clusterDomain, svc.Spec.Ports[i].Port)
798}

net/portmapper/upnp.go1

522:17unused-append-resultresult of append is never used or observed

net/portmapper/upnp.go:522:17

521 if err != nil {
522 errs = append(errs, err)
523 continue

client/local/local.go1

110:54unused-parameterparameter network is unused

client/local/local.go:110:54

109
110func (lc *Client) defaultDialer(ctx context.Context, network, addr string) (net.Conn, error) {
111 if addr != "local-tailscaled.sock:80" {

client/web/web.go1

1065:7unused-receiverreceiver s is unused

client/web/web.go:1065:7

1064// This does not currently check whether a specific device can connect, just any device.
1065func (s *Server) aclsAllowAccess(rules []tailcfg.FilterRule) bool {
1066 for _, rule := range rules {

tempfork/acme/acme_test.go1

55:39use-anyuse any instead of interface{}

tempfork/acme/acme_test.go:55:39

54// interface.
55func decodeJWSRequest(t *testing.T, v interface{}, r io.Reader) {
56 // Decode request

client/local/cert.go1

83:20use-errors-newreplace fmt.Errorf with errors.New for a static message

client/local/cert.go:83:20

82 if mem.Contains(mem.B(certPEM), mem.S(" PRIVATE KEY-----")) {
83 return nil, nil, fmt.Errorf("unexpected output: key in cert")
84 }

cmd/tailscale/cli/file.go1

234:4use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tailscale/cli/file.go:234:4

233 case <-ctx.Done():
234 print()
235 fmt.Fprintln(os.Stderr)

cmd/k8s-operator/proxygroup.go1

1122:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/k8s-operator/proxygroup.go:1122:2

1121 // Sort for predictable ordering and status.
1122 sort.Slice(metadata, func(i, j int) bool {
1123 return metadata[i].ordinal < metadata[j].ordinal

cmd/tailscale/cli/serve_v2_test.go1

859:32var-declarationomit the explicit zero value from the variable declaration

cmd/tailscale/cli/serve_v2_test.go:859:32

858 }
859 var got *ipn.ServeConfig = nil
860 if lc.setCount > lastCount {

client/tailscale/tailscale.go1

26:5var-namingidentifier should use MixedCaps rather than underscores

client/tailscale/tailscale.go:26:5

25// for now. This package is being replaced by [tailscale.com/client/tailscale/v2].
26var I_Acknowledge_This_API_Is_Unstable = false
27

tempfork/sshtest/ssh/session_test.go1

49:3waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/sshtest/ssh/session_test.go:49:3

48 }
49 wg.Add(1)
50 go func() {

packages/deb/deb.go1

55:29weak-cryptographydeprecated cryptographic primitive crypto/sha1.New should not protect new data

packages/deb/deb.go:55:29

54
55 m5, s1, s256 := md5.New(), sha1.New(), sha256.New()
56 summers := io.MultiWriter(m5, s1, s256)

appc/appconnector_test.go1

125:55add-constantstring literal "192.0.2.1/32" appears more than twice; define a constant

appc/appconnector_test.go:125:55

124 // Ensure that the contained /32 is removed, replaced by the /24.
125 wantRemoved := []netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")}
126 if !slices.EqualFunc(rc.RemovedRoutes(), wantRemoved, prefixEqual) {

net/socks5/socks5.go1

683:15append-to-sized-slicepkt already has a positive length; use make with length zero and capacity, or reslice to zero before append

net/socks5/socks5.go:683:15

682
683 return append(pkt, addrPkt...), nil
684}

cmd/tailscale/cli/maybe_syspolicy.go1

8:8blank-importsblank import should be justified by a comment

cmd/tailscale/cli/maybe_syspolicy.go:8:8

7
8import _ "tailscale.com/feature/syspolicy"
9

cmd/tailscale/cli/serve_v2.go1

729:6boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/serve_v2.go:729:6

728 } else {
729 if sc.AllowFunnel[hp] == true {
730 output.WriteString(msgFunnelAvailable)

control/controlbase/conn_test.go1

277:2call-to-gcavoid explicit garbage collection

control/controlbase/conn_test.go:277:2

276 }
277 runtime.GC()
278 var ms runtime.MemStats

appc/appconnector.go1

439:24cognitive-complexityfunction has cognitive complexity 13; maximum is 7

appc/appconnector.go:439:24

438// e.mu must be held.
439func (e *AppConnector) findRoutedDomainLocked(domain string, cnameChain map[string]string) (string, bool) {
440 var isRouted bool

clientupdate/distsign/distsign.go1

331:18confusing-namingname download differs from Download only by capitalization

clientupdate/distsign/distsign.go:331:18

330// limit bytes. On success, the returned value is a BLAKE2s hash of the file.
331func (c *Client) download(ctx context.Context, url, dst string, limit int64) ([]byte, int64, error) {
332 tr := http.DefaultTransport.(*http.Transport).Clone()

cmd/k8s-operator/dnsrecords.go1

405:123confusing-resultsadjacent unnamed results of the same type should be named

cmd/k8s-operator/dnsrecords.go:405:123

404// It separates IPv4 and IPv6 addresses for dual-stack services.
405func (dnsRR *dnsRecordsReconciler) getClusterIPServiceIPs(proxySvc *corev1.Service, logger *zap.SugaredLogger) ([]string, []string, error) {
406 // Handle services with no ClusterIP

kube/kubeclient/client.go1

97:6constructor-interface-returnNew returns interface Client although its concrete result is consistently *client; return the concrete type

kube/kubeclient/client.go:97:6

96// New returns a new client
97func New(name string) (Client, error) {
98 ns, err := readFile("namespace")

derp/derp_test.go1

549:38context-as-argumentcontext.Context should be the first parameter

derp/derp_test.go:549:38

548
549func newTestServer(t *testing.T, ctx context.Context) *testServer {
550 t.Helper()

kube/certs/certs.go1

71:25context-cancel-in-loopcontext.WithCancel is created in a loop but its cancellation function is not called during the iteration

kube/certs/certs.go:71:25

70 if _, exists := cm.certLoops[domain]; !exists {
71 cancelCtx, cancel := context.WithCancel(ctx)
72 mak.Set(&cm.certLoops, domain, cancel)

control/controlclient/auto.go1

143:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

control/controlclient/auto.go:143:2

142
143 authCtx context.Context // context used for auth requests
144 mapCtx context.Context // context used for netmap and update requests

tsweb/varz/varz_test.go1

172:10copy-lock-valuecomposite literal copies expvar.Map by value; it contains sync.RWMutex

tsweb/varz/varz_test.go:172:10

171 Label: "label",
172 Map: *(func() *expvar.Map {
173 m := new(expvar.Map)

appc/observe.go1

20:24cyclomatic-complexityfunction complexity is 24; maximum is 10

appc/observe.go:20:24

19// advised to advertise the discovered route.
20func (e *AppConnector) ObserveDNSResponse(res []byte) error {
21 var p dnsmessage.Parser

client/web/assets.go1

95:3deep-exitprocess-exit calls should be confined to main or init

client/web/assets.go:95:3

94 if err := cmd.Start(); err != nil {
95 log.Fatalf("Starting JS dev server: %v", err)
96 }

client/tailscale/cert.go1

33:9deprecated-api-usagetailscale.com/client/local.ExpandSNIName is deprecated: use [Client.ExpandSNIName].

client/tailscale/cert.go:33:9

32func ExpandSNIName(ctx context.Context, name string) (fqdn string, ok bool) {
33 return local.ExpandSNIName(ctx, name)
34}

appc/appconnector_test.go1

167:3discarded-error-resulterror result returned by rc.SetRoutes is discarded

appc/appconnector_test.go:167:3

166 mak.Set(&a.domains, "example.com", []netip.Addr{netip.MustParseAddr("192.0.2.1")})
167 rc.SetRoutes([]netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")})
168 routes := []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24")}

client/local/local.go1

816:1doc-comment-perioddocumentation comment should end with punctuation

client/local/local.go:816:1

815// nodes or subnet routers.
816// See https://tailscale.com/kb/1320/performance-best-practices#linux-optimizations-for-subnet-routers-and-exit-nodes
817func (lc *Client) SetUDPGROForwarding(ctx context.Context) error {

k8s-operator/api-proxy/proxy.go1

27:2duplicated-importspackage tailscale.com/k8s-operator/sessionrecording is imported more than once

k8s-operator/api-proxy/proxy.go:27:2

26 "tailscale.com/k8s-operator/sessionrecording"
27 ksr "tailscale.com/k8s-operator/sessionrecording"
28 "tailscale.com/kube/kubetypes"

cmd/gitops-pusher/gitops-pusher.go1

193:3early-returninvert the condition and return early to reduce nesting

cmd/gitops-pusher/gitops-pusher.go:193:3

192 if err != nil {
193 if os.IsNotExist(err) {
194 cache = &Cache{}

ipn/ipnlocal/expiry.go1

203:26empty-conditional-blockempty block should be removed or documented

ipn/ipnlocal/expiry.go:203:26

202
203 if selfExpiry.IsZero() {
204 // No expiry for self node

cmd/tailscale/cli/file.go1

489:2enforce-switch-styledefault clause should be the last switch clause

cmd/tailscale/cli/file.go:489:2

488 switch action {
489 default:
490 // This should not happen.

tempfork/sshtest/ssh/client_auth_test.go1

49:114error-last-resulterror should be the last returned value

tempfork/sshtest/ssh/client_auth_test.go:49:114

48// tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection.
49func tryAuthBothSides(t *testing.T, config *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) (clientError error, serverAuthErrors []error) {
50 c1, c2, err := netPipe()

ipn/ipnext/ipnext.go1

75:5error-namingpackage error variable should be named errFoo or ErrFoo

ipn/ipnext/ipnext.go:75:5

74// that may change throughout the LocalBackend's lifetime.
75var SkipExtension = errors.New("skipping extension")
76

appc/appconnector_test.go1

208:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:208:13

207 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.0.8")); err != nil {
208 t.Errorf("ObserveDNSResponse: %v", err)
209 }

cmd/k8s-operator/proxygroup.go1

910:6error-type-namingerror implementation type should have an Error suffix

cmd/k8s-operator/proxygroup.go:910:6

909
910type FindStaticEndpointErr struct {
911 msg string

drive/driveimpl/dirfs/dirfs_test.go1

183:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

drive/driveimpl/dirfs/dirfs_test.go:183:2

182func TestMkdir(t *testing.T) {
183 fs, _, _, _ := createFileSystem(t)
184

appc/appconnector.go1

221:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:221:24

220// and is storing its discovered routes persistently.
221func (e *AppConnector) ShouldStoreRoutes() bool {
222 return e.storeRoutesFunc != nil

client/local/local.go1

1:1file-length-limitfile has 1400 lines; maximum is 500

client/local/local.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/containerboot/forwarding.go1

69:25flag-parameterboolean parameter v4Forwarding controls function flow

cmd/containerboot/forwarding.go:69:25

68
69func enableIPForwarding(v4Forwarding, v6Forwarding bool, root string) error {
70 var paths []string

appc/observe.go1

1:1formatfile is not formatted

appc/observe.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt appc/observe.go`

appc/appconnector_test.go1

652:6function-lengthfunction has 33 statements and 80 lines; maximum is 50 statements or 75 lines

appc/appconnector_test.go:652:6

651
652func TestUpdateWildcardRouteRemoval(t *testing.T) {
653 ctx := t.Context()

cmd/natc/ippool/consensusippool.go1

196:34function-result-limitfunction returns 4 values; maximum is 3

cmd/natc/ippool/consensusippool.go:196:34

195// would be 24 hours ago.
196func (ps *consensusPerPeerState) unusedIPV4(ipset *netipx.IPSet, reuseDeadline time.Time) (netip.Addr, bool, string, error) {
197 // If we want to have a random IP choice behavior we could make that work with the state machine by doing something like

client/web/web.go1

482:3identical-switch-branchesswitch repeats a case body

client/web/web.go:482:3

481 return true
482 case r.URL.Path == "/api/device-details-click" && r.Method == httpm.POST:
483 // Special case metric endpoint that is allowed without a browser session.

tempfork/sshtest/ssh/session_test.go1

11:2import-alias-namingimport alias should contain lower-case letters and digits

tempfork/sshtest/ssh/session_test.go:11:2

10 "bytes"
11 crypto_rand "crypto/rand"
12 "errors"

client/local/local.go1

890:81import-shadowingidentifier bytes shadows an imported package

client/local/local.go:890:81

889// (often just one, but can be more if we raced multiple resolvers).
890func (lc *Client) QueryDNS(ctx context.Context, name string, queryType string) (bytes []byte, resolvers []*dnstype.Resolver, err error) {
891 if !buildfeatures.HasDNS {

tsweb/debug_test.go1

186:3increment-decrementuse ++ or -- instead of assigning an addition or subtraction of one

tsweb/debug_test.go:186:3

185 dbg.KVFunc("Debug pageviews", func() any {
186 views = views + 1
187 return views

control/controlclient/map.go1

511:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

control/controlclient/map.go:511:4

510 }
511 ms.peers[nodeID] = mut.View()
512 stats.changed++

cmd/k8s-operator/egress-services-readiness_test.go1

157:28inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatInt with base 10

cmd/k8s-operator/egress-services-readiness_test.go:157:28

156 l := pgLabels(pg.Name, nil)
157 l[appsv1.PodIndexLabel] = fmt.Sprintf("%d", ordinal)
158 ip := fmt.Sprintf("10.0.0.%d", ordinal)

client/local/local.go1

420:53insecure-url-schemeURL uses insecure http scheme

client/local/local.go:420:53

419func (lc *Client) TailDaemonLogs(ctx context.Context) (io.Reader, error) {
420 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/logtap", nil)
421 if err != nil {

tempfork/gliderlabs/ssh/session.go1

23:14interface-method-limitinterface has 21 methods, exceeding the configured design limit of 10

tempfork/gliderlabs/ssh/session.go:23:14

22// TODO: Signals
23type Session interface {
24 gossh.Channel

ipn/prefs.go1

330:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

ipn/prefs.go:330:7

329func (marshalAsTrueInJSON) MarshalJSON() ([]byte, error) { return trueJSON, nil }
330func (*marshalAsTrueInJSON) UnmarshalJSON([]byte) error { return nil }
331

client/systray/systray.go1

676:7max-control-nestingcontrol-flow nesting exceeds 5 levels

client/systray/systray.go:676:7

675 for _, ps := range city.peers {
676 if status.ExitNodeStatus.ID == ps.ID {
677 mullvadMenu.Check()

prober/derp.go1

379:6max-parametersfunction has 9 parameters; maximum is 8

prober/derp.go:379:6

378// can be the same server.
379func derpProbeQueuingDelay(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, packetsPerSecond int, packetTimeout time.Duration, packetsDropped *expvar.Float, qdh *histogram, meshKey key.DERPMesh) (err error) {
380 // This probe uses clients with isProber=false to avoid spamming the derper

client/tailscale/acl.go1

166:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:166:6

165// JavaScript client to be rendered in the HTML.
166type ACLTestFailureSummary struct {
167 // User is the source ("src") value of the ACL test that failed.

client/local/local.go1

948:2modifies-parameterassignment modifies parameter ctx

client/local/local.go:948:2

947 }
948 ctx = httptrace.WithClientTrace(ctx, &trace)
949 req, err := http.NewRequestWithContext(ctx, "POST", "http://"+apitype.LocalAPIHost+"/localapi/v0/dial", nil)

health/state.go1

72:2modifies-value-receiverassignment modifies value receiver u

health/state.go:72:2

71func (u UnhealthyState) withETag() UnhealthyState {
72 u.ETag = ""
73 u.ETag = hex.EncodeToString(u.hash())

client/local/local.go1

504:16nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:504:16

503 // generates another log marker.
504 Record <-chan struct{}
505}

client/tailscale/acl.go1

489:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

client/tailscale/acl.go:489:3

488 if err != nil {
489 return nil, err
490 }

cmd/k8s-operator/sts.go1

210:4nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/k8s-operator/sts.go:210:4

209 logger.Infof("ProxyClass %s specified for the proxy, but it is not (yet) in a ready state, waiting..")
210 return nil, nil
211 }

cmd/tailscale/cli/file.go1

181:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

cmd/tailscale/cli/file.go:181:3

180 ctxProgress, cancelProgress := context.WithCancel(ctx)
181 defer cancelProgress()
182 if isatty.IsTerminal(os.Stderr.Fd()) {

client/local/debugportmapper.go1

65:4no-else-after-returnremove else and unindent its body after the return

client/local/debugportmapper.go:65:4

64 return nil, fmt.Errorf("both GatewayAddr and SelfAddr must be provided if one is")
65 } else if opts.GatewayAddr.IsValid() {
66 vals.Set("gateway_and_self", fmt.Sprintf("%s/%s", opts.GatewayAddr, opts.SelfAddr))

client/tailscale/required_version.go1

8:6no-initreplace init with explicit initialization

client/tailscale/required_version.go:8:6

7
8func init() {
9 you_need_Go_1_23_to_compile_Tailscale()

client/local/local.go1

1111:3no-naked-returnreturn values must be explicit

client/local/local.go:1111:3

1110 if err != nil {
1111 return
1112 }

appc/appconnector.go1

86:2no-package-varpackage variables introduce mutable global state

appc/appconnector.go:86:2

85 metricStoreRoutesNBuckets = []int64{1, 2, 3, 4, 5, 10, 100, 1000, 10000}
86 metricStoreRoutesRate []*clientmetric.Metric
87 metricStoreRoutesN []*clientmetric.Metric

control/controlbase/noiseexplorer_test.go1

233:2overwritten-before-usethis value of ad is overwritten before use

control/controlbase/noiseexplorer_test.go:233:2

232func decryptWithAd(cs *cipherstate, ad []byte, ciphertext []byte) (*cipherstate, []byte, bool) {
233 valid, ad, plaintext := decrypt(cs.k, cs.n, ad, ciphertext)
234 cs = setNonce(cs, incrementNonce(cs.n))

assert_ts_toolchain_match.go1

6:9package-commentspackage should have a documentation comment

assert_ts_toolchain_match.go:6:9

5
6package tailscaleroot
7

k8s-operator/conditions.go1

6:9package-directory-mismatchpackage kube does not match directory k8s-operator

k8s-operator/conditions.go:6:9

5
6package kube
7

client/web/web_test.go1

421:17range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:421:17

420 if tt.cookie != "" {
421 r.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tt.cookie})
422 }

cmd/containerboot/settings.go1

386:7receiver-namingreceiver name cfg is inconsistent with s

cmd/containerboot/settings.go:386:7

385
386func (cfg *settings) localHealthEnabled() bool {
387 return cfg.LocalAddrPort != "" && cfg.HealthCheckEnabled

clientupdate/distsign/distsign.go1

146:51redefines-builtin-ididentifier len shadows a predeclared identifier

clientupdate/distsign/distsign.go:146:51

145// to compute the inputs.
146func (s *SigningKey) SignPackageHash(hash []byte, len int64) ([]byte, error) {
147 if len <= 0 {

client/web/web_test.go1

97:41redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:97:41

96
97 remoteUser := &tailcfg.UserProfile{ID: tailcfg.UserID(1)}
98 remoteIPWithAllCapabilities := "100.100.100.101"

ipn/ipnlocal/local.go1

4660:2redundant-final-returnomit the unnecessary return at the end of a resultless function

ipn/ipnlocal/local.go:4660:2

4659 c.Close()
4660 return
4661}

derp/derphttp/derphttp_client.go1

1098:3single-case-switchswitch with one case can be replaced by an if statement

derp/derphttp/derphttp_client.go:1098:3

1097 m, err = client.Recv()
1098 switch m := m.(type) {
1099 case derp.PongMessage:

clientupdate/distsign/distsign_test.go1

507:6slice-preallocationpreallocate pubs with capacity len(range source) before appending once per iteration

clientupdate/distsign/distsign_test.go:507:6

506func (s *testServer) resignSigningKeys() {
507 var pubs [][]byte
508 for _, k := range s.sign {

client/local/local.go1

446:47standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/local/local.go:446:47

445 return func(yield func(eventbus.DebugEvent, error) bool) {
446 req, err := http.NewRequestWithContext(ctx, "GET",
447 "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-bus-events", nil)

appc/appconnector_test.go1

833:1task-commentTODO comment should be resolved or linked to an owned work item

appc/appconnector_test.go:833:1

832//
833// TODO(creachadair, 2025-09-18): Remove this along with the advertiser
834// interface once the LocalBackend is switched to use the event bus and the

net/dns/resolver/tsdns.go1

597:51time-value-equalitycompare time.Time values with Time.Equal instead of == or !=

net/dns/resolver/tsdns.go:597:51

596 }
597 if c, ok := resolvConfCacheValue.LoadOk(); ok && c.mod == cur.mod && c.size == cur.size {
598 return c.ip, nil

chirp/chirp.go1

52:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

chirp/chirp.go:52:1

51// BIRDClient handles communication with the BIRD Internet Routing Daemon.
52type BIRDClient struct {
53 socket string

clientupdate/distsign/distsign.go1

332:29unchecked-type-assertionuse the checked two-result form of the type assertion

clientupdate/distsign/distsign.go:332:29

331func (c *Client) download(ctx context.Context, url, dst string, limit int64) ([]byte, int64, error) {
332 tr := http.DefaultTransport.(*http.Transport).Clone()
333 tr.Proxy = feature.HookProxyFromEnvironment.GetOrNil()

cmd/k8s-operator/e2e/ingress_test.go1

121:3unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

cmd/k8s-operator/e2e/ingress_test.go:121:3

120 defer cancel()
121 resp, err = tailnetClient.HTTPClient().Do(req.WithContext(ctx))
122 return err

ipn/desktop/sessions_windows.go1

586:6unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:586:6

585
586type _WNDCLASSEX struct {
587 CbSize uint32

cmd/k8s-proxy/internal/config/config.go1

45:115unexported-returnexported function returns an unexported type

cmd/k8s-proxy/internal/config/config.go:45:115

44
45func NewConfigLoader(logger *zap.SugaredLogger, client clientcorev1.CoreV1Interface, cfgChan chan<- *conf.Config) *configLoader {
46 return &configLoader{

cmd/tailscale/cli/debug.go1

594:2unnecessary-formatformatting call has no formatting directive

cmd/tailscale/cli/debug.go:594:2

593 fmt.Printf("curl.exe http://%v/localapi/v0/status\n", lc.Addr())
594 fmt.Printf("Ctrl+C to stop")
595 http.Serve(lc, rp)

cmd/tailscale/cli/serve_legacy.go1

834:3unreachable-codestatement is unreachable after unconditional control flow

cmd/tailscale/cli/serve_legacy.go:834:3

833 log.Fatalf("lost connection to tailscaled: %v", err)
834 e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enablement_lost_connection", feature), 1)
835 return err

cmd/tailscale/cli/serve_v2.go1

756:34unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

cmd/tailscale/cli/serve_v2.go:756:34

755
756 output.WriteString(fmt.Sprintf("|-- tcp://%s:%d (%s)\n", host, srvPort, tlsStatus))
757 for _, a := range ips {

client/tailscale/tailnet.go1

17:60unused-parameterparameter tailnetID is unused

client/tailscale/tailnet.go:17:60

16// TailnetDeleteRequest handles sending a DELETE request for a tailnet to control.
17func (c *Client) TailnetDeleteRequest(ctx context.Context, tailnetID string) (err error) {
18 defer func() {

clientupdate/clientupdate.go1

548:7unused-receiverreceiver up is unused

clientupdate/clientupdate.go:548:7

547
548func (up *Updater) archPackageInstalled() bool {
549 err := exec.Command("pacman", "--query", "tailscale").Run()

tempfork/acme/http.go1

175:80use-anyuse any instead of interface{}

tempfork/acme/http.go:175:80

174// It uses postNoRetry to make individual requests.
175func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) {
176 retry := c.retryTimer()

client/local/debugportmapper.go1

64:15use-errors-newreplace fmt.Errorf with errors.New for a static message

client/local/debugportmapper.go:64:15

63 if opts.GatewayAddr.IsValid() != opts.SelfAddr.IsValid() {
64 return nil, fmt.Errorf("both GatewayAddr and SelfAddr must be provided if one is")
65 } else if opts.GatewayAddr.IsValid() {

cmd/tailscale/cli/file.go1

238:4use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tailscale/cli/file.go:238:4

237 case <-tc.C:
238 print()
239 }

cmd/nardump/nardump.go1

87:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/nardump/nardump.go:87:2

86 }
87 sort.Slice(ents, func(i, j int) bool {
88 return ents[i].Name() < ents[j].Name()

cmd/containerboot/egressservices_test.go1

25:2var-namingidentifier should use MixedCaps rather than underscores

cmd/containerboot/egressservices_test.go:25:2

24 tailnetIPv4, tailnetIPv6 := netip.MustParseAddr("100.99.99.99"), netip.MustParseAddr("fd7a:115c:a1e0::701:b62a")
25 tailnetIPv4_1, tailnetIPv6_1 := netip.MustParseAddr("100.88.88.88"), netip.MustParseAddr("fd7a:115c:a1e0::4101:512f")
26 ports := map[egressservices.PortMap]struct{}{{Protocol: "tcp", MatchPort: 4003, TargetPort: 80}: {}}

tempfork/sshtest/ssh/session_test.go1

66:4waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/sshtest/ssh/session_test.go:66:4

65 }
66 wg.Add(1)
67 go func() {

tempfork/sshtest/ssh/cipher.go1

55:9weak-cryptographydeprecated cryptographic primitive crypto/rc4.NewCipher should not protect new data

tempfork/sshtest/ssh/cipher.go:55:9

54func newRC4(key, iv []byte) (cipher.Stream, error) {
55 return rc4.NewCipher(key)
56}

appc/appconnector_test.go1

136:27add-constantstring literal "192.0.0.1/32" appears more than twice; define a constant

appc/appconnector_test.go:136:27

135 eqUpdate(appctype.RouteUpdate{
136 Advertise: prefixes("192.0.0.1/32", "192.0.2.0/24"),
137 Unadvertise: prefixes("192.0.2.1/32"),

net/socks5/socks5.go1

729:15append-to-sized-slicepkt already has a positive length; use make with length zero and capacity, or reslice to zero before append

net/socks5/socks5.go:729:15

728
729 return append(pkt, addrPkt...), nil
730}

cmd/tailscale/cli/up.go1

28:2blank-importsblank import should be justified by a comment

cmd/tailscale/cli/up.go:28:2

27 "tailscale.com/feature/buildfeatures"
28 _ "tailscale.com/feature/condregister/oauthkey"
29 "tailscale.com/health/healthmsg"

cmd/tailscale/cli/serve_v2_test.go1

1150:7boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/serve_v2_test.go:1150:7

1149
1150 if tt.wantErr == true && err == nil {
1151 t.Errorf("Expected an error but got none")

ipn/ipnlocal/c2n_pprof.go1

20:4call-to-gcavoid explicit garbage collection

ipn/ipnlocal/c2n_pprof.go:20:4

19 if gc, _ := strconv.Atoi(r.FormValue("gc")); gc > 0 {
20 runtime.GC()
21 }

appc/appconnector_test.go1

31:6cognitive-complexityfunction has cognitive complexity 9; maximum is 7

appc/appconnector_test.go:31:6

30
31func TestUpdateDomains(t *testing.T) {
32 ctx := t.Context()

cmd/pgproxy/pgproxy.go1

197:17confusing-namingname serve differs from Serve only by capitalization

cmd/pgproxy/pgproxy.go:197:17

196// enforcing strict TLS to the upstream.
197func (p *proxy) serve(sessionID int64, c net.Conn) error {
198 defer c.Close()

cmd/k8s-operator/dnsrecords.go1

441:131confusing-resultsadjacent unnamed results of the same type should be named

cmd/k8s-operator/dnsrecords.go:441:131

440// getPodIPs returns Pod IPv4 and IPv6 addresses from EndpointSlices for non-ProxyGroup Services.
441func (dnsRR *dnsRecordsReconciler) getPodIPs(ctx context.Context, proxySvc *corev1.Service, logger *zap.SugaredLogger) ([]string, []string, error) {
442 // Get the Pod IP addresses for the proxy from the EndpointSlices for

kube/localclient/local-client.go1

35:6constructor-interface-returnNew returns interface LocalClient although its concrete result is consistently *localClient; return the concrete type

kube/localclient/local-client.go:35:6

34// New returns a LocalClient that wraps the provided local.Client.
35func New(lc *local.Client) LocalClient {
36 return &localClient{lc: lc}

feature/taildrop/localapi.go1

273:6context-as-argumentcontext.Context should be the first parameter

feature/taildrop/localapi.go:273:6

272 h *localapi.Handler,
273 ctx context.Context,
274 progressUpdates chan (ipn.OutgoingFile),

net/dnsfallback/dnsfallback.go1

112:3context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

net/dnsfallback/dnsfallback.go:112:3

111 ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
112 defer cancel()
113 dm, err := bootstrapDNSMap(ctx, cand.dnsName, cand.ip, host, logf, ht, netMon)

control/controlclient/auto.go1

144:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

control/controlclient/auto.go:144:2

143 authCtx context.Context // context used for auth requests
144 mapCtx context.Context // context used for netmap and update requests
145 authCancel func() // cancel authCtx

client/systray/systray.go1

203:19cyclomatic-complexityfunction complexity is 20; maximum is 10

client/systray/systray.go:203:19

202// So for now we rebuild the whole thing, and can optimize this later if needed.
203func (menu *Menu) rebuild() {
204 menu.mu.Lock()

client/web/assets.go1

128:3deep-exitprocess-exit calls should be confined to main or init

client/web/assets.go:128:3

127 if err != nil {
128 log.Fatalf("failed to find git top level (not in corp git?): %v", err)
129 }

client/tailscale/localclient_aliases.go1

64:9deprecated-api-usagetailscale.com/client/local.WhoIs is deprecated: use [Client.WhoIs].

client/tailscale/localclient_aliases.go:64:9

63func WhoIs(ctx context.Context, remoteAddr string) (*apitype.WhoIsResponse, error) {
64 return local.WhoIs(ctx, remoteAddr)
65}

appc/appconnector_test.go1

403:2discarded-error-resulterror result returned by b.StartAnswers is discarded

appc/appconnector_test.go:403:2

402 b.EnableCompression()
403 b.StartAnswers()
404 switch addr.BitLen() {

client/tailscale/acl.go1

121:1doc-comment-perioddocumentation comment should end with punctuation

client/tailscale/acl.go:121:1

120// https://tailscale.com/s/acl-format
121// https://github.com/tailscale/hujson
122func (c *Client) ACLHuJSON(ctx context.Context) (acl *ACLHuJSON, err error) {

ssh/tailssh/tailssh_integration_test.go1

35:2duplicated-importspackage golang.org/x/crypto/ssh is imported more than once

ssh/tailssh/tailssh_integration_test.go:35:2

34 "golang.org/x/crypto/ssh"
35 gossh "golang.org/x/crypto/ssh"
36 "golang.org/x/crypto/ssh/agent"

cmd/hello/hello.go1

183:3early-returninvert the condition and return early to reduce nesting

cmd/hello/hello.go:183:3

182 if err != nil {
183 if devMode() {
184 log.Printf("warning: using fake data in dev mode due to whois lookup error: %v", err)

ipn/ipnlocal/expiry.go1

205:43empty-conditional-blockempty block should be removed or documented

ipn/ipnlocal/expiry.go:205:43

204 // No expiry for self node
205 } else if selfExpiry.Before(controlNow) {
206 // Self node already expired; we don't want to return a

cmd/tailscale/cli/status.go1

261:2enforce-switch-styledefault clause should be the last switch clause

cmd/tailscale/cli/status.go:261:2

260 switch st.BackendState {
261 default:
262 return fmt.Sprintf("unexpected state: %s", st.BackendState), false

tempfork/sshtest/ssh/server.go1

377:61error-last-resulterror should be the last returned value

tempfork/sshtest/ssh/server.go:377:61

376func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
377 sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
378 gssAPIServer := gssapiConfig.Server

tstest/integration/integration.go1

162:2error-namingpackage error variable should be named errFoo or ErrFoo

tstest/integration/integration.go:162:2

161 buildOnce sync.Once
162 buildErr error
163 binariesCache *Binaries

appc/appconnector_test.go1

251:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:251:13

250 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.0.8")); err != nil {
251 t.Errorf("ObserveDNSResponse: %v", err)
252 }

cmd/stunstamp/stunstamp.go1

836:6error-type-namingerror implementation type should have an Error suffix

cmd/stunstamp/stunstamp.go:836:6

835
836type recoverableErr struct {
837 error

drive/driveimpl/dirfs/dirfs_test.go1

226:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

drive/driveimpl/dirfs/dirfs_test.go:226:2

225func TestRemoveAll(t *testing.T) {
226 fs, _, _, _ := createFileSystem(t)
227

appc/appconnector.go1

267:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:267:24

266// given the new domains and routes.
267func (e *AppConnector) UpdateDomainsAndRoutes(domains []string, routes []netip.Prefix) {
268 e.queue.Add(func() {

client/systray/systray.go1

1:1file-length-limitfile has 790 lines; maximum is 500

client/systray/systray.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/containerboot/forwarding.go1

69:39flag-parameterboolean parameter v6Forwarding controls function flow

cmd/containerboot/forwarding.go:69:39

68
69func enableIPForwarding(v4Forwarding, v6Forwarding bool, root string) error {
70 var paths []string

appc/observe_disabled.go1

1:1formatfile is not formatted

appc/observe_disabled.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt appc/observe_disabled.go`

appc/observe.go1

20:24function-lengthfunction has 61 statements and 113 lines; maximum is 50 statements or 75 lines

appc/observe.go:20:24

19// advised to advertise the discovered route.
20func (e *AppConnector) ObserveDNSResponse(res []byte) error {
21 var p dnsmessage.Parser

cmd/testwrapper/args.go1

51:6function-result-limitfunction returns 4 values; maximum is 3

cmd/testwrapper/args.go:51:6

50// passed to go test and the arguments passed to the tests.
51func splitArgs(args []string) (pre, pkgs, post []string, _ error) {
52 if len(args) == 0 {

client/web/web.go1

492:3identical-switch-branchesswitch repeats a case body

client/web/web.go:492:3

491 return true
492 default:
493 // No additional auth on non-api (assets, index.html, etc).

client/local/local.go1

1167:53import-shadowingidentifier feature shadows an imported package

client/local/local.go:1167:53

1166// 2023-08-09: Valid feature values are "serve" and "funnel".
1167func (lc *Client) QueryFeature(ctx context.Context, feature string) (*tailcfg.QueryFeatureResponse, error) {
1168 v := url.Values{"feature": {feature}}

control/controlclient/map.go1

520:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

control/controlclient/map.go:520:4

519 mut.Online = ptr.To(online)
520 ms.peers[nodeID] = mut.View()
521 stats.changed++

cmd/stunstamp/stunstamp.go1

710:10inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

cmd/stunstamp/stunstamp.go:710:10

709 Name: "region_id",
710 Value: fmt.Sprintf("%d", meta.regionID),
711 })

client/local/local.go1

447:4insecure-url-schemeURL uses insecure http scheme

client/local/local.go:447:4

446 req, err := http.NewRequestWithContext(ctx, "GET",
447 "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-bus-events", nil)
448 if err != nil {

types/prefs/prefs_test.go1

547:18interface-method-limitinterface has 12 methods, exceeding the configured design limit of 10

types/prefs/prefs_test.go:547:18

546// access to the preference's value and state.
547type pref[T any] interface {
548 prefView[T]

kube/egressservices/egressservices.go1

84:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

kube/egressservices/egressservices.go:84:7

83
84func (p PortMaps) MarshalJSON() ([]byte, error) {
85 l := make([]PortMap, 0, len(p))

cmd/cloner/cloner.go1

138:7max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:138:7

137 if codegen.ContainsPointers(ptr.Elem()) {
138 if _, isIface := ptr.Elem().Underlying().(*types.Interface); isIface {
139 it.Import("", "tailscale.com/types/ptr")

prober/derp.go1

409:6max-parametersfunction has 9 parameters; maximum is 8

prober/derp.go:409:6

408
409func runDerpProbeQueuingDelayContinously(ctx context.Context, from, to *tailcfg.DERPNode, fromc, toc *derphttp.Client, packetsPerSecond int, packetTimeout time.Duration, packetsDropped *expvar.Float, qdh *histogram) error {
410 // Make sure all goroutines have finished.

client/tailscale/acl.go1

178:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:178:6

177// ACLTestError is ErrResponse but with an extra field to account for ACLTestFailureSummary.
178type ACLTestError struct {
179 ErrResponse

client/systray/systray.go1

54:3modifies-parameterassignment modifies parameter client

client/systray/systray.go:54:3

53 if client == nil {
54 client = &local.Client{}
55 }

health/state.go1

73:2modifies-value-receiverassignment modifies value receiver u

health/state.go:73:2

72 u.ETag = ""
73 u.ETag = hex.EncodeToString(u.hash())
74 return u

client/local/local.go1

622:10nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:622:10

621 }
622 var res struct {
623 Error string

client/tailscale/acl.go1

495:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

client/tailscale/acl.go:495:3

494 if err != nil {
495 return nil, err
496 }

cmd/k8s-operator/sts.go1

1219:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/k8s-operator/sts.go:1219:3

1218 if len(lst.Items) == 0 {
1219 return nil, nil
1220 }

control/controlhttp/client.go1

150:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

control/controlhttp/client.go:150:3

149 })
150 defer timer.Stop()
151 }

client/local/local.go1

467:6no-else-after-returnremove else and unindent its body after the return

client/local/local.go:467:6

466 return
467 } else if err != nil {
468 yield(eventbus.DebugEvent{}, err)

clientupdate/clientupdate.go1

256:6no-initreplace init with explicit initialization

clientupdate/clientupdate.go:256:6

255
256func init() {
257 feature.HookCanAutoUpdate.Set(canAutoUpdate)

client/local/local.go1

1121:3no-naked-returnreturn values must be explicit

client/local/local.go:1121:3

1120 if err != nil {
1121 return
1122 }

appc/appconnector.go1

87:2no-package-varpackage variables introduce mutable global state

appc/appconnector.go:87:2

86 metricStoreRoutesRate []*clientmetric.Metric
87 metricStoreRoutesN []*clientmetric.Metric
88)

control/controlbase/noiseexplorer_test.go1

314:2overwritten-before-usethis value of ciphertext is overwritten before use

control/controlbase/noiseexplorer_test.go:314:2

313func writeMessageA(hs *handshakestate, payload []byte) (*handshakestate, messagebuffer) {
314 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}
315 hs.e = generateKeypair()

atomicfile/atomicfile_notwindows.go1

6:9package-commentspackage should have a documentation comment

atomicfile/atomicfile_notwindows.go:6:9

5
6package atomicfile
7

k8s-operator/conditions_test.go1

6:9package-directory-mismatchpackage kube does not match directory k8s-operator

k8s-operator/conditions_test.go:6:9

5
6package kube
7

client/web/web_test.go1

772:22range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:772:22

771 if tt.controlURL != "" {
772 testControlURL = &tt.controlURL
773 } else {

cmd/containerboot/settings.go1

390:7receiver-namingreceiver name cfg is inconsistent with s

cmd/containerboot/settings.go:390:7

389
390func (cfg *settings) egressSvcsTerminateEPEnabled() bool {
391 return cfg.LocalAddrPort != "" && cfg.EgressProxiesCfgPath != ""

clientupdate/distsign/distsign.go1

158:2redefines-builtin-ididentifier len shadows a predeclared identifier

clientupdate/distsign/distsign.go:158:2

157 hash.Hash
158 len int64
159}

client/web/web_test.go1

261:36redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:261:36

260func TestGetTailscaleBrowserSession(t *testing.T) {
261 userA := &tailcfg.UserProfile{ID: tailcfg.UserID(1)}
262 userB := &tailcfg.UserProfile{ID: tailcfg.UserID(2)}

ipn/localapi/localapi.go1

892:2redundant-final-returnomit the unnecessary return at the end of a resultless function

ipn/localapi/localapi.go:892:2

891 w.WriteHeader(http.StatusNoContent)
892 return
893}

feature/featuretags/featuretags.go1

21:2single-case-switchswitch with one case can be replaced by an if statement

feature/featuretags/featuretags.go:21:2

20func (ft FeatureTag) IsOmittable() bool {
21 switch ft {
22 case CLI:

clientupdate/distsign/roots.go1

32:6slice-preallocationpreallocate keys with capacity len(range source) before appending once per iteration

clientupdate/distsign/roots.go:32:6

31 }
32 var keys []ed25519.PublicKey
33 for _, f := range files {

client/local/local.go2

699:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/local/local.go:699:46

698func (lc *Client) GetWaitingFile(ctx context.Context, baseName string) (rc io.ReadCloser, size int64, err error) {
699 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/files/"+url.PathEscape(baseName), nil)
700 if err != nil {
1054:3task-commentTODO comment should be resolved or linked to an owned work item

client/local/local.go:1054:3

1053 if runtime.GOOS != "linux" {
1054 // TODO(bradfitz): flesh this out
1055 return "not running?"

wgengine/magicsock/magicsock_test.go1

3138:8time-value-equalitycompare time.Time values with Time.Equal instead of == or !=

wgengine/magicsock/magicsock_test.go:3138:8

3137 newTime := conn.lastErrRebind.Load()
3138 if newTime == lastRebindTime {
3139 t.Errorf("expected a rebind to occur")

chirp/chirp_test.go1

116:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

chirp/chirp_test.go:116:1

115
116type hangingListener struct {
117 net.Listener

cmd/containerboot/ingressservices_test.go1

173:15unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/containerboot/ingressservices_test.go:173:15

172
173 fake := nfr.(*linuxfw.FakeNetfilterRunner)
174 gotServices := fake.GetServiceState()

cmd/stunstamp/stunstamp.go1

866:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

cmd/stunstamp/stunstamp.go:866:2

865 req.Header.Set("X-Prometheus-Remote-Write-Version", "0.1.0")
866 resp, err := r.c.Do(req)
867 if err != nil {

ipn/desktop/sessions_windows.go1

601:6unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:601:6

600
601type _CREATESTRUCT struct {
602 CreateParams uintptr

control/controlbase/handshake.go1

369:81unexported-returnexported function returns an unexported type

control/controlbase/handshake.go:369:81

368// calculation.
369func (s *symmetricState) MixDH(priv key.MachinePrivate, pub key.MachinePublic) (*singleUseCHP, error) {
370 s.checkFinished()

cmd/tailscale/cli/dns-status.go1

116:3unnecessary-formatformatting call has no formatting directive

cmd/tailscale/cli/dns-status.go:116:3

115 } else {
116 fmt.Printf("MagicDNS: disabled tailnet-wide.\n")
117 }

cmd/tailscale/cli/serve_legacy.go1

845:4unreachable-codestatement is unreachable after unconditional control flow

cmd/tailscale/cli/serve_legacy.go:845:4

844 log.Fatalf("lost connection to tailscaled: %v", err)
845 e.lc.IncrementCounter(ctx, fmt.Sprintf("%s_enablement_lost_connection", feature), 1)
846 return err

cmd/tsidp/tsidp.go1

204:31unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

cmd/tsidp/tsidp.go:204:31

203 if *flagPort != 443 {
204 srv.serverURL = fmt.Sprintf("https://%s:%d", strings.TrimSuffix(st.Self.DNSName, "."), *flagPort)
205 } else {

client/web/assets.go1

66:51unused-parameterparameter r is unused

client/web/assets.go:66:51

65
66func openPrecompressedFile(w http.ResponseWriter, r *http.Request, path string, fs fs.FS) (fs.File, error) {
67 if f, err := fs.Open(path + ".gz"); err == nil {

clientupdate/clientupdate.go1

553:7unused-receiverreceiver up is unused

clientupdate/clientupdate.go:553:7

552
553func (up *Updater) updateArchLike() error {
554 // Arch maintainer asked us not to implement "tailscale update" or

tempfork/acme/http.go1

217:87use-anyuse any instead of interface{}

tempfork/acme/http.go:217:87

216// See jwsEncodeJSON for other details.
217func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) {
218 kid := noKeyID

client/local/local.go1

709:18use-errors-newreplace fmt.Errorf with errors.New for a static message

client/local/local.go:709:18

708 res.Body.Close()
709 return nil, 0, fmt.Errorf("unexpected chunking")
710 }

cmd/tl-longchain/tl-longchain.go1

56:2use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tl-longchain/tl-longchain.go:56:2

55 }
56 print("Self", *st.NodeKey, *st.NodeKeySignature)
57 if len(st.VisiblePeers) > 0 {

cmd/sniproxy/sniproxy.go1

208:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/sniproxy/sniproxy.go:208:2

207 }
208 sort.SliceStable(routes, func(i, j int) bool {
209 return routes[i].Addr().Less(routes[j].Addr()) // determinism r us

cmd/containerboot/egressservices_test.go1

25:17var-namingidentifier should use MixedCaps rather than underscores

cmd/containerboot/egressservices_test.go:25:17

24 tailnetIPv4, tailnetIPv6 := netip.MustParseAddr("100.99.99.99"), netip.MustParseAddr("fd7a:115c:a1e0::701:b62a")
25 tailnetIPv4_1, tailnetIPv6_1 := netip.MustParseAddr("100.88.88.88"), netip.MustParseAddr("fd7a:115c:a1e0::4101:512f")
26 ports := map[egressservices.PortMap]struct{}{{Protocol: "tcp", MatchPort: 4003, TargetPort: 80}: {}}

tempfork/sshtest/ssh/session_test.go1

678:3waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/sshtest/ssh/session_test.go:678:3

677 serverID <- conn.SessionID()
678 wg.Add(1)
679 go func() {

tempfork/sshtest/ssh/cipher.go1

461:12weak-cryptographydeprecated cryptographic primitive crypto/des.NewTripleDESCipher should not protect new data

tempfork/sshtest/ssh/cipher.go:461:12

460func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
461 c, err := des.NewTripleDESCipher(key)
462 if err != nil {

appc/appconnector_test.go1

168:50add-constantstring literal "192.0.2.0/24" appears more than twice; define a constant

appc/appconnector_test.go:168:50

167 rc.SetRoutes([]netip.Prefix{netip.MustParsePrefix("192.0.2.1/32")})
168 routes := []netip.Prefix{netip.MustParsePrefix("192.0.2.0/24")}
169 a.updateRoutes(routes)

net/udprelay/server.go1

157:17append-to-sized-slicereply already has a positive length; use make with length zero and capacity, or reslice to zero before append

net/udprelay/server.go:157:17

156 }
157 reply = append(reply, disco.Magic...)
158 reply = serverDisco.AppendTo(reply)

cmd/tailscale/cli/web.go1

12:2blank-importsblank import should be justified by a comment

cmd/tailscale/cli/web.go:12:2

11 "crypto/tls"
12 _ "embed"
13 "flag"

cmd/tailscale/cli/serve_v2_test.go1

1155:7boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/serve_v2_test.go:1155:7

1154
1155 if tt.wantErr == false && err != nil {
1156 t.Errorf("Got an error, but didn't expect one: %v", err)

ipn/ipnlocal/c2n_pprof.go1

34:4call-to-gcavoid explicit garbage collection

ipn/ipnlocal/c2n_pprof.go:34:4

33 if profile == "heap" && gc > 0 {
34 runtime.GC()
35 }

appc/appconnector_test.go1

73:6cognitive-complexityfunction has cognitive complexity 15; maximum is 7

appc/appconnector_test.go:73:6

72
73func TestUpdateRoutes(t *testing.T) {
74 ctx := t.Context()

control/controlhttp/client.go1

98:18confusing-namingname dial differs from Dial only by capitalization

control/controlhttp/client.go:98:18

97
98func (a *Dialer) dial(ctx context.Context) (*ClientConn, error) {
99

cmd/k8s-operator/proxygroup_test.go1

1657:57confusing-resultsadjacent unnamed results of the same type should be named

cmd/k8s-operator/proxygroup_test.go:1657:57

1656
1657func proxyClassesForLEStagingTest() (*tsapi.ProxyClass, *tsapi.ProxyClass, *tsapi.ProxyClass) {
1658 pcLEStaging := &tsapi.ProxyClass{

logtail/buffer.go1

29:6constructor-interface-returnNewMemoryBuffer returns interface Buffer although its concrete result is consistently *memBuffer; return the concrete type

logtail/buffer.go:29:6

28
29func NewMemoryBuffer(numEntries int) Buffer {
30 return &memBuffer{

ipn/ipnlocal/captiveportal.go1

81:50context-as-argumentcontext.Context should be the first parameter

ipn/ipnlocal/captiveportal.go:81:50

80
81func checkCaptivePortalLoop(b *LocalBackend, ctx context.Context) {
82 var tmr *time.Timer

net/netcheck/netcheck.go1

924:24context-cancel-in-loopcontext.WithCancel is created in a loop but its cancellation function is not called during the iteration

net/netcheck/netcheck.go:924:24

923 for _, probeSet := range plan {
924 setCtx, cancelSet := context.WithCancel(ctx)
925 go func(probeSet []probe) {

control/controlclient/direct.go1

88:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

control/controlclient/direct.go:88:2

87 panicOnUse bool // if true, panic if client is used (for testing)
88 closedCtx context.Context // alive until Direct.Close is called
89 closeCtx context.CancelFunc // cancels closedCtx

client/systray/systray.go1

406:19cyclomatic-complexityfunction complexity is 16; maximum is 10

client/systray/systray.go:406:19

405// This method does not return until ctx.Done is closed.
406func (menu *Menu) eventLoop(ctx context.Context) {
407 for {

client/web/web.go1

308:3deep-exitprocess-exit calls should be confined to main or init

client/web/web.go:308:3

307 default: // invalid mode
308 log.Fatalf("invalid mode: %v", mode)
309 }

cmd/gitops-pusher/gitops-pusher.go1

27:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/gitops-pusher/gitops-pusher.go:27:2

26 "golang.org/x/oauth2/clientcredentials"
27 "tailscale.com/client/tailscale"
28 "tailscale.com/util/httpm"

appc/appconnector_test.go1

406:3discarded-error-resulterror result returned by b.AResource is discarded

appc/appconnector_test.go:406:3

405 case 32:
406 b.AResource(
407 dnsmessage.ResourceHeader{

client/tailscale/acl.go1

305:1doc-comment-perioddocumentation comment should end with punctuation

client/tailscale/acl.go:305:1

304
305// ACLPreviewResponse is the response type of previewACLPostRequest
306type ACLPreviewResponse struct {

cmd/k8s-operator/dnsrecords.go1

107:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/dnsrecords.go:107:3

106 if err := dnsRR.maybeProvision(ctx, proxySvc, logger); err != nil {
107 if strings.Contains(err.Error(), optimisticLockErrorMsg) {
108 logger.Infof("optimistic lock error, retrying: %s", err)

ipn/ipnlocal/profiles.go1

923:84empty-conditional-blockempty block should be removed or documented

ipn/ipnlocal/profiles.go:923:84

922 pm.dlogf("no known profiles; trying to migrate from legacy prefs")
923 if initialProfile, err = pm.migrateFromLegacyPrefs(pm.currentUserID); err != nil {
924

cmd/tailscale/cli/up.go1

1045:3enforce-switch-styledefault clause should be the last switch clause

cmd/tailscale/cli/up.go:1045:3

1044 switch f.Name {
1045 default:
1046 panic(fmt.Sprintf("unhandled flag %q", f.Name))

types/lazy/lazy.go1

118:44error-last-resulterror should be the last returned value

types/lazy/lazy.go:118:44

117// and returns both the T and err returned by GetErr's fill function.
118func (z *SyncValue[T]) PeekErr() (v T, err error, ok bool) {
119 if e := z.err.Load(); e != nil {

util/multierr/multierr_test.go1

110:5error-namingpackage error variable should be named errFoo or ErrFoo

util/multierr/multierr_test.go:110:5

109
110var sink error
111

appc/appconnector_test.go1

261:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:261:13

260 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.0.8")); err != nil {
261 t.Errorf("ObserveDNSResponse: %v", err)
262 }

control/controlbase/conn.go1

347:6error-type-namingerror implementation type should have an Error suffix

control/controlbase/conn.go:347:6

346// on a cipher.
347type errCipherExhausted struct{}
348

drive/driveimpl/dirfs/dirfs_test.go1

252:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

drive/driveimpl/dirfs/dirfs_test.go:252:2

251func TestRename(t *testing.T) {
252 fs, _, _, _ := createFileSystem(t)
253

appc/appconnector.go1

279:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:279:24

278// matches all subdomains of a domain.
279func (e *AppConnector) UpdateDomains(domains []string) {
280 e.queue.Add(func() {

client/tailscale/acl.go1

1:1file-length-limitfile has 523 lines; maximum is 500

client/tailscale/acl.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/containerboot/settings.go1

173:39flag-parameterboolean parameter acceptDNS controls function flow

cmd/containerboot/settings.go:173:39

172// be omitted (default to true).
173func parseAcceptDNS(extraArgs string, acceptDNS bool) (string, bool) {
174 if !strings.Contains(extraArgs, "--accept-dns") {

assert_ts_toolchain_match.go1

1:1formatfile is not formatted

assert_ts_toolchain_match.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt assert_ts_toolchain_match.go`

client/systray/systray.go1

203:19function-lengthfunction has 74 statements and 132 lines; maximum is 50 statements or 75 lines

client/systray/systray.go:203:19

202// So for now we rebuild the whole thing, and can optimize this later if needed.
203func (menu *Menu) rebuild() {
204 menu.mu.Lock()

control/controlbase/noiseexplorer_test.go1

329:6function-result-limitfunction returns 4 values; maximum is 3

control/controlbase/noiseexplorer_test.go:329:6

328
329func writeMessageB(hs *handshakestate, payload []byte) ([32]byte, messagebuffer, cipherstate, cipherstate) {
330 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}

client/web/web.go1

687:2identical-switch-branchesswitch repeats a case body

client/web/web.go:687:2

686 return
687 case path == "/local/v0/update/check" && r.Method == httpm.POST:
688 peerAllowed := func(_ noBodyData, peer peerCapabilities) bool {

client/local/tailnetlock.go1

149:73import-shadowingidentifier url shadows an imported package

client/local/tailnetlock.go:149:73

148// in url and returns information extracted from it.
149func (lc *Client) NetworkLockVerifySigningDeeplink(ctx context.Context, url string) (*tka.DeeplinkValidationResult, error) {
150 vr := struct {

derp/derpserver/derpserver.go1

708:3inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

derp/derpserver/derpserver.go:708:3

707 if _, ok := s.clientsMesh[c.key]; !ok {
708 s.clientsMesh[c.key] = nil // just for varz of total users in cluster
709 }

cmd/tailscale/cli/dns-query.go1

181:9inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use the string value directly

cmd/tailscale/cli/dns-query.go:181:9

180 }
181 return fmt.Sprintf("%s", r.Addr)
182}

client/local/local.go1

699:53insecure-url-schemeURL uses insecure http scheme

client/local/local.go:699:53

698func (lc *Client) GetWaitingFile(ctx context.Context, baseName string) (rc io.ReadCloser, size int64, err error) {
699 req, err := http.NewRequestWithContext(ctx, "GET", "http://"+apitype.LocalAPIHost+"/localapi/v0/files/"+url.PathEscape(baseName), nil)
700 if err != nil {

util/testenv/testenv.go1

25:9interface-method-limitinterface has 20 methods, exceeding the configured design limit of 10

util/testenv/testenv.go:25:9

24// TB is testing.TB, to avoid importing "testing" in non-test code.
25type TB interface {
26 Cleanup(func())

net/flowtrack/flowtrack.go1

72:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

net/flowtrack/flowtrack.go:72:7

71
72func (t *Tuple) UnmarshalJSON(b []byte) error {
73 var ot tupleOld

cmd/cloner/cloner.go1

151:12max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:151:12

150 writef("\tdst.%s[i] = append(src.%s[i][:0:0], src.%s[i]...)", fname, fname, fname)
151 } else if _, isIface := ft.Elem().Underlying().(*types.Interface); isIface {
152 writef("\tdst.%s[i] = src.%s[i].Clone()", fname, fname)

prober/derp.go1

705:6max-parametersfunction has 9 parameters; maximum is 8

prober/derp.go:705:6

704// to exercise TCP-in-TCP in similar fashion to TCP over Tailscale via DERP.
705func derpProbeBandwidth(ctx context.Context, dm *tailcfg.DERPMap, from, to *tailcfg.DERPNode, size int64, transferTimeSeconds, totalBytesTransferred *expvar.Float, tunIPv4Prefix *netip.Prefix, meshKey key.DERPMesh) (err error) {
706 // This probe uses clients with isProber=false to avoid spamming the derper logs with every packet

client/tailscale/acl.go1

288:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:288:6

287// While JSON requests will have LineNumber, the value is not useful.
288type UserRuleMatch struct {
289 Users []string `json:"users"`

client/web/auth.go1

218:3modifies-parameterassignment modifies parameter session

client/web/auth.go:218:3

217 if a.Complete {
218 session.Authenticated = a.Complete
219 s.browserSessions.Store(session.ID, session)

logpolicy/logpolicy.go1

551:3modifies-value-receiverassignment modifies value receiver opts

logpolicy/logpolicy.go:551:3

550 if opts.Dir == "" {
551 opts.Dir = LogsDir(earlyLogf)
552 }

client/local/local.go1

762:11nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:762:11

761 }
762 var jres struct {
763 Warning string

client/tailscale/acl.go1

503:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

client/tailscale/acl.go:503:3

502 if err != nil {
503 return nil, err
504 }

cmd/k8s-operator/tsrecorder.go1

406:4nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/k8s-operator/tsrecorder.go:406:4

405 if apierrors.IsNotFound(err) {
406 return nil, nil
407 }

derp/derp_test.go1

115:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

derp/derp_test.go:115:3

114 }
115 defer cout.Close()
116 connsOut = append(connsOut, cout)

client/web/auth.go1

131:4no-else-after-returnremove else and unindent its body after the return

client/web/auth.go:131:4

130 return nil, whoIs, status, errNoSession
131 } else if err != nil {
132 return nil, whoIs, status, err

cmd/derper/bootstrap_dns.go1

49:6no-initreplace init with explicit initialization

cmd/derper/bootstrap_dns.go:49:6

48
49func init() {
50 expvar.Publish("counter_bootstrap_dns_queried_domains", expvar.Func(func() any {

client/local/local.go1

1125:3no-naked-returnreturn values must be explicit

client/local/local.go:1125:3

1124 if err != nil {
1125 return
1126 }

atomicfile/atomicfile_windows_test.go1

14:5no-package-varpackage variables introduce mutable global state

atomicfile/atomicfile_windows_test.go:14:5

13
14var _SECURITY_RESOURCE_MANAGER_AUTHORITY = windows.SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 9}}
15

control/controlbase/noiseexplorer_test.go1

314:2overwritten-before-usethis value of ns is overwritten before use

control/controlbase/noiseexplorer_test.go:314:2

313func writeMessageA(hs *handshakestate, payload []byte) (*handshakestate, messagebuffer) {
314 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}
315 hs.e = generateKeypair()

atomicfile/atomicfile_windows.go1

4:9package-commentspackage should have a documentation comment

atomicfile/atomicfile_windows.go:4:9

3
4package atomicfile
5

k8s-operator/utils.go1

7:9package-directory-mismatchpackage kube does not match directory k8s-operator

k8s-operator/utils.go:7:9

6// Package kube contains types and utilities for the Tailscale Kubernetes Operator.
7package kube
8

client/web/web_test.go1

779:16range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:779:16

778 r.RemoteAddr = remoteIP
779 r.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tt.cookie})
780 w := httptest.NewRecorder()

cmd/k8s-operator/ingress-for-pg.go1

761:7receiver-namingreceiver name a is inconsistent with r

cmd/k8s-operator/ingress-for-pg.go:761:7

760
761func (a *HAIngressReconciler) maybeUpdateAdvertiseServicesConfig(ctx context.Context, pgName string, serviceName tailcfg.ServiceName, mode serviceAdvertisementMode, logger *zap.SugaredLogger) (err error) {
762 // Get all config Secrets for this ProxyGroup.

clientupdate/distsign/distsign.go1

225:8redefines-builtin-ididentifier len shadows a predeclared identifier

clientupdate/distsign/distsign.go:225:8

224 dstPathUnverified := dstPath + ".unverified"
225 hash, len, err := c.download(ctx, srcURL, dstPathUnverified, downloadSizeLimit)
226 if err != nil {

client/web/web_test.go1

262:36redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:262:36

261 userA := &tailcfg.UserProfile{ID: tailcfg.UserID(1)}
262 userB := &tailcfg.UserProfile{ID: tailcfg.UserID(2)}
263

ipn/store/mem/store_mem.go1

66:2redundant-final-returnomit the unnecessary return at the end of a resultless function

ipn/store/mem/store_mem.go:66:2

65 }
66 return
67}

feature/tap/tap_linux.go1

145:3single-case-switchswitch with one case can be replaced by an if statement

feature/tap/tap_linux.go:145:3

144 }
145 switch arpPacket.Op() {
146 case header.ARPRequest:

cmd/k8s-nameserver/main.go1

273:7slice-preallocationpreallocate validIPs with capacity len(range source) before appending once per iteration

cmd/k8s-nameserver/main.go:273:7

272 }
273 var validIPs []net.IP
274 for _, ipS := range ips {

client/local/local.go1

732:46standard-http-method-constantreplace the HTTP method literal with http.MethodPut

client/local/local.go:732:46

731func (lc *Client) PushFile(ctx context.Context, target tailcfg.StableNodeID, size int64, name string, r io.Reader) error {
732 req, err := http.NewRequestWithContext(ctx, "PUT", "http://"+apitype.LocalAPIHost+"/localapi/v0/file-put/"+string(target)+"/"+url.PathEscape(name), r)
733 if err != nil {

client/local/tailnetlock.go1

32:1task-commentTODO comment should be resolved or linked to an owned work item

client/local/tailnetlock.go:32:1

31//
32// TODO(tom): Plumb through disablement secrets.
33func (lc *Client) NetworkLockInit(ctx context.Context, keys []tka.Key, disablementValues [][]byte, supportDisablement []byte) (*ipnstate.NetworkLockStatus, error) {

client/local/local.go1

179:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/local/local.go:179:1

178
179type errorJSON struct {
180 Error string

cmd/containerboot/main_test.go1

1421:32unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/containerboot/main_test.go:1421:32

1420 k.srv = httptest.NewTLSServer(k)
1421 k.Host = k.srv.Listener.Addr().(*net.TCPAddr).IP.String()
1422 k.Port = strconv.Itoa(k.srv.Listener.Addr().(*net.TCPAddr).Port)

control/ts2021/client_test.go1

270:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

control/ts2021/client_test.go:270:2

269 // Verify we can do HTTP/2 against that conn.
270 res, err := nc.Do(req)
271 if err != nil {

ipn/desktop/sessions_windows.go1

616:6unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:616:6

615
616type _POINT struct {
617 X, Y int32

control/controlbase/noiseexplorer_test.go1

391:75unexported-returnexported function returns an unexported type

control/controlbase/noiseexplorer_test.go:391:75

390
391func InitSession(initiator bool, prologue []byte, s keypair, rs [32]byte) noisesession {
392 var session noisesession

cmd/tailscale/cli/network-lock.go1

382:4unnecessary-formatformatting call has no formatting directive

cmd/tailscale/cli/network-lock.go:382:4

381 if isatty.IsTerminal(os.Stdout.Fd()) {
382 fmt.Printf(`Warning
383Removal of a signing key(s) without resigning nodes (--re-sign=false)

cmd/tailscaled/debug.go1

240:3unreachable-codestatement is unreachable after unconditional control flow

cmd/tailscaled/debug.go:240:3

239 log.Fatalf("unknown region %q", derpRegion)
240 panic("unreachable")
241 }

ipn/serve.go1

667:22unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

ipn/serve.go:667:22

666 if port, err := strconv.ParseUint(target, 10, 16); err == nil {
667 return fmt.Sprintf("%s://%s:%d", defaultScheme, host, port), nil
668 }

client/web/web_test.go1

1477:40unused-parameterparameter src is unused

client/web/web_test.go:1477:40

1476
1477func mockNewAuthURL(_ context.Context, src tailcfg.NodeID) (*tailcfg.WebClientAuthResponse, error) {
1478 // Create new dummy auth URL.

clientupdate/clientupdate.go1

561:7unused-receiverreceiver up is unused

clientupdate/clientupdate.go:561:7

560
561func (up *Updater) updateNixos() error {
562 // NixOS package updates are managed on a system level and not individually.

tempfork/acme/jws.go1

62:29use-anyuse any instead of interface{}

tempfork/acme/jws.go:62:29

61// See https://tools.ietf.org/html/rfc7515#section-7.
62func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid KeyID, nonce, url string) ([]byte, error) {
63 if key == nil {

client/local/local.go1

980:15use-errors-newreplace fmt.Errorf with errors.New for a static message

client/local/local.go:980:15

979 res.Body.Close()
980 return nil, fmt.Errorf("httptrace didn't provide a connection")
981 }

cmd/tl-longchain/tl-longchain.go1

60:4use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tl-longchain/tl-longchain.go:60:4

59 for _, peer := range st.VisiblePeers {
60 print(peerInfo(peer), peer.NodeKey, peer.NodeKeySignature)
61 }

cmd/tailscale/cli/netcheck.go1

192:3use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/tailscale/cli/netcheck.go:192:3

191 }
192 sort.Slice(rids, func(i, j int) bool {
193 l1, ok1 := report.RegionLatency[rids[i]]

cmd/natc/natc_test.go1

93:53var-namingidentifier should use MixedCaps rather than underscores

cmd/natc/natc_test.go:93:53

92
93func (r *resolver) LookupNetIP(ctx context.Context, _net, host string) ([]netip.Addr, error) {
94 if addrs, ok := r.resolves[host]; ok {

tempfork/sshtest/ssh/session_test.go1

698:3waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/sshtest/ssh/session_test.go:698:3

697 clientID <- conn.SessionID()
698 wg.Add(1)
699 go func() {

tempfork/sshtest/ssh/keys.go1

1609:12weak-cryptographydeprecated cryptographic primitive crypto/md5.Sum should not protect new data

tempfork/sshtest/ssh/keys.go:1609:12

1608func FingerprintLegacyMD5(pubKey PublicKey) string {
1609 md5sum := md5.Sum(pubKey.Marshal())
1610 hexarray := make([]string, len(md5sum))

appc/appconnector_test.go1

208:13add-constantstring literal "ObserveDNSResponse: %v" appears more than twice; define a constant

appc/appconnector_test.go:208:13

207 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.0.8")); err != nil {
208 t.Errorf("ObserveDNSResponse: %v", err)
209 }

net/udprelay/server_test.go1

71:14append-to-sized-slicepkt already has a positive length; use make with length zero and capacity, or reslice to zero before append

net/udprelay/server_test.go:71:14

70 }
71 pkt = append(pkt, b...)
72 c.write(t, pkt)

feature/capture/dissector/dissector.go1

8:2blank-importsblank import should be justified by a comment

feature/capture/dissector/dissector.go:8:2

7import (
8 _ "embed"
9)

cmd/tailscale/cli/up.go1

933:37boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/up.go:933:37

932 }
933 if flagName == "accept-routes" && valNew == false && env.goos == "linux" && env.distro == distro.Synology {
934 // Issue 3176. Old prefs had 'RouteAll: true' on disk, so ignore that.

tsweb/debug.go1

177:2call-to-gcavoid explicit garbage collection

tsweb/debug.go:177:2

176 }
177 runtime.GC()
178 w.Write([]byte("Done.\n"))

appc/appconnector_test.go1

188:6cognitive-complexityfunction has cognitive complexity 9; maximum is 7

appc/appconnector_test.go:188:6

187
188func TestDomainRoutes(t *testing.T) {
189 bus := eventbustest.NewBus(t)

control/controlhttp/controlhttpserver/controlhttpserver.go1

41:6confusing-namingname acceptHTTP differs from AcceptHTTP only by capitalization

control/controlhttp/controlhttpserver/controlhttpserver.go:41:6

40
41func acceptHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request, private key.MachinePrivate, earlyWrite func(protocolVersion int, w io.Writer) error) (_ *controlbase.Conn, retErr error) {
42 next := strings.ToLower(r.Header.Get("Upgrade"))

cmd/k8s-operator/proxygroup_test.go1

1657:76confusing-resultsadjacent unnamed results of the same type should be named

cmd/k8s-operator/proxygroup_test.go:1657:76

1656
1657func proxyClassesForLEStagingTest() (*tsapi.ProxyClass, *tsapi.ProxyClass, *tsapi.ProxyClass) {
1658 pcLEStaging := &tsapi.ProxyClass{

net/dns/manager_darwin.go1

23:6constructor-interface-returnNewOSConfigurator returns interface OSConfigurator although its concrete result is consistently *darwinConfigurator; return the concrete type

net/dns/manager_darwin.go:23:6

22// The health tracker and the knobs may be nil and are ignored on this platform.
23func NewOSConfigurator(logf logger.Logf, _ *health.Tracker, _ policyclient.Client, _ *controlknobs.Knobs, ifName string) (OSConfigurator, error) {
24 return &darwinConfigurator{logf: logf, ifName: ifName}, nil

ipn/ipnserver/server.go1

78:45context-as-argumentcontext.Context should be the first parameter

ipn/ipnserver/server.go:78:45

77// ready is closed when the waiter is ready (or ctx is done).
78func (s *waiterSet) add(mu *sync.Mutex, ctx context.Context) (ready <-chan struct{}, cleanup func()) {
79 ctx, cancel := context.WithCancel(ctx)

ssh/tailssh/tailssh.go1

382:4context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

ssh/tailssh/tailssh.go:382:4

381 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
382 defer cancel()
383

control/controlclient/map.go1

66:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

control/controlclient/map.go:66:2

65 // sessionAliveCtxClose.
66 sessionAliveCtx context.Context
67 sessionAliveCtxClose context.CancelFunc // closes sessionAliveCtx

client/systray/systray.go1

564:19cyclomatic-complexityfunction complexity is 32; maximum is 10

client/systray/systray.go:564:19

563
564func (menu *Menu) rebuildExitNodeMenu(ctx context.Context) {
565 if menu.status == nil {

clientupdate/clientupdate_windows.go1

165:2deep-exitprocess-exit calls should be confined to main or init

clientupdate/clientupdate_windows.go:165:2

164 // to be replaced.
165 os.Exit(0)
166 panic("unreachable")

cmd/gitops-pusher/gitops-pusher_test.go1

11:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/gitops-pusher/gitops-pusher_test.go:11:2

10
11 "tailscale.com/client/tailscale"
12)

appc/appconnector_test.go1

418:3discarded-error-resulterror result returned by b.AAAAResource is discarded

appc/appconnector_test.go:418:3

417 case 128:
418 b.AAAAResource(
419 dnsmessage.ResourceHeader{

client/tailscale/acl.go1

318:1doc-comment-perioddocumentation comment should end with punctuation

client/tailscale/acl.go:318:1

317
318// ACLPreview is the response type of PreviewACLForUser, PreviewACLForIPPort, PreviewACLHuJSONForUser, and PreviewACLHuJSONForIPPort
319type ACLPreview struct {

cmd/k8s-operator/egress-services.go1

162:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/egress-services.go:162:3

161 if err := esr.maybeProvision(ctx, svc, l); err != nil {
162 if strings.Contains(err.Error(), optimisticLockErrorMsg) {
163 l.Infof("optimistic lock error, retrying: %s", err)

net/dns/manager.go1

368:60empty-conditional-blockempty block should be removed or documented

net/dns/manager.go:368:60

367 baseCfg = &cfg
368 } else if isApple && err == ErrGetBaseConfigNotSupported {
369 // This is currently (2022-10-13) expected on certain iOS and macOS

control/controlclient/map.go1

657:3enforce-switch-styledefault clause should be the last switch clause

control/controlclient/map.go:657:3

656 switch field {
657 default:
658 // The whole point of using reflect in this function is to panic

util/singleflight/singleflight.go1

101:65error-last-resulterror should be the last returned value

util/singleflight/singleflight.go:101:65

100// The return value shared indicates whether v was given to multiple callers.
101func (g *Group[K, V]) Do(key K, fn func() (V, error)) (v V, err error, shared bool) {
102 g.mu.Lock()

util/syspolicy/syspolicy_test.go1

23:5error-namingpackage error variable should be named errFoo or ErrFoo

util/syspolicy/syspolicy_test.go:23:5

22
23var someOtherError = errors.New("error other than not found")
24

appc/appconnector_test.go1

272:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:272:13

271 if err := a.ObserveDNSResponse(dnsCNAMEResponse("192.0.0.9", "www.example.com.", "chain.example.com.", "example.com.")); err != nil {
272 t.Errorf("ObserveDNSResponse: %v", err)
273 }

control/controlbase/conn.go1

357:6error-type-namingerror implementation type should have an Error suffix

control/controlbase/conn.go:357:6

356// become unusable due to a past partial write.
357type errPartialWrite struct {
358 err error

net/dnscache/dnscache.go1

272:6excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

net/dnscache/dnscache.go:272:6

271 if r.UseLastGood {
272 if _, _, _, ok := r.lookupIPCacheExpired(host); ok {
273 // If we have some previous good value for this host,

appc/appconnector.go1

287:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:287:24

286// complete.
287func (e *AppConnector) Wait(ctx context.Context) {
288 e.queue.Wait(ctx)

client/web/web.go1

1:1file-length-limitfile has 1385 lines; maximum is 500

client/web/web.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/egress-services.go1

739:47flag-parameterboolean parameter configured controls function flow

cmd/k8s-operator/egress-services.go:739:47

738
739func svcConfiguredReason(svc *corev1.Service, configured bool, l *zap.SugaredLogger) string {
740 var r string

atomicfile/atomicfile.go1

1:1formatfile is not formatted

atomicfile/atomicfile.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt atomicfile/atomicfile.go`

client/systray/systray.go1

564:19function-lengthfunction has 72 statements and 125 lines; maximum is 50 statements or 75 lines

client/systray/systray.go:564:19

563
564func (menu *Menu) rebuildExitNodeMenu(ctx context.Context) {
565 if menu.status == nil {

control/controlbase/noiseexplorer_test.go1

367:6function-result-limitfunction returns 5 values; maximum is 3

control/controlbase/noiseexplorer_test.go:367:6

366
367func readMessageB(hs *handshakestate, message *messagebuffer) ([32]byte, []byte, bool, cipherstate, cipherstate) {
368 valid1 := true

client/web/web.go1

694:2identical-switch-branchesswitch repeats a case body

client/web/web.go:694:2

693 return
694 case path == "/local/v0/update/progress" && r.Method == httpm.POST:
695 newHandler[noBodyData](s, w, r, alwaysAllowed).

client/tailscale/tailscale.go1

86:2import-shadowingidentifier url shadows an imported package

client/tailscale/tailscale.go:86:2

85 }
86 url := c.baseURL() + path.Join(elem...)
87 if query != "" {

ipn/ipnlocal/state_test.go1

1609:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

ipn/ipnlocal/state_test.go:1609:4

1608 })
1609 derpmap.Regions[n.HomeDERP] = r
1610 }

ipn/ipnlocal/serve.go1

1076:46inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatUint with base 10

ipn/ipnlocal/serve.go:1076:46

1075 fqdn := strings.Join([]string{forVIPService.WithoutPrefix(), magicDNSSuffix}, ".")
1076 key := ipn.HostPort(net.JoinHostPort(fqdn, fmt.Sprintf("%d", port)))
1077 return b.serveConfig.FindServiceWeb(forVIPService, key)

client/local/local.go1

732:53insecure-url-schemeURL uses insecure http scheme

client/local/local.go:732:53

731func (lc *Client) PushFile(ctx context.Context, target tailcfg.StableNodeID, size int64, name string, r io.Reader) error {
732 req, err := http.NewRequestWithContext(ctx, "PUT", "http://"+apitype.LocalAPIHost+"/localapi/v0/file-put/"+string(target)+"/"+url.PathEscape(name), r)
733 if err != nil {

wgengine/wgengine.go1

62:13interface-method-limitinterface has 15 methods, exceeding the configured design limit of 10

wgengine/wgengine.go:62:13

61// Engine is the Tailscale WireGuard engine interface.
62type Engine interface {
63 // Reconfig reconfigures WireGuard and makes sure it's running.

tailcfg/tailcfg.go1

312:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tailcfg/tailcfg.go:312:7

311// UnmarshalJSON sets *m to a copy of data.
312func (m *RawMessage) UnmarshalJSON(data []byte) error {
313 if m == nil {

cmd/cloner/cloner.go1

198:6max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:198:6

197 writef("\t\tif v == nil { dst.%s[k] = nil } else {", fname)
198 if base := elem.Elem().Underlying(); codegen.ContainsPointers(base) {
199 if _, isIface := base.(*types.Interface); isIface {

prober/derp.go1

900:6max-parametersfunction has 9 parameters; maximum is 8

prober/derp.go:900:6

899// is recorded in `transferTimeSeconds`.
900func derpProbeBandwidthTUN(ctx context.Context, transferTimeSeconds, totalBytesTransferred *expvar.Float, from, to *tailcfg.DERPNode, fromc, toc *derphttp.Client, size int64, prefix *netip.Prefix) error {
901 // Make sure all goroutines have finished.

client/tailscale/acl.go1

306:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:306:6

305// ACLPreviewResponse is the response type of previewACLPostRequest
306type ACLPreviewResponse struct {
307 Matches []UserRuleMatch `json:"matches"` // ACL rules that match the specified user or ipport.

client/web/web.go1

185:3modifies-parameterassignment modifies parameter opts

client/web/web.go:185:3

184 if opts.LocalClient == nil {
185 opts.LocalClient = &local.Client{}
186 }

logpolicy/logpolicy.go1

554:3modifies-value-receiverassignment modifies value receiver opts

logpolicy/logpolicy.go:554:3

553 if opts.CmdName == "" {
554 opts.CmdName = version.CmdName()
555 }

client/local/local.go1

782:11nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:782:11

781 }
782 var jres struct {
783 Warning string

client/tailscale/acl.go1

519:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

client/tailscale/acl.go:519:3

518 // failed to unmarshal
519 return nil, err
520 }

cmd/ssh-auth-none-demo/ssh-auth-none-demo.go1

97:6nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/ssh-auth-none-demo/ssh-auth-none-demo.go:97:6

96 }
97 return nil, nil
98 },

derp/derp_test.go1

122:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

derp/derp_test.go:122:3

121 }
122 defer cin.Close()
123

client/web/auth.go1

144:4no-else-after-returnremove else and unindent its body after the return

client/web/auth.go:144:4

143 return nil, whoIs, status, errNoSession
144 } else if session.isExpired(s.timeNow()) {
145 // Session expired, remove from session map and return errNoSession.

cmd/derper/derper.go1

106:6no-initreplace init with explicit initialization

cmd/derper/derper.go:106:6

105
106func init() {
107 expvar.Publish("derper_tls_request_version", tlsRequestVersion)

client/tailscale/dns.go1

196:3no-naked-returnreturn values must be explicit

client/tailscale/dns.go:196:3

195 if err != nil {
196 return
197 }

client/local/local.go1

50:5no-package-varpackage variables introduce mutable global state

client/local/local.go:50:5

49// package-level functions.
50var defaultClient Client
51

control/controlbase/noiseexplorer_test.go1

330:2overwritten-before-usethis value of ciphertext is overwritten before use

control/controlbase/noiseexplorer_test.go:330:2

329func writeMessageB(hs *handshakestate, payload []byte) ([32]byte, messagebuffer, cipherstate, cipherstate) {
330 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}
331 hs.e = generateKeypair()

atomicfile/mksyscall.go1

4:9package-commentspackage should have a documentation comment

atomicfile/mksyscall.go:4:9

3
4package atomicfile
5

license_test.go1

4:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

license_test.go:4:9

3
4package tailscaleroot
5

client/web/web_test.go1

1028:16range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:1028:16

1027 r.RemoteAddr = tt.remoteAddr
1028 r.AddCookie(&http.Cookie{Name: sessionCookieName, Value: tt.cookie})
1029 w := httptest.NewRecorder()

cmd/k8s-operator/sts.go1

195:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:195:7

194// up to date.
195func (a *tailscaleSTSReconciler) Provision(ctx context.Context, logger *zap.SugaredLogger, sts *tailscaleSTSConfig) (*corev1.Service, error) {
196 // Do full reconcile.

cmd/containerboot/main.go1

245:3redefines-builtin-ididentifier close shadows a predeclared identifier

cmd/containerboot/main.go:245:3

244
245 close := runHTTPServer(mux, cfg.HealthCheckAddrPort)
246 defer close()

client/web/web_test.go1

443:35redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:443:35

442 // browser sessions w/ different users.
443 user := &tailcfg.UserProfile{ID: tailcfg.UserID(1)}
444 self := &ipnstate.PeerStatus{ID: "self", UserID: user.ID}

kube/kubeclient/client.go1

453:2redundant-final-returnomit the unnecessary return at the end of a resultless function

kube/kubeclient/client.go:453:2

452 hasPerms = true
453 return
454}

feature/wakeonlan/wakeonlan.go1

227:2single-case-switchswitch with one case can be replaced by an if statement

feature/wakeonlan/wakeonlan.go:227:2

226 base := strings.TrimRightFunc(ifName, unicode.IsNumber)
227 switch runtime.GOOS {
228 case "darwin":

cmd/k8s-nameserver/main.go1

294:7slice-preallocationpreallocate validIPs with capacity len(range source) before appending once per iteration

cmd/k8s-nameserver/main.go:294:7

293 }
294 var validIPs []net.IP
295 for _, ipS := range ips {

client/local/local.go1

949:46standard-http-method-constantreplace the HTTP method literal with http.MethodPost

client/local/local.go:949:46

948 ctx = httptrace.WithClientTrace(ctx, &trace)
949 req, err := http.NewRequestWithContext(ctx, "POST", "http://"+apitype.LocalAPIHost+"/localapi/v0/dial", nil)
950 if err != nil {

client/systray/systray.go1

319:2task-commentTODO comment should be resolved or linked to an owned work item

client/systray/systray.go:319:2

318
319 // TODO(#15528): this menu item shouldn't be necessary at all,
320 // but is at least more discoverable than having users switch profiles or exit nodes.

client/systray/logo.go1

36:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/systray/logo.go:36:1

35
36var (
37 // disconnected is all gray dots

cmd/containerboot/main_test.go1

1422:45unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/containerboot/main_test.go:1422:45

1421 k.Host = k.srv.Listener.Addr().(*net.TCPAddr).IP.String()
1422 k.Port = strconv.Itoa(k.srv.Listener.Addr().(*net.TCPAddr).Port)
1423

drive/driveimpl/drive_test.go1

221:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

drive/driveimpl/drive_test.go:221:2

220 u := fmt.Sprintf("http://%s/%s/%s", addr, wrongSecret, url.PathEscape(file111))
221 resp, err := client.Get(u)
222 if err != nil {

ipn/desktop/sessions_windows.go1

620:6unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:620:6

619
620type _MSG struct {
621 HWnd windows.HWND

control/controlbase/noiseexplorer_test.go1

404:58unexported-returnexported function returns an unexported type

control/controlbase/noiseexplorer_test.go:404:58

403
404func SendMessage(session *noisesession, message []byte) (*noisesession, messagebuffer) {
405 var messageBuffer messagebuffer

cmd/tailscale/cli/network-lock.go1

388:5unnecessary-formatformatting call has no formatting directive

cmd/tailscale/cli/network-lock.go:388:5

387 if !prompt.YesNo("Are you sure you want to remove the signing key(s)?", true) {
388 fmt.Printf("aborting removal of signing key(s)\n")
389 os.Exit(0)

cmd/testwrapper/testwrapper.go1

209:3unreachable-codestatement is unreachable after unconditional control flow

cmd/testwrapper/testwrapper.go:209:3

208 log.Fatal(err)
209 return
210 }

ipn/store/kubestore/store_kube.go1

84:24unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

ipn/store/kubestore/store_kube.go:84:24

83 // Derive the API server address from the environment variables
84 c.SetURL(fmt.Sprintf("https://%s:%s", os.Getenv("KUBERNETES_SERVICE_HOST"), os.Getenv("KUBERNETES_SERVICE_PORT_HTTPS")))
85 }

client/web/web_test.go1

1482:52unused-parameterparameter src is unused

client/web/web_test.go:1482:52

1481
1482func mockWaitAuthURL(_ context.Context, id string, src tailcfg.NodeID) (*tailcfg.WebClientAuthResponse, error) {
1483 switch id {

clientupdate/clientupdate.go1

757:7unused-receiverreceiver up is unused

clientupdate/clientupdate.go:757:7

756
757func (up *Updater) updateMacSys() error {
758 return errors.New("NOTREACHED: On MacSys builds, `tailscale update` is handled in Swift to launch the GUI updater")

tempfork/gliderlabs/ssh/context.go1

91:22use-anyuse any instead of interface{}

tempfork/gliderlabs/ssh/context.go:91:22

90 // SetValue allows you to easily write new values into the underlying context.
91 SetValue(key, value interface{})
92}

client/tailscale/keys.go1

87:19use-errors-newreplace fmt.Errorf with errors.New for a static message

client/tailscale/keys.go:87:19

86 if expirySeconds < 0 {
87 return "", nil, fmt.Errorf("expiry must be positive")
88 }

cmd/tl-longchain/tl-longchain.go1

66:4use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

cmd/tl-longchain/tl-longchain.go:66:4

65 for _, peer := range st.FilteredPeers {
66 print(peerInfo(peer), peer.NodeKey, peer.NodeKeySignature)
67 }

cmd/tailscale/cli/serve_legacy.go1

722:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/tailscale/cli/serve_legacy.go:722:2

721 mounts := slicesx.MapKeys(sc.Web[hp].Handlers)
722 sort.Slice(mounts, func(i, j int) bool {
723 return len(mounts[i]) < len(mounts[j])

cmd/tsidp/tsidp.go1

1100:2var-namingidentifier should use MixedCaps rather than underscores

cmd/tsidp/tsidp.go:1100:2

1099 UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`
1100 JWKS_URI string `json:"jwks_uri"`
1101 ScopesSupported views.Slice[string] `json:"scopes_supported"`

tempfork/sshtest/ssh/session_test.go1

871:3waitgroup-add-inside-goroutinecall WaitGroup.Add before starting the goroutine to avoid racing with Wait

tempfork/sshtest/ssh/session_test.go:871:3

870 }
871 wg.Add(1)
872 go func() {

appc/appconnector_test.go1

213:40add-constantstring literal "192.0.0.8" appears more than twice; define a constant

appc/appconnector_test.go:213:40

212 want := map[string][]netip.Addr{
213 "example.com": {netip.MustParseAddr("192.0.0.8")},
214 }

net/udprelay/server_test.go1

102:14append-to-sized-slicepkt already has a positive length; use make with length zero and capacity, or reslice to zero before append

net/udprelay/server_test.go:102:14

101 }
102 pkt = append(pkt, disco.Magic...)
103 pkt = c.local.Public().AppendTo(pkt)

feature/condregister/maybe_ace.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_ace.go:8:8

7
8import _ "tailscale.com/feature/ace"
9

cmd/tailscale/cli/up.go1

941:42boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/up.go:941:42

940 }
941 if flagName == "stateful-filtering" && valCur == true && valNew == false && env.goos == "linux" {
942 // See https://github.com/tailscale/tailscale/issues/12307

wgengine/netstack/netstack_test.go1

98:2call-to-gcavoid explicit garbage collection

wgengine/netstack/netstack_test.go:98:2

97func getMemStats() (ms runtime.MemStats) {
98 runtime.GC()
99 runtime.ReadMemStats(&ms)

appc/appconnector_test.go1

229:6cognitive-complexityfunction has cognitive complexity 35; maximum is 7

appc/appconnector_test.go:229:6

228
229func TestObserveDNSResponse(t *testing.T) {
230 ctx := t.Context()

control/controlhttp/http_test.go1

148:6confusing-namingname testControlHTTP differs from TestControlHTTP only by capitalization

control/controlhttp/http_test.go:148:6

147
148func testControlHTTP(t *testing.T, param httpTestParam) {
149 proxy := param.proxy

control/controlbase/conn_test.go1

364:75confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/conn_test.go:364:75

363
364func pairWithConns(t *testing.T, clientConn, serverConn net.Conn) (*Conn, *Conn) {
365 var (

net/memnet/conn.go1

32:6constructor-interface-returnNewConn returns interface Conn although its concrete result is consistently *connHalf; return the concrete type

net/memnet/conn.go:32:6

31// NewConn creates a pair of Conns that are wired together by pipes.
32func NewConn(name string, maxBuf int) (Conn, Conn) {
33 r := NewPipe(name+"|0", maxBuf)

net/netmon/loghelper.go1

46:64context-as-argumentcontext.Context should be the first parameter

net/netmon/loghelper.go:46:64

45
46func (nm *Monitor) changeDeltaWatcher(ec *eventbus.Client, ctx context.Context, fn func(ChangeDelta)) func(*eventbus.Client) {
47 sub := eventbus.Subscribe[ChangeDelta](ec)

tsnet/tsnet_test.go1

1285:3context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

tsnet/tsnet_test.go:1285:3

1284 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
1285 defer cancel()
1286 status1, err := lc1.Status(ctx)

derp/derphttp/derphttp_client.go1

84:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

derp/derphttp/derphttp_client.go:84:2

83
84 ctx context.Context // closed via cancelCtx in Client.Close
85 cancelCtx context.CancelFunc

client/web/auth.go1

108:18cyclomatic-complexityfunction complexity is 15; maximum is 10

client/web/auth.go:108:18

107// unless getTailscaleBrowserSession reports errNotUsingTailscale.
108func (s *Server) getSession(r *http.Request) (*browserSession, *apitype.WhoIsResponse, *ipnstate.Status, error) {
109 whoIs, whoIsErr := s.lc.WhoIs(r.Context(), r.RemoteAddr)

cmd/addlicense/main.go1

36:2deep-exitprocess-exit calls should be confined to main or init

cmd/addlicense/main.go:36:2

35`[1:])
36 os.Exit(2)
37}

cmd/k8s-operator/operator.go1

50:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/k8s-operator/operator.go:50:2

49 "tailscale.com/client/local"
50 "tailscale.com/client/tailscale"
51 "tailscale.com/hostinfo"

appc/appconnector_test.go1

439:2discarded-error-resulterror result returned by b.StartAnswers is discarded

appc/appconnector_test.go:439:2

438 b.EnableCompression()
439 b.StartAnswers()
440

client/web/web.go1

47:1doc-comment-perioddocumentation comment should end with punctuation

client/web/web.go:47:1

46// ListenPort is the static port used for the web client when run inside tailscaled.
47// (5252 are the numbers above the letters "TSTS" on a qwerty keyboard.)
48const ListenPort = 5252

cmd/k8s-operator/ingress.go1

84:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/ingress.go:84:3

83 if err := a.maybeProvision(ctx, logger, ing); err != nil {
84 if strings.Contains(err.Error(), optimisticLockErrorMsg) {
85 logger.Infof("optimistic lock error, retrying: %s", err)

net/netmon/netmon_linux.go1

200:48empty-conditional-blockempty block should be removed or documented

net/netmon/netmon_linux.go:200:48

199
200 if rmsg.Table == tsTable && dst.IsSingleIP() {
201 // Don't log. Spammy and normal to see a bunch of these on start-up,

derp/derp_client.go1

536:3enforce-switch-styledefault clause should be the last switch clause

derp/derp_client.go:536:3

535 switch t {
536 default:
537 continue

util/winutil/subprocess_windows_test.go1

261:2error-namingpackage error variable should be named errFoo or ErrFoo

util/winutil/subprocess_windows_test.go:261:2

260 gorootPath string
261 gorootErr error
262)

appc/appconnector_test.go1

283:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:283:13

282 if err := a.ObserveDNSResponse(dnsCNAMEResponse("192.0.0.10", "outside.example.org.", "www.example.com.", "example.org.")); err != nil {
283 t.Errorf("ObserveDNSResponse: %v", err)
284 }

control/controlbase/conn.go1

370:6error-type-namingerror implementation type should have an Error suffix

control/controlbase/conn.go:370:6

369// unacceptably large Noise frame.
370type errReadTooBig struct {
371 requested int

net/dnscache/dnscache_test.go1

141:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

net/dnscache/dnscache_test.go:141:2

140
141 _, _, _, err = r.LookupIP(context.Background(), "bad")
142 if got, want := fmt.Sprint(err), `dnscache: unexpected hostname "bad" doesn't match expected "foo.bar"`; got != want {

appc/appconnector.go1

293:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:293:24

292// It is safe (and a noop) to call Close on nil.
293func (e *AppConnector) Close() {
294 if e == nil {

client/web/web_test.go1

1:1file-length-limitfile has 1590 lines; maximum is 500

client/web/web_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/ingress-for-pg_test.go1

762:76flag-parameterboolean parameter wantHTTP controls function flow

cmd/k8s-operator/ingress-for-pg_test.go:762:76

761
762func verifyServeConfig(t *testing.T, fc client.Client, serviceName string, wantHTTP bool) {
763 t.Helper()

atomicfile/atomicfile_notwindows.go1

1:1formatfile is not formatted

atomicfile/atomicfile_notwindows.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt atomicfile/atomicfile_notwindows.go`

client/web/web.go1

725:18function-lengthfunction has 46 statements and 96 lines; maximum is 50 statements or 75 lines

client/web/web.go:725:18

724// and returns an authResponse indicating the current auth state and any steps the user needs to take.
725func (s *Server) serveAPIAuth(w http.ResponseWriter, r *http.Request) {
726 var resp authResponse

control/controlclient/direct.go1

517:18function-result-limitfunction returns 4 values; maximum is 3

control/controlclient/direct.go:517:18

516
517func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, newURL string, nks tkatype.MarshaledSignature, err error) {
518 if c.panicOnUse {

client/web/web.go1

698:2identical-switch-branchesswitch repeats a case body

client/web/web.go:698:2

697 return
698 case path == "/local/v0/upload-client-metrics" && r.Method == httpm.POST:
699 newHandler[noBodyData](s, w, r, alwaysAllowed).

client/web/assets.go1

66:81import-shadowingidentifier fs shadows an imported package

client/web/assets.go:66:81

65
66func openPrecompressedFile(w http.ResponseWriter, r *http.Request, path string, fs fs.FS) (fs.File, error) {
67 if f, err := fs.Open(path + ".gz"); err == nil {

net/netcheck/netcheck.go1

1389:5inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

net/netcheck/netcheck.go:1389:5

1388 if bd, ok := bestRecent[regionID]; !ok || d < bd {
1389 bestRecent[regionID] = d
1390 }

ipn/ipnlocal/serve.go1

1079:49inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatUint with base 10

ipn/ipnlocal/serve.go:1079:49

1078 }
1079 key := ipn.HostPort(net.JoinHostPort(hostname, fmt.Sprintf("%d", port)))
1080 return b.serveConfig.FindWeb(key)

client/local/local.go1

949:54insecure-url-schemeURL uses insecure http scheme

client/local/local.go:949:54

948 ctx = httptrace.WithClientTrace(ctx, &trace)
949 req, err := http.NewRequestWithContext(ctx, "POST", "http://"+apitype.LocalAPIHost+"/localapi/v0/dial", nil)
950 if err != nil {

tailcfg/tailcfg.go1

650:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tailcfg/tailcfg.go:650:7

649
650func (m *MachineStatus) UnmarshalText(b []byte) error {
651 switch string(b) {

cmd/cloner/cloner.go1

199:7max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:199:7

198 if base := elem.Elem().Underlying(); codegen.ContainsPointers(base) {
199 if _, isIface := base.(*types.Interface); isIface {
200 it.Import("", "tailscale.com/types/ptr")

wgengine/netlog/netlog.go1

100:19max-parametersfunction has 9 parameters; maximum is 8

wgengine/netlog/netlog.go:100:19

99// The netMon parameter is optional; if non-nil it's used to do faster interface lookups.
100func (nl *Logger) Startup(nodeID tailcfg.StableNodeID, nodeLogID, domainLogID logid.PrivateID, tun, sock Device, netMon *netmon.Monitor, health *health.Tracker, bus *eventbus.Bus, logExitFlowEnabledEnabled bool) error {
101 nl.mu.Lock()

client/tailscale/acl.go1

319:6max-public-structsfile declares more than 5 exported structs

client/tailscale/acl.go:319:6

318// ACLPreview is the response type of PreviewACLForUser, PreviewACLForIPPort, PreviewACLHuJSONForUser, and PreviewACLHuJSONForIPPort
319type ACLPreview struct {
320 Matches []UserRuleMatch `json:"matches"`

client/web/web.go1

359:3modifies-parameterassignment modifies parameter r

client/web/web.go:359:3

358 if r.URL.Path == "/metrics" {
359 r.URL.Path = "/api/local/v0/usermetrics"
360 s.proxyRequestToLocalAPI(w, r)

logpolicy/logpolicy.go1

559:3modifies-value-receiverassignment modifies value receiver opts

logpolicy/logpolicy.go:559:3

558 if useStdLogger {
559 opts.Logf = log.Printf
560 }

client/local/local.go1

801:11nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:801:11

800 }
801 var jres struct {
802 Warning string

cmd/k8s-nameserver/main.go1

397:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-nameserver/main.go:397:3

396 } else if os.IsNotExist(err) {
397 return nil, nil
398 } else {

cmd/stunstamp/stunstamp.go1

454:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/stunstamp/stunstamp.go:454:3

453 if !info.stableConn && bool(stable) {
454 return nil, nil
455 }

derp/derp_test.go1

125:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

derp/derp_test.go:125:3

124 ctx, cancel := context.WithCancel(context.Background())
125 defer cancel()
126

client/web/auth.go1

319:5no-else-after-returnremove else and unindent its body after the return

client/web/auth.go:319:5

318 return peerCapabilities{}, nil
319 } else {
320 return peerCapabilities{capFeatureAll: true}, nil // owner can edit all features

cmd/derper/derper.go1

513:6no-initreplace init with explicit initialization

cmd/derper/derper.go:513:6

512
513func init() {
514 expvar.Publish("go_sync_mutex_wait_seconds", expvar.Func(func() any {

cmd/derpprobe/derpprobe.go1

199:2no-naked-returnreturn values must be explicit

cmd/derpprobe/derpprobe.go:199:2

198 sort.Strings(o.good)
199 return
200}

client/local/local.go1

233:5no-package-varpackage variables introduce mutable global state

client/local/local.go:233:5

232
233var onVersionMismatch func(clientVer, serverVer string)
234

control/controlbase/noiseexplorer_test.go1

344:2overwritten-before-usethis value of ciphertext is overwritten before use

control/controlbase/noiseexplorer_test.go:344:2

343func writeMessageRegular(cs *cipherstate, payload []byte) (*cipherstate, messagebuffer) {
344 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}
345 cs, ciphertext = encryptWithAd(cs, []byte{}, payload)

client/local/cert.go1

6:9package-commentspackage should have a documentation comment

client/local/cert.go:6:9

5
6package local
7

pkgdoc_test.go1

4:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

pkgdoc_test.go:4:9

3
4package tailscaleroot
5

client/web/web_test.go1

1558:9range-value-addresstaking the address of range value tt can be misleading

client/web/web_test.go:1558:9

1557
1558 s := &Server{
1559 originOverride: tt.originOverride,

cmd/k8s-operator/sts.go1

239:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:239:7

238// otherwise it returns false and the caller should retry later.
239func (a *tailscaleSTSReconciler) Cleanup(ctx context.Context, logger *zap.SugaredLogger, labels map[string]string, typ string) (done bool, _ error) {
240 // Need to delete the StatefulSet first, and delete it with foreground

cmd/containerboot/main.go1

267:3redefines-builtin-ididentifier close shadows a predeclared identifier

cmd/containerboot/main.go:267:3

266
267 close := runHTTPServer(mux, cfg.LocalAddrPort)
268 defer close()

client/web/web_test.go1

532:66redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:532:66

531func TestServeAuth(t *testing.T) {
532 user := &tailcfg.UserProfile{LoginName: "user@example.com", ID: tailcfg.UserID(1)}
533 self := &ipnstate.PeerStatus{

net/art/stride_table.go1

181:2redundant-final-returnomit the unnecessary return at the end of a resultless function

net/art/stride_table.go:181:2

180 t.allot(idx, old, p)
181 return
182}

ipn/ipnlocal/local.go1

2121:3single-case-switchswitch with one case can be replaced by an if statement

ipn/ipnlocal/local.go:2121:3

2120 // sufficient.
2121 switch m.(type) {
2122 case netmap.NodeMutationOnline:

cmd/k8s-operator/egress-eps.go1

106:2slice-preallocationpreallocate newEndpoints with capacity len(range source) before appending once per iteration

cmd/k8s-operator/egress-eps.go:106:2

105 }
106 newEndpoints := make([]discoveryv1.Endpoint, 0)
107 for _, pod := range podList.Items {

client/local/local.go1

1218:46standard-http-method-constantreplace the HTTP method literal with http.MethodPost

client/local/local.go:1218:46

1217func (lc *Client) StreamDebugCapture(ctx context.Context) (io.ReadCloser, error) {
1218 req, err := http.NewRequestWithContext(ctx, "POST", "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-capture", nil)
1219 if err != nil {

client/systray/systray.go2

687:2task-commentTODO comment should be resolved or linked to an owned work item

client/systray/systray.go:687:2

686
687 // TODO: "Allow Local Network Access" and "Run Exit Node" menu items
688}
76:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/systray/systray.go:76:1

75// Menu represents the systray menu, its items, and the current Tailscale state.
76type Menu struct {
77 mu sync.Mutex // protects the entire Menu

cmd/containerboot/main_test.go1

1665:20unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/containerboot/main_test.go:1665:20

1664 }
1665 port := ln.Addr().(*net.TCPAddr).Port
1666 *p = port

ipn/localapi/localapi_test.go1

88:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

ipn/localapi/localapi_test.go:88:2

87 }
88 res, err := c.Do(req)
89 if err != nil {

ipn/desktop/sessions_windows.go1

630:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:630:2

629const (
630 _WM_CREATE = 1
631 _WM_DESTROY = 2

control/controlbase/noiseexplorer_test.go1

404:73unexported-returnexported function returns an unexported type

control/controlbase/noiseexplorer_test.go:404:73

403
404func SendMessage(session *noisesession, message []byte) (*noisesession, messagebuffer) {
405 var messageBuffer messagebuffer

ipn/auditlog/auditlog_test.go1

323:49unnecessary-formatformatting call has no formatting directive

ipn/auditlog/auditlog_test.go:323:49

322
323 err := al.Enqueue(tailcfg.AuditNodeDisconnect, fmt.Sprintf("log 1"))
324 c.Assert(err, qt.IsNil)

cmd/tsconnect/wasm/wasm_js.go1

54:4unreachable-codestatement is unreachable after unconditional control flow

cmd/tsconnect/wasm/wasm_js.go:54:4

53 log.Fatal("Usage: newIPN(config)")
54 return nil
55 }

tsconsensus/http.go1

31:21unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

tsconsensus/http.go:31:21

30func (rac *commandClient) url(host string, path string) string {
31 return fmt.Sprintf("http://%s:%d%s", host, rac.port, path)
32}

clientupdate/clientupdate.go1

881:25unused-parameterparameter ctx is unused

clientupdate/clientupdate.go:881:25

880
881func restartSystemdUnit(ctx context.Context) error {
882 if _, err := exec.LookPath("systemctl"); err != nil {

clientupdate/clientupdate_not_downloads.go1

8:7unused-receiverreceiver up is unused

clientupdate/clientupdate_not_downloads.go:8:7

7
8func (up *Updater) downloadURLToFile(pathSrc, fileDst string) (ret error) {
9 panic("unreachable")

tempfork/gliderlabs/ssh/context.go1

122:44use-anyuse any instead of interface{}

tempfork/gliderlabs/ssh/context.go:122:44

121
122func (ctx *sshContext) SetValue(key, value interface{}) {
123 ctx.Context = context.WithValue(ctx.Context, key, value)

client/tailscale/keys.go1

90:19use-errors-newreplace fmt.Errorf with errors.New for a static message

client/tailscale/keys.go:90:19

89 if expirySeconds == 0 && expiry != 0 {
90 return "", nil, fmt.Errorf("non-zero expiry must be at least one second")
91 }

logtail/logtail.go1

560:3use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

logtail/logtail.go:560:3

559 // ourselves.
560 println("logtail: try drain wake, numHTTP:", l.httpDoCalls.Load())
561 }

cmd/tailscale/cli/serve_v2.go1

741:3use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/tailscale/cli/serve_v2.go:741:3

740 mounts := slicesx.MapKeys(webConfig.Handlers)
741 sort.Slice(mounts, func(i, j int) bool {
742 return len(mounts[i]) < len(mounts[j])

control/controlbase/noiseexplorer_test.go1

47:2var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:47:2

46type keypair struct {
47 public_key [32]byte
48 private_key [32]byte

appc/appconnector_test.go1

260:46add-constantstring literal "example.com." appears more than twice; define a constant

appc/appconnector_test.go:260:46

259 a.updateDomains([]string{"example.com"})
260 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.0.8")); err != nil {
261 t.Errorf("ObserveDNSResponse: %v", err)

feature/condregister/maybe_appconnectors.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_appconnectors.go:8:8

7
8import _ "tailscale.com/feature/appconnectors"
9

cmd/tailscale/cli/up.go1

941:60boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/up.go:941:60

940 }
941 if flagName == "stateful-filtering" && valCur == true && valNew == false && env.goos == "linux" {
942 // See https://github.com/tailscale/tailscale/issues/12307

appc/appconnector_test.go1

343:6cognitive-complexityfunction has cognitive complexity 17; maximum is 7

appc/appconnector_test.go:343:6

342
343func TestWildcardDomains(t *testing.T) {
344 ctx := t.Context()

derp/derp_client.go1

98:6confusing-namingname newClient differs from NewClient only by capitalization

derp/derp_client.go:98:6

97
98func newClient(privateKey key.NodePrivate, nc Conn, brw *bufio.ReadWriter, logf logger.Logf, opt clientOpt) (*Client, error) {
99 c := &Client{

control/controlbase/conn_test.go1

387:33confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/conn_test.go:387:33

386
387func pair(t *testing.T) (*Conn, *Conn) {
388 s1, s2 := memnet.NewConn("noise", 128000)

net/memnet/conn.go1

40:6constructor-interface-returnNewTCPConn returns interface Conn although its concrete result is consistently *connHalf; return the concrete type

net/memnet/conn.go:40:6

39// NewTCPConn creates a pair of Conns that are wired together by pipes.
40func NewTCPConn(src, dst netip.AddrPort, maxBuf int) (local Conn, remote Conn) {
41 r := NewPipe(src.String(), maxBuf)

net/ping/ping_test.go1

333:52context-as-argumentcontext.Context should be the first parameter

net/ping/ping_test.go:333:52

332
333func (p *Pinger) waitOutstanding(t *testing.T, ctx context.Context, count int) {
334 // This is a bit janky, but... we busy-loop to wait for the Send call

tstest/integration/integration_test.go1

739:3context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

tstest/integration/integration_test.go:739:3

738 ctx, cancel = context.WithTimeout(t.Context(), 2*time.Second)
739 defer cancel()
740

feature/capture/capture.go1

96:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

feature/capture/capture.go:96:2

95type Sink struct {
96 ctx context.Context
97 ctxCancel context.CancelFunc

client/web/web.go1

332:18cyclomatic-complexityfunction complexity is 15; maximum is 10

client/web/web.go:332:18

331
332func (s *Server) serve(w http.ResponseWriter, r *http.Request) {
333 if s.mode == ManageServerMode {

cmd/addlicense/main.go1

65:3deep-exitprocess-exit calls should be confined to main or init

cmd/addlicense/main.go:65:3

64 fmt.Fprintln(os.Stderr, err)
65 os.Exit(1)
66 }

cmd/k8s-operator/proxygroup.go1

35:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/k8s-operator/proxygroup.go:35:2

34
35 "tailscale.com/client/tailscale"
36 "tailscale.com/ipn"

appc/appconnector_test.go1

443:4discarded-error-resulterror result returned by b.CNAMEResource is discarded

appc/appconnector_test.go:443:4

442 for i, domain := range domains[:len(domains)-1] {
443 b.CNAMEResource(
444 dnsmessage.ResourceHeader{

client/web/web_test.go1

91:1doc-comment-perioddocumentation comment should end with punctuation

client/web/web_test.go:91:1

90// 1. invalid endpoint errors
91// 2. permissioning of api endpoints based on node capabilities
92func TestServeAPI(t *testing.T) {

cmd/k8s-operator/proxygroup.go1

705:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/proxygroup.go:705:3

704 errResp := &tailscale.ErrResponse{}
705 if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
706 logger.Debugf("device %s not found, likely because it has already been deleted from control", string(id))

tempfork/sshtest/ssh/channel.go1

329:25empty-conditional-blockempty block should be removed or documented

tempfork/sshtest/ssh/channel.go:329:25

328 ch.extPending.write(data)
329 } else if extended > 0 {
330 // discard other extended data.

derp/derp_test.go1

156:5enforce-switch-styledefault clause should be the last switch clause

derp/derp_test.go:156:5

155 switch m := m.(type) {
156 default:
157 t.Errorf("unexpected message type %T", m)

appc/appconnector_test.go1

294:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:294:13

293 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "2001:db8::1")); err != nil {
294 t.Errorf("ObserveDNSResponse: %v", err)
295 }

kube/kubeapi/api.go1

216:6error-type-namingerror implementation type should have an Error suffix

kube/kubeapi/api.go:216:6

215// Status is a return value for calls that don't return other objects.
216type Status struct {
217 TypeMeta `json:",inline"`

net/stun/stun_fuzzer.go1

8:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

net/stun/stun_fuzzer.go:8:2

7func FuzzStunParser(data []byte) int {
8 _, _, _ = ParseResponse(data)
9

appc/appconnector.go1

422:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appconnector.go:422:24

421// addresses.
422func (e *AppConnector) DomainRoutes() map[string][]netip.Addr {
423 e.mu.Lock()

clientupdate/clientupdate.go1

1:1file-length-limitfile has 1234 lines; maximum is 500

clientupdate/clientupdate.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/operator.go1

828:52flag-parameterboolean parameter isDefaultLoadBalancer controls function flow

cmd/k8s-operator/operator.go:828:52

827// event is observed on a tailscale Ingress, reconcile the proxy headless Service.
828func dnsRecordsReconcilerIngressHandler(ns string, isDefaultLoadBalancer bool, cl client.Client, logger *zap.SugaredLogger) handler.MapFunc {
829 return func(ctx context.Context, o client.Object) []reconcile.Request {

atomicfile/atomicfile_test.go1

1:1formatfile is not formatted

atomicfile/atomicfile_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt atomicfile/atomicfile_test.go`

client/web/web.go1

934:18function-lengthfunction has 47 statements and 116 lines; maximum is 50 statements or 75 lines

client/web/web.go:934:18

933
934func (s *Server) serveGetNodeData(w http.ResponseWriter, r *http.Request) {
935 st, err := s.lc.Status(r.Context())

derp/derphttp/derphttp_client.go1

676:18function-result-limitfunction returns 4 values; maximum is 3

derp/derphttp/derphttp_client.go:676:18

675// established.
676func (c *Client) DialRegionTLS(ctx context.Context, reg *tailcfg.DERPRegion) (tlsConn *tls.Conn, connClose io.Closer, node *tailcfg.DERPNode, err error) {
677 tcpConn, node, err := c.dialRegion(ctx, reg)

clientupdate/clientupdate.go1

1025:2identical-switch-branchesswitch repeats a case body

clientupdate/clientupdate.go:1025:2

1024 return errors.New("Tailscale was not found in the QNAP App Center")
1025 default:
1026 return fmt.Errorf("failed to check update status with qpkg_cli (upgradeStatus = %d)", status)

client/web/qnap.go1

102:28import-shadowingidentifier url shadows an imported package

client/web/qnap.go:102:28

101
102func qnapAuthnFinish(user, url string) (string, *qnapAuthResponse, error) {
103 // QNAP Force HTTPS mode uses a self-signed certificate. Even importing

net/netcheck/netcheck.go1

1489:3inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

net/netcheck/netcheck.go:1489:3

1488 if prev, ok := m[regionID]; !ok || d < prev {
1489 m[regionID] = d
1490 }

k8s-operator/apis/v1alpha1/types_proxyclass.go1

191:10inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatUint with base 10

k8s-operator/apis/v1alpha1/types_proxyclass.go:191:10

190 if pr.EndPort == 0 {
191 return fmt.Sprintf("%d", pr.Port)
192 }

client/local/local.go1

1218:54insecure-url-schemeURL uses insecure http scheme

client/local/local.go:1218:54

1217func (lc *Client) StreamDebugCapture(ctx context.Context) (io.ReadCloser, error) {
1218 req, err := http.NewRequestWithContext(ctx, "POST", "http://"+apitype.LocalAPIHost+"/localapi/v0/debug-capture", nil)
1219 if err != nil {

tailcfg/tailcfg.go1

1190:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tailcfg/tailcfg.go:1190:7

1189
1190func (st *SignatureType) UnmarshalText(b []byte) error {
1191 switch string(b) {

cmd/cloner/cloner.go1

211:6max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:211:6

210 case *types.Interface:
211 if cloneResultType := methodResultType(elem, "Clone"); cloneResultType != nil {
212 if _, isPtr := cloneResultType.(*types.Pointer); isPtr {

wgengine/netlog/netlog.go1

163:6max-parametersfunction has 9 parameters; maximum is 8

wgengine/netlog/netlog.go:163:6

162
163func recordStatistics(logger *logtail.Logger, nodeID tailcfg.StableNodeID, start, end time.Time, connstats, sockStats map[netlogtype.Connection]netlogtype.Counts, addrs map[netip.Addr]bool, prefixes map[netip.Prefix]bool, logExitFlowEnabled bool) {
164 m := netlogtype.Message{NodeID: nodeID, Start: start.UTC(), End: end.UTC()}

client/tailscale/apitype/apitype.go1

76:6max-public-structsfile declares more than 5 exported structs

client/tailscale/apitype/apitype.go:76:6

75// It returns the StableNodeID, name, and location of a suggested exit node for the client making the request.
76type ExitNodeSuggestionResponse struct {
77 ID tailcfg.StableNodeID

client/web/web.go1

1145:3modifies-parameterassignment modifies parameter data

client/web/web.go:1145:3

1144 if data.SetExitNode {
1145 data.AdvertiseRoutes = currNonExitRoutes
1146 } else if data.SetRoutes {

logpolicy/logpolicy.go1

872:3modifies-value-receiverassignment modifies value receiver opts

logpolicy/logpolicy.go:872:3

871 if opts.NetMon == nil {
872 opts.NetMon = netmon.NewStatic()
873 }

client/local/local.go1

822:11nested-structsmove nested anonymous struct types to named declarations

client/local/local.go:822:11

821 }
822 var jres struct {
823 Warning string

cmd/k8s-operator/api-server-proxy-pg.go1

95:4nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/api-server-proxy-pg.go:95:4

94 logger.Infof("optimistic lock error, retrying: %s", err)
95 return reconcile.Result{}, nil
96 }

cmd/stunstamp/stunstamp.go1

457:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/stunstamp/stunstamp.go:457:3

456 if !info.userspaceTS && source == timestampSourceUserspace {
457 return nil, nil
458 }

envknob/envknob.go1

589:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

envknob/envknob.go:589:3

588 }
589 defer f.Close()
590

client/web/web.go1

254:5no-else-after-returnremove else and unindent its body after the return

client/web/web.go:254:5

253 return
254 } else if secFetchSite != "" {
255 http.Error(w, fmt.Sprintf("CSRF request denied with Sec-Fetch-Site %q", secFetchSite), http.StatusForbidden)

cmd/stunstamp/stunstamp.go1

161:6no-initreplace init with explicit initialization

cmd/stunstamp/stunstamp.go:161:6

160
161func init() {
162 lports = &lportsPool{

cmd/sniproxy/server.go1

211:3no-naked-returnreturn values must be explicit

cmd/sniproxy/server.go:211:3

210 if err != nil {
211 return
212 }

client/local/local.go1

330:5no-package-varpackage variables introduce mutable global state

client/local/local.go:330:5

329// [Client.WhoIsProto] when a peer is not found.
330var ErrPeerNotFound = errors.New("peer not found")
331

derp/derphttp/derphttp_test.go1

622:2overwritten-before-usethis value of err is overwritten before use

derp/derphttp/derphttp_test.go:622:2

621 netMon := netmon.NewStatic()
622 c, err := derphttp.NewClient(key.NewNode(), "https://"+hostname+"/", t.Logf, netMon)
623 defer c.Close()

client/local/debugportmapper.go1

6:9package-commentspackage should have a documentation comment

client/local/debugportmapper.go:6:9

5
6package local
7

types/prefs/prefs_example/prefs_test.go1

4:9package-directory-mismatchpackage prefs_example does not match directory prefs_example

types/prefs/prefs_example/prefs_test.go:4:9

3
4package prefs_example
5

clientupdate/clientupdate_test.go1

651:28range-value-addresstaking the address of range value content can be misleading

clientupdate/clientupdate_test.go:651:28

650 for file, content := range files {
651 if err := tw.WriteHeader(&tar.Header{
652 Name: file,

cmd/k8s-operator/sts.go1

342:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:342:7

341
342func (a *tailscaleSTSReconciler) reconcileHeadlessService(ctx context.Context, logger *zap.SugaredLogger, sts *tailscaleSTSConfig) (*corev1.Service, error) {
343 nameBase := statefulSetNameBase(sts.ParentResourceName)

cmd/containerboot/main.go1

873:54redefines-builtin-ididentifier close shadows a predeclared identifier

cmd/containerboot/main.go:873:54

872
873func runHTTPServer(mux *http.ServeMux, addr string) (close func() error) {
874 ln, err := net.Listen("tcp", addr)

client/web/web_test.go1

802:33redundant-conversionconversion from string to the identical type is redundant

client/web/web_test.go:802:33

801 }
802 if diff := cmp.Diff(gotResp, string(wantResp)); diff != "" {
803 t.Errorf("wrong response; (-got+want):%v", diff)

ssh/tailssh/tailssh.go1

1052:2redundant-final-returnomit the unnecessary return at the end of a resultless function

ssh/tailssh/tailssh.go:1052:2

1051 ss.Exit(1)
1052 return
1053}

ipn/ipnlocal/local.go1

2134:3single-case-switchswitch with one case can be replaced by an if statement

ipn/ipnlocal/local.go:2134:3

2133 for _, m := range muts {
2134 switch m.(type) {
2135 case netmap.NodeMutationLastSeen,

cmd/k8s-operator/egress-services_test.go1

241:2slice-preallocationpreallocate ports with capacity len(range source) before appending once per iteration

cmd/k8s-operator/egress-services_test.go:241:2

240func portsForEndpointSlice(svc *corev1.Service) []discoveryv1.EndpointPort {
241 ports := make([]discoveryv1.EndpointPort, 0)
242 for _, p := range svc.Spec.Ports {

client/local/local.go1

1244:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/local/local.go:1244:46

1243func (lc *Client) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*IPNBusWatcher, error) {
1244 req, err := http.NewRequestWithContext(ctx, "GET",
1245 "http://"+apitype.LocalAPIHost+"/localapi/v0/watch-ipn-bus?mask="+fmt.Sprint(mask),

client/tailscale/acl.go2

99:2task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/acl.go:99:2

98 // If status code was not successful, return the error.
99 // TODO: Change the check for the StatusCode to include other 2XX success codes.
100 if resp.StatusCode != http.StatusOK {
166:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/tailscale/acl.go:166:1

165// JavaScript client to be rendered in the HTML.
166type ACLTestFailureSummary struct {
167 // User is the source ("src") value of the ACL test that failed.

cmd/derper/cert_test.go1

146:21unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/derper/cert_test.go:146:21

145
146 lnPort := ln.Addr().(*net.TCPAddr).Port
147

net/captivedetection/captivedetection.go1

225:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

net/captivedetection/captivedetection.go:225:2

224 // Make the actual request, and check if the response looks like a captive portal or not.
225 r, err := d.httpClient.Do(req)
226 if err != nil {

ipn/desktop/sessions_windows.go1

631:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:631:2

630 _WM_CREATE = 1
631 _WM_DESTROY = 2
632 _WM_CLOSE = 16

control/controlbase/noiseexplorer_test.go1

424:66unexported-returnexported function returns an unexported type

control/controlbase/noiseexplorer_test.go:424:66

423
424func RecvMessage(session *noisesession, message *messagebuffer) (*noisesession, []byte, bool) {
425 var plaintext []byte

net/art/table.go1

161:4unnecessary-formatformatting call has no formatting directive

net/art/table.go:161:4

160 if debugInsert {
161 fmt.Printf("insert: default route\n")
162 }

cmd/tsconnect/wasm/wasm_js.go1

170:5unreachable-codestatement is unreachable after unconditional control flow

cmd/tsconnect/wasm/wasm_js.go:170:5

169 })`)
170 return nil
171 }

tsconsensus/tsconsensus_test.go1

455:21unsafe-formatted-url-host-portformatted host and port may be invalid for IPv6; build the address with net.JoinHostPort

tsconsensus/tsconsensus_test.go:455:21

454
455 url := fmt.Sprintf("http://%s:%d/", ps[0].c.self.hostAddr.String(), mp)
456 httpClientOnTailnet := ps[1].ts.HTTPClient()

clientupdate/clientupdate_not_downloads.go1

8:38unused-parameterparameter pathSrc is unused

clientupdate/clientupdate_not_downloads.go:8:38

7
8func (up *Updater) downloadURLToFile(pathSrc, fileDst string) (ret error) {
9 panic("unreachable")

clientupdate/clientupdate_notwindows.go1

8:7unused-receiverreceiver up is unused

clientupdate/clientupdate_notwindows.go:8:7

7
8func (up *Updater) updateWindows() error {
9 panic("unreachable")

tempfork/gliderlabs/ssh/session_test.go1

298:24use-anyuse any instead of interface{}

tempfork/gliderlabs/ssh/session_test.go:298:24

297 // doneChan lets us specify that we should exit.
298 doneChan := make(chan interface{})
299

client/web/qnap.go1

55:18use-errors-newreplace fmt.Errorf with errors.New for a static message

client/web/qnap.go:55:18

54 }
55 return "", nil, fmt.Errorf("not authenticated by any mechanism")
56}

util/winutil/testdata/testrestartableprocesses/main.go1

31:3use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

util/winutil/testdata/testrestartableprocesses/main.go:31:3

30 if len(os.Args) < 2 {
31 println("usage: " + os.Args[0] + " name-of-test")
32 return

cmd/tsidp/ui.go1

77:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

cmd/tsidp/ui.go:77:2

76
77 sort.Slice(clients, func(i, j int) bool {
78 if clients[i].Name != clients[j].Name {

control/controlbase/noiseexplorer_test.go1

48:2var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:48:2

47 public_key [32]byte
48 private_key [32]byte
49}

appc/appconnector_test.go1

314:62add-constantstring literal "192.0.2.1" appears more than twice; define a constant

appc/appconnector_test.go:314:62

313 wantRoutes = append(wantRoutes, pfx)
314 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.2.1")); err != nil {
315 t.Errorf("ObserveDNSResponse: %v", err)

feature/condregister/maybe_c2n.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_c2n.go:8:8

7
8import _ "tailscale.com/feature/c2n"
9

cmd/tailscale/cli/up.go1

1106:5boolean-literal-comparisonomit the boolean literal from the logical expression

cmd/tailscale/cli/up.go:1106:5

1105func fmtFlagValueArg(flagName string, val any) string {
1106 if val == true {
1107 return "--" + flagName

appc/appconnector_test.go1

571:6cognitive-complexityfunction has cognitive complexity 14; maximum is 7

appc/appconnector_test.go:571:6

570
571func TestUpdateDomainRouteRemoval(t *testing.T) {
572 ctx := t.Context()

derp/derp_client.go1

221:18confusing-namingname send differs from Send only by capitalization

derp/derp_client.go:221:18

220
221func (c *Client) send(dstKey key.NodePublic, pkt []byte) (ret error) {
222 defer func() {

control/controlbase/noiseexplorer_test.go1

169:81confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/noiseexplorer_test.go:169:81

168
169func decrypt(k [32]byte, n uint32, ad []byte, ciphertext []byte) (bool, []byte, []byte) {
170 var nonce [12]byte

tempfork/sshtest/ssh/client.go1

71:6constructor-interface-returnNewClientConn returns interface Conn although its concrete result is consistently *connection; return the concrete type

tempfork/sshtest/ssh/client.go:71:6

70// must be serviced or the connection will hang.
71func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
72 fullConf := *config

net/portmapper/upnp_test.go1

1043:39context-as-argumentcontext.Context should be the first parameter

net/portmapper/upnp_test.go:1043:39

1042
1043func mustProbeUPnP(tb testing.TB, ctx context.Context, c *Client) portmappertype.ProbeResult {
1044 tb.Helper()

util/singleflight/singleflight_test.go1

432:6context-cancel-in-loopcancellation deferred inside a loop runs only when the surrounding function returns; cancel before the iteration ends

util/singleflight/singleflight_test.go:432:6

431 ctx, cancel := context.WithCancel(context.Background())
432 defer cancel()
433 cancels = append(cancels, cancel)

feature/portlist/portlist.go1

44:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

feature/portlist/portlist.go:44:2

43type Extension struct {
44 ctx context.Context
45 ctxCancel context.CancelFunc

client/web/web.go1

471:18cyclomatic-complexityfunction complexity is 13; maximum is 10

client/web/web.go:471:18

470// errors to the ResponseWriter itself.
471func (s *Server) authorizeRequest(w http.ResponseWriter, r *http.Request) (ok bool) {
472 if s.mode == ManageServerMode { // client using tailscale auth

cmd/connector-gen/aws.go1

38:3deep-exitprocess-exit calls should be confined to main or init

cmd/connector-gen/aws.go:38:3

37 if err != nil {
38 log.Fatal(err)
39 }

cmd/k8s-operator/proxygroup_test.go1

29:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/k8s-operator/proxygroup_test.go:29:2

28 "sigs.k8s.io/controller-runtime/pkg/client/fake"
29 "tailscale.com/client/tailscale"
30 "tailscale.com/ipn"

appc/appconnector_test.go1

461:3discarded-error-resulterror result returned by b.AResource is discarded

appc/appconnector_test.go:461:3

460 case 32:
461 b.AResource(
462 dnsmessage.ResourceHeader{

cmd/gitops-pusher/gitops-pusher.go1

347:1doc-comment-perioddocumentation comment should end with punctuation

cmd/gitops-pusher/gitops-pusher.go:347:1

346
347// ACLGitopsTestError is redefined here so we can add a custom .Error() response
348type ACLGitopsTestError struct {

cmd/k8s-operator/proxygroup.go1

1145:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/proxygroup.go:1145:3

1144 device := tsapi.TailnetDevice{}
1145 if hostname, _, ok := strings.Cut(string(m.stateSecret.Data[kubetypes.KeyDeviceFQDN]), "."); ok {
1146 device.Hostname = hostname

tempfork/sshtest/ssh/client_auth_test.go1

708:115empty-conditional-blockempty block should be removed or documented

tempfork/sshtest/ssh/client_auth_test.go:708:115

707 // message. See issue 50805.
708 if runtime.GOOS == "windows" && strings.Contains(err.Error(), "wsarecv: An established connection was aborted") {
709 // OK.

derp/derp_test.go1

374:4enforce-switch-styledefault clause should be the last switch clause

derp/derp_test.go:374:4

373 switch m := m.(type) {
374 default:
375 errCh <- fmt.Errorf("%s: unexpected message type %T", name, m)

appc/appconnector_test.go1

303:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:303:13

302 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "2001:db8::1")); err != nil {
303 t.Errorf("ObserveDNSResponse: %v", err)
304 }

net/neterror/neterror.go1

71:6error-type-namingerror implementation type should have an Error suffix

net/neterror/neterror.go:71:6

70
71type ErrUDPGSODisabled struct {
72 OnLaddr string

tempfork/gliderlabs/ssh/example_test.go1

36:4excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

tempfork/gliderlabs/ssh/example_test.go:36:4

35 }
36 allowed, _, _, _, err := ssh.ParseAuthorizedKey(data)
37 if err != nil {

appc/appctest/appctest.go1

25:27exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appctest/appctest.go:25:27

24
25func (rc *RouteCollector) AdvertiseRoute(pfx ...netip.Prefix) error {
26 rc.routes = append(rc.routes, pfx...)

clientupdate/clientupdate_test.go1

1:1file-length-limitfile has 953 lines; maximum is 500

clientupdate/clientupdate_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/proxygroup_test.go1

1747:89flag-parameterboolean parameter shouldExist controls function flow

cmd/k8s-operator/proxygroup_test.go:1747:89

1746
1747func expectProxyGroupResources(t *testing.T, fc client.WithWatch, pg *tsapi.ProxyGroup, shouldExist bool, proxyClass *tsapi.ProxyClass) {
1748 t.Helper()

atomicfile/atomicfile_windows_test.go1

1:1formatfile is not formatted

atomicfile/atomicfile_windows_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt atomicfile/atomicfile_windows_test.go`

client/web/web.go1

1177:18function-lengthfunction has 27 statements and 78 lines; maximum is 50 statements or 75 lines

client/web/web.go:1177:18

1176// If reauthentication has been requested, an authURL is returned to complete device registration.
1177func (s *Server) tailscaleUp(ctx context.Context, st *ipnstate.Status, opt tailscaleUpOptions) (authURL string, retErr error) {
1178 origAuthURL := st.AuthURL

derp/derpserver/derpserver.go1

1585:18function-result-limitfunction returns 4 values; maximum is 3

derp/derpserver/derpserver.go:1585:18

1584
1585func (s *Server) recvForwardPacket(br *bufio.Reader, frameLen uint32) (srcKey, dstKey key.NodePublic, contents []byte, err error) {
1586 if frameLen < derp.KeyLen*2 {

cmd/proxy-to-grafana/proxy-to-grafana.go1

100:2identical-switch-branchesswitch repeats a case body

cmd/proxy-to-grafana/proxy-to-grafana.go:100:2

99 return "Admin"
100 default:
101 // A safe default.

client/web/web.go1

640:2import-shadowingidentifier path shadows an imported package

client/web/web.go:640:2

639
640 path := strings.TrimPrefix(r.URL.Path, "/api")
641 switch {

net/netmon/state.go1

501:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

net/netmon/state.go:501:4

500 iface.Desc = desc
501 s.Interface[dr.InterfaceName] = iface
502 }

release/dist/synology/pkgs.go1

60:22inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

release/dist/synology/pkgs.go:60:22

59func (t *target) dsmVersionString() string {
60 dsmVersionString := fmt.Sprintf("%d", t.dsmMajorVersion)
61 if t.dsmMinorVersion != 0 {

client/local/local.go1

1245:3insecure-url-schemeURL uses insecure http scheme

client/local/local.go:1245:3

1244 req, err := http.NewRequestWithContext(ctx, "GET",
1245 "http://"+apitype.LocalAPIHost+"/localapi/v0/watch-ipn-bus?mask="+fmt.Sprint(mask),
1246 nil)

tka/aum.go1

49:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tka/aum.go:49:7

48// MarshalText implements encoding.TextMarshaler.
49func (h AUMHash) MarshalText() ([]byte, error) {
50 return h.AppendText(nil)

cmd/cloner/cloner.go1

212:7max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/cloner/cloner.go:212:7

211 if cloneResultType := methodResultType(elem, "Clone"); cloneResultType != nil {
212 if _, isPtr := cloneResultType.(*types.Pointer); isPtr {
213 writef("\t\tdst.%s[k] = *(v.Clone())", fname)

client/tailscale/apitype/apitype.go1

84:6max-public-structsfile declares more than 5 exported structs

client/tailscale/apitype/apitype.go:84:6

83// into the CLI.
84type DNSOSConfig struct {
85 Nameservers []string

client/web/web.go1

1147:3modifies-parameterassignment modifies parameter data

client/web/web.go:1147:3

1146 } else if data.SetRoutes {
1147 data.AdvertiseExitNode = currAdvertisingExitNode
1148 data.UseExitNode = prefs.ExitNodeID

logpolicy/logpolicy.go1

894:3modifies-value-receiverassignment modifies value receiver opts

logpolicy/logpolicy.go:894:3

893 if opts.Logf == nil {
894 opts.Logf = log.Printf
895 }

client/local/tailnetlock.go1

137:39nested-structsmove nested anonymous struct types to named declarations

client/local/tailnetlock.go:137:39

136 var b bytes.Buffer
137 if err := json.NewEncoder(&b).Encode(struct{}{}); err != nil {
138 return err

cmd/k8s-operator/api-server-proxy-pg.go1

177:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/api-server-proxy-pg.go:177:3

176 tsoperator.SetProxyGroupCondition(pg, tsapi.KubeAPIServerProxyValid, metav1.ConditionFalse, reasonKubeAPIServerProxyInvalid, msg, pg.Generation, r.clock, logger)
177 return nil
178 }

cmd/stunstamp/stunstamp.go1

460:3nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/stunstamp/stunstamp.go:460:3

459 if !info.kernelTS && source == timestampSourceKernel {
460 return nil, nil
461 }

feature/taildrop/ext.go1

296:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

feature/taildrop/ext.go:296:3

295 gotFile, gotFileCancel := context.WithCancel(context.Background())
296 defer gotFileCancel()
297

client/web/web.go1

654:6no-else-after-returnremove else and unindent its body after the return

client/web/web.go:654:6

653 return false
654 } else if d.SetRoutes && !p.canEdit(capFeatureSubnets) {
655 return false

cmd/tailscale/cli/cert.go1

30:6no-initreplace init with explicit initialization

cmd/tailscale/cli/cert.go:30:6

29
30func init() {
31 maybeCertCmd = func() *ffcli.Command {

cmd/sniproxy/server.go1

217:3no-naked-returnreturn values must be explicit

cmd/sniproxy/server.go:217:3

216 if err != nil {
217 return
218 }

client/systray/logo.go1

38:2no-package-varpackage variables introduce mutable global state

client/systray/logo.go:38:2

37 // disconnected is all gray dots
38 disconnected = tsLogo{dots: [9]byte{
39 0, 0, 0,

net/tsdial/tsdial.go1

290:2overwritten-before-usethis value of rip is overwritten before use

net/tsdial/tsdial.go:290:2

289 }
290 lip, rip := la.AddrPort().Addr(), ra.AddrPort().Addr()
291

client/local/serve.go1

6:9package-commentspackage should have a documentation comment

client/local/serve.go:6:9

5
6package local
7

types/prefs/prefs_example/prefs_types.go1

11:9package-directory-mismatchpackage prefs_example does not match directory prefs_example

types/prefs/prefs_example/prefs_types.go:11:9

10// generating code for test packages.
11package prefs_example
12

clientupdate/clientupdate_test.go1

651:28range-value-addresstaking the address of range value file can be misleading

clientupdate/clientupdate_test.go:651:28

650 for file, content := range files {
651 if err := tw.WriteHeader(&tar.Header{
652 Name: file,

cmd/k8s-operator/sts.go1

362:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:362:7

361
362func (a *tailscaleSTSReconciler) provisionSecrets(ctx context.Context, logger *zap.SugaredLogger, stsC *tailscaleSTSConfig, hsvc *corev1.Service) ([]string, error) {
363 secretNames := make([]string, stsC.Replicas)

cmd/featuretags/featuretags.go1

21:2redefines-builtin-ididentifier min shadows a predeclared identifier

cmd/featuretags/featuretags.go:21:2

20var (
21 min = flag.Bool("min", false, "remove all features not mentioned in --add")
22 remove = flag.String("remove", "", "a comma-separated list of features to remove from the build. (without the 'ts_omit_' prefix)")

client/web/web_test.go1

838:66redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:838:66

837func TestServeAPIAuthMetricLogging(t *testing.T) {
838 user := &tailcfg.UserProfile{LoginName: "user@example.com", ID: tailcfg.UserID(1)}
839 otherUser := &tailcfg.UserProfile{LoginName: "user2@example.com", ID: tailcfg.UserID(2)}

tstest/tstest.go1

36:2redundant-final-returnomit the unnecessary return at the end of a resultless function

tstest/tstest.go:36:2

35 *target = val
36 return
37}

k8s-operator/sessionrecording/spdy/conn.go1

145:3single-case-switchswitch with one case can be replaced by an if statement

k8s-operator/sessionrecording/spdy/conn.go:145:3

144 if !sf.Ctrl && c.hasTerm { // data frame
145 switch sf.StreamID {
146 case c.resizeStreamID.Load():

cmd/k8s-operator/operator.go1

766:3slice-preallocationpreallocate reqs with capacity len(range source) before appending once per iteration

cmd/k8s-operator/operator.go:766:3

765 return func(ctx context.Context, _ client.Object) []reconcile.Request {
766 reqs := make([]reconcile.Request, 0)
767

client/tailscale/acl.go2

88:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/tailscale/acl.go:88:46

87 path := c.BuildTailnetURL("acl")
88 req, err := http.NewRequestWithContext(ctx, "GET", path, nil)
89 if err != nil {
205:2task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/acl.go:205:2

204 // If status code was not successful, return the error.
205 // TODO: Change the check for the StatusCode to include other 2XX success codes.
206 if resp.StatusCode != http.StatusOK {

client/tailscale/devices.go1

118:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/tailscale/devices.go:118:1

117
118var (
119 DeviceAllFields = &DeviceFieldsOpts{}

cmd/k8s-operator/proxygroup_test.go1

1649:15unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/k8s-operator/proxygroup_test.go:1649:15

1648 }
1649 errs := err.(unwrapper)
1650 if len(errs.Unwrap()) != tc.expectedErrs {

net/netcheck/netcheck.go1

1083:7unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

net/netcheck/netcheck.go:1083:7

1082 // pool.
1083 if r, err := http.DefaultClient.Do(req); err != nil || r.StatusCode > 299 {
1084 if err != nil {

ipn/desktop/sessions_windows.go1

632:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:632:2

631 _WM_DESTROY = 2
632 _WM_CLOSE = 16
633 _WM_NCCREATE = 129

feature/taildrop/taildrop.go1

117:34unexported-returnexported function returns an unexported type

feature/taildrop/taildrop.go:117:34

116// so the Shutdown method must be called for resource cleanup.
117func (opts managerOptions) New() *manager {
118 if opts.Logf == nil {

net/art/table.go1

341:4unnecessary-formatformatting call has no formatting directive

net/art/table.go:341:4

340 if debugDelete {
341 fmt.Printf("delete: default route\n")
342 }

envknob/envknob.go1

292:2unreachable-codestatement is unreachable after unconditional control flow

envknob/envknob.go:292:2

291 log.Fatalf("invalid boolean environment variable %s value %q", envVar, val)
292 panic("unreachable")
293}

clientupdate/clientupdate_not_downloads.go1

8:47unused-parameterparameter fileDst is unused

clientupdate/clientupdate_not_downloads.go:8:47

7
8func (up *Updater) downloadURLToFile(pathSrc, fileDst string) (ret error) {
9 panic("unreachable")

cmd/containerboot/serve_test.go1

209:7unused-receiverreceiver m is unused

cmd/containerboot/serve_test.go:209:7

208
209func (m *fakeLocalClient) CertPair(ctx context.Context, domain string) (certPEM, keyPEM []byte, err error) {
210 return nil, nil, nil

tempfork/gliderlabs/ssh/session_test.go1

356:24use-anyuse any instead of interface{}

tempfork/gliderlabs/ssh/session_test.go:356:24

355 // doneChan lets us specify that we should exit.
356 doneChan := make(chan interface{})
357

client/web/qnap.go1

124:19use-errors-newreplace fmt.Errorf with errors.New for a static message

client/web/qnap.go:124:19

123 if authResp.AuthPassed == 0 {
124 return "", nil, fmt.Errorf("not authenticated")
125 }

util/winutil/testdata/testrestartableprocesses/main.go1

36:3use-fmt-printuse fmt.Print or fmt.Println instead of the builtin

util/winutil/testdata/testrestartableprocesses/main.go:36:3

35 if f == nil {
36 println("unknown function: " + os.Args[1])
37 return

feature/taildrop/retrieve.go1

94:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

feature/taildrop/retrieve.go:94:2

93 }
94 sort.Slice(ret, func(i, j int) bool { return ret[i].Name < ret[j].Name })
95 return ret, nil

control/controlbase/noiseexplorer_test.go1

143:9var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:143:9

142
143func dh(private_key [32]byte, public_key [32]byte) [32]byte {
144 var ss [32]byte

appc/appconnector_test.go1

326:54add-constantstring literal "192.0.0.8/32" appears more than twice; define a constant

appc/appconnector_test.go:326:54

325 if err := eventbustest.ExpectExactly(w,
326 eqUpdate(appctype.RouteUpdate{Advertise: prefixes("192.0.0.8/32")}), // from initial DNS response, via example.com
327 eventbustest.Type[appctype.RouteInfo](),

feature/condregister/maybe_capture.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_capture.go:8:8

7
8import _ "tailscale.com/feature/capture"
9

derp/derpserver/derpserver.go1

868:5boolean-literal-comparisonomit the boolean literal from the logical expression

derp/derpserver/derpserver.go:868:5

867func (c *sclient) requestPeerGoneWriteLimited(peer key.NodePublic, contents []byte, reason derp.PeerGoneReasonType) {
868 if disco.LooksLikeDiscoWrapper(contents) != true {
869 return

appc/appconnector_test.go1

652:6cognitive-complexityfunction has cognitive complexity 14; maximum is 7

appc/appconnector_test.go:652:6

651
652func TestUpdateWildcardRouteRemoval(t *testing.T) {
653 ctx := t.Context()

derp/derphttp/derphttp_client.go1

331:18confusing-namingname connect differs from Connect only by capitalization

derp/derphttp/derphttp_client.go:331:18

330
331func (c *Client) connect(ctx context.Context, caller string) (client *derp.Client, connGen int, err error) {
332 c.mu.Lock()

control/controlbase/noiseexplorer_test.go1

197:50confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/noiseexplorer_test.go:197:50

196
197func getHkdf(ck [32]byte, ikm []byte) ([32]byte, [32]byte, [32]byte) {
198 var k1 [32]byte

tempfork/sshtest/ssh/keys.go1

370:6constructor-interface-returnNewSignerWithAlgorithms returns interface MultiAlgorithmSigner although its concrete result is consistently *multiAlgorithmSigner; return the concrete type

tempfork/sshtest/ssh/keys.go:370:6

369// the specified algorithms are incompatible with the public key type.
370func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
371 if len(algorithms) == 0 {

tsconsensus/tsconsensus_test.go1

153:34context-as-argumentcontext.Context should be the first parameter

tsconsensus/tsconsensus_test.go:153:34

152
153func startNode(t testing.TB, ctx context.Context, controlURL, hostname string) (*tsnet.Server, key.NodePublic, netip.Addr) {
154 t.Helper()

wgengine/magicsock/relaymanager.go1

1049:18context-cancel-in-loopcontext.WithCancel is created in a loop but its cancellation function is not called during the iteration

wgengine/magicsock/relaymanager.go:1049:18

1048 }
1049 ctx, cancel := context.WithCancel(context.Background())
1050 started := &relayEndpointAllocWork{

feature/taildrop/delete.go1

36:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

feature/taildrop/delete.go:36:2

35 group sync.WaitGroup
36 shutdownCtx context.Context
37 shutdown context.CancelFunc

client/web/web.go1

631:18cyclomatic-complexityfunction complexity is 23; maximum is 10

client/web/web.go:631:18

630// which protects the handler using gorilla csrf.
631func (s *Server) serveAPI(w http.ResponseWriter, r *http.Request) {
632 if r.Method == httpm.PATCH {

cmd/connector-gen/aws.go1

44:3deep-exitprocess-exit calls should be confined to main or init

cmd/connector-gen/aws.go:44:3

43 if err := json.NewDecoder(r.Body).Decode(&aws); err != nil {
44 log.Fatal(err)
45 }

cmd/k8s-operator/sts.go1

33:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/k8s-operator/sts.go:33:2

32
33 "tailscale.com/client/tailscale"
34 "tailscale.com/ipn"

appc/appconnector_test.go1

473:3discarded-error-resulterror result returned by b.AAAAResource is discarded

appc/appconnector_test.go:473:3

472 case 128:
473 b.AAAAResource(
474 dnsmessage.ResourceHeader{

cmd/k8s-operator/ingress-for-pg.go1

48:2doc-comment-perioddocumentation comment should end with punctuation

cmd/k8s-operator/ingress-for-pg.go:48:2

47 TailscaleSvcOwnerRef = "tailscale.com/k8s-operator:owned-by:%s"
48 // FinalizerNamePG is the finalizer used by the IngressPGReconciler
49 FinalizerNamePG = "tailscale.com/ingress-pg-finalizer"

cmd/k8s-operator/sts.go1

283:5early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/sts.go:283:5

282 errResp := &tailscale.ErrResponse{}
283 if ok := errors.As(err, errResp); ok && errResp.Status == http.StatusNotFound {
284 logger.Debugf("device %s not found, likely because it has already been deleted from control", string(dev.id))

tempfork/sshtest/ssh/common.go1

335:27empty-conditional-blockempty block should be removed or documented

tempfork/sshtest/ssh/common.go:335:27

334
335 if c.RekeyThreshold == 0 {
336 // cipher specific default

derp/derphttp/derphttp_test.go1

118:5enforce-switch-styledefault clause should be the last switch clause

derp/derphttp/derphttp_test.go:118:5

117 switch m := m.(type) {
118 default:
119 t.Errorf("unexpected message type %T", m)

appc/appconnector_test.go1

315:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:315:13

314 if err := a.ObserveDNSResponse(dnsResponse("example.com.", "192.0.2.1")); err != nil {
315 t.Errorf("ObserveDNSResponse: %v", err)
316 }

net/udprelay/server.go1

708:6error-type-namingerror implementation type should have an Error suffix

net/udprelay/server.go:708:6

707// requested after waiting for at least RetryAfter duration.
708type ErrServerNotReady struct {
709 RetryAfter time.Duration

tempfork/sshtest/ssh/certs_test.go1

104:2excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

tempfork/sshtest/ssh/certs_test.go:104:2

103func TestValidateCert(t *testing.T) {
104 key, _, _, _, err := ParseAuthorizedKey(testdata.SSHCertificates["rsa-user-testcertificate"])
105 if err != nil {

appc/appctest/appctest.go1

33:27exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appctest/appctest.go:33:27

32
33func (rc *RouteCollector) UnadvertiseRoute(toRemove ...netip.Prefix) error {
34 routes := rc.routes

clientupdate/distsign/distsign_test.go1

1:1file-length-limitfile has 586 lines; maximum is 500

clientupdate/distsign/distsign_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/sts.go1

959:46flag-parameterboolean parameter metrics controls function flow

cmd/k8s-operator/sts.go:959:46

958
959func enableEndpoints(ss *appsv1.StatefulSet, metrics, debug bool) {
960 for i, c := range ss.Spec.Template.Spec.Containers {

atomicfile/mksyscall.go1

1:1formatfile is not formatted

atomicfile/mksyscall.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt atomicfile/mksyscall.go`

client/web/web_test.go1

92:6function-lengthfunction has 17 statements and 167 lines; maximum is 50 statements or 75 lines

client/web/web_test.go:92:6

91// 2. permissioning of api endpoints based on node capabilities
92func TestServeAPI(t *testing.T) {
93 selfTags := views.SliceOf([]string{"tag:server"})

drive/driveimpl/dirfs/dirfs_test.go1

279:6function-result-limitfunction returns 4 values; maximum is 3

drive/driveimpl/dirfs/dirfs_test.go:279:6

278
279func createFileSystem(t *testing.T) (webdav.FileSystem, string, string, *tstest.Clock) {
280 s1, dir1 := startRemote(t)

cmd/stunstamp/stunstamp_default.go1

31:2identical-switch-branchesswitch repeats a case body

cmd/stunstamp/stunstamp_default.go:31:2

30 }
31 case protocolHTTPS:
32 return protocolSupportInfo{

client/web/web.go1

1201:23import-shadowingidentifier url shadows an imported package

client/web/web.go:1201:23

1200 // provided auth URL from an IPN notify.
1201 printAuthURL := func(url string) bool {
1202 return url != origAuthURL

pkgdoc_test.go1

53:4inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

pkgdoc_test.go:53:4

52 if _, ok := byDir[dir]; !ok {
53 byDir[dir] = nil
54 }

release/dist/synology/pkgs.go1

177:19inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.FormatInt with base 10

release/dist/synology/pkgs.go:177:19

176 }
177 f("extractsize", fmt.Sprintf("%v", uncompressedSz>>10)) // in KiB
178 return ret.Bytes()

client/systray/systray.go1

313:20insecure-url-schemeURL uses insecure http scheme

client/systray/systray.go:313:20

312 onClick(ctx, menu.more, func(_ context.Context) {
313 webbrowser.Open("http://100.100.100.100/")
314 })

tka/disabled_stub.go1

131:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tka/disabled_stub.go:131:7

130
131func (h *AUMHash) UnmarshalText(text []byte) error {
132 return errNoTailnetLock

cmd/containerboot/main.go1

537:7max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/containerboot/main.go:537:7

536 for _, n := range n.NetMap.Peers {
537 if strings.EqualFold(n.Name(), cfg.TailnetTargetFQDN) {
538 node = n

client/tailscale/apitype/apitype.go1

91:6max-public-structsfile declares more than 5 exported structs

client/tailscale/apitype/apitype.go:91:6

90// DNSQueryResponse is the response to a DNS query request sent via LocalAPI.
91type DNSQueryResponse struct {
92 // Bytes is the raw DNS response bytes.

client/web/web.go1

1148:3modifies-parameterassignment modifies parameter data

client/web/web.go:1148:3

1147 data.AdvertiseExitNode = currAdvertisingExitNode
1148 data.UseExitNode = prefs.ExitNodeID
1149 }

net/dns/manager_linux_test.go1

336:3modifies-value-receiverassignment modifies value receiver m

net/dns/manager_linux_test.go:336:3

335 if s, ok := v.(string); ok {
336 m[name] = s[:0]
337 }

client/local/tailnetlock.go1

150:8nested-structsmove nested anonymous struct types to named declarations

client/local/tailnetlock.go:150:8

149func (lc *Client) NetworkLockVerifySigningDeeplink(ctx context.Context, url string) (*tka.DeeplinkValidationResult, error) {
150 vr := struct {
151 URL string

cmd/k8s-operator/egress-pod-readiness.go1

246:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/egress-pod-readiness.go:246:3

245 // error types are possible, but checking for those would likely make the system too fragile.
246 return unreachable, nil
247 }

cmd/tailscale/cli/serve_legacy_test.go1

929:2nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

cmd/tailscale/cli/serve_legacy_test.go:929:2

928func (lc *fakeLocalServeClient) WatchIPNBus(ctx context.Context, mask ipn.NotifyWatchOpt) (*local.IPNBusWatcher, error) {
929 return nil, nil // unused in tests
930}

feature/taildrop/ext.go1

299:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

feature/taildrop/ext.go:299:3

298 handle := e.addFileWaiter(gotFileCancel)
299 defer e.removeFileWaiter(handle)
300

clientupdate/clientupdate.go1

47:4no-else-after-returnremove else and unindent its body after the return

clientupdate/clientupdate.go:47:4

46 return UnstableTrack
47 } else {
48 return StableTrack

cmd/tailscale/cli/configure-jetkvm.go1

21:6no-initreplace init with explicit initialization

cmd/tailscale/cli/configure-jetkvm.go:21:6

20
21func init() {
22 maybeJetKVMConfigureCmd = jetKVMConfigureCmd

cmd/stunstamp/stunstamp.go1

557:5no-naked-returnreturn values must be explicit

cmd/stunstamp/stunstamp.go:557:5

556 if err != nil {
557 return
558 }

client/systray/logo.go1

45:2no-package-varpackage variables introduce mutable global state

client/systray/logo.go:45:2

44 // connected is the normal Tailscale logo
45 connected = tsLogo{dots: [9]byte{
46 0, 0, 0,

safesocket/unixsocket.go1

77:2overwritten-before-usethis value of plist is overwritten before use

safesocket/unixsocket.go:77:2

76 }
77 plist, err := exec.Command("launchctl", "list", "com.tailscale.tailscaled").Output()
78 _ = plist // parse it? https://github.com/DHowett/go-plist if we need something.

client/local/syspolicy.go1

6:9package-commentspackage should have a documentation comment

client/local/syspolicy.go:6:9

5
6package local
7

version-embed.go1

5:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

version-embed.go:5:9

4// Package tailscaleroot embeds VERSION.txt into the binary.
5package tailscaleroot
6

cmd/containerboot/egressservices.go1

256:41range-value-addresstaking the address of range value cfg can be misleading

cmd/containerboot/egressservices.go:256:41

255 // Update the status. Status will be written back to the state Secret by the caller.
256 mak.Set(&newStatus.Services, svcName, &egressservices.ServiceStatus{TailnetTargetIPs: tailnetTargetIPs, TailnetTarget: cfg.TailnetTarget, Ports: cfg.Ports})
257 }

cmd/k8s-operator/sts.go1

513:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:513:7

512// returned capver is -1. Either of device ID, hostname and IPs can be empty string if not found in the Secret.
513func (a *tailscaleSTSReconciler) DeviceInfo(ctx context.Context, childLabels map[string]string, logger *zap.SugaredLogger) ([]*device, error) {
514 var secrets corev1.SecretList

cmd/sync-containers/main.go1

38:2redefines-builtin-ididentifier max shadows a predeclared identifier

cmd/sync-containers/main.go:38:2

37 dst = flag.String("dst", "", "Destination image")
38 max = flag.Int("max", 0, "Maximum number of tags to sync (0 for all tags)")
39 dryRun = flag.Bool("dry-run", true, "Don't actually sync anything")

client/web/web_test.go1

839:72redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:839:72

838 user := &tailcfg.UserProfile{LoginName: "user@example.com", ID: tailcfg.UserID(1)}
839 otherUser := &tailcfg.UserProfile{LoginName: "user2@example.com", ID: tailcfg.UserID(2)}
840 self := &ipnstate.PeerStatus{

util/set/smallset.go1

139:2redundant-final-returnomit the unnecessary return at the end of a resultless function

util/set/smallset.go:139:2

138 }
139 return
140}

license_test.go1

62:3single-case-switchswitch with one case can be replaced by an if statement

license_test.go:62:3

61 }
62 switch base {
63 case "zsyscall_windows.go":

cmd/k8s-operator/operator.go1

904:3slice-preallocationpreallocate reqs with capacity len(range source) before appending once per iteration

cmd/k8s-operator/operator.go:904:3

903
904 reqs := make([]reconcile.Request, 0)
905 seenSvcs := make(set.Set[string])

client/tailscale/acl.go2

131:46standard-http-method-constantreplace the HTTP method literal with http.MethodGet

client/tailscale/acl.go:131:46

130 path := c.BuildTailnetURL("acl", url.Values{"details": {"1"}})
131 req, err := http.NewRequestWithContext(ctx, "GET", path, nil)
132 if err != nil {
352:2task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/acl.go:352:2

351 // If status code was not successful, return the error.
352 // TODO: Change the check for the StatusCode to include other 2XX success codes.
353 if resp.StatusCode != http.StatusOK {

client/tailscale/routes.go1

55:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/tailscale/routes.go:55:1

54
55type postRoutesParams struct {
56 Routes []netip.Prefix `json:"routes"`

cmd/natc/ippool/consensusippool.go1

188:24unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/natc/ippool/consensusippool.go:188:24

187func (ipp *ConsensusIPPool) StopConsensus(ctx context.Context) error {
188 return (ipp.consensus).(*tsconsensus.Consensus).Stop(ctx)
189}

net/netcheck/netcheck.go1

1092:7unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

net/netcheck/netcheck.go:1092:7

1091 t0 := c.timeNow()
1092 if r, err := http.DefaultClient.Do(req); err != nil || r.StatusCode > 299 {
1093 if err != nil {

ipn/desktop/sessions_windows.go1

633:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:633:2

632 _WM_CLOSE = 16
633 _WM_NCCREATE = 129
634 _WM_QUIT = 18

ipn/ipnlocal/extension_host_test.go1

1317:59unexported-returnexported function returns an unexported type

ipn/ipnlocal/extension_host_test.go:1317:59

1316// It fails the test if the host is already initialized.
1317func (h *ExtensionHost) SetWorkQueueForTest(t *testing.T) *testExecQueue {
1318 t.Helper()

safesocket/basic_test.go1

25:10unnecessary-formatformatting call has no formatting directive

safesocket/basic_test.go:25:10

24 } else {
25 sock = fmt.Sprintf(`\\.\pipe\tailscale-test`)
26 t.Cleanup(downgradeSDDL())

envknob/envknob.go1

309:2unreachable-codestatement is unreachable after unconditional control flow

envknob/envknob.go:309:2

308 log.Fatalf("invalid boolean environment variable %s value %q", envVar, val)
309 panic("unreachable")
310}

cmd/containerboot/serve_test.go1

204:42unused-parameterparameter ctx is unused

cmd/containerboot/serve_test.go:204:42

203
204func (m *fakeLocalClient) SetServeConfig(ctx context.Context, cfg *ipn.ServeConfig) error {
205 m.setServeCalled = true

cmd/derper/bootstrap_dns_test.go1

38:7unused-receiverreceiver b is unused

cmd/derper/bootstrap_dns_test.go:38:7

37
38func (b *bitbucketResponseWriter) Header() http.Header { return make(http.Header) }
39

tempfork/gliderlabs/ssh/session_test.go1

410:24use-anyuse any instead of interface{}

tempfork/gliderlabs/ssh/session_test.go:410:24

409 // doneChan lets us specify that we should exit.
410 doneChan := make(chan interface{})
411

client/web/web.go1

180:15use-errors-newreplace fmt.Errorf with errors.New for a static message

client/web/web.go:180:15

179 case "":
180 return nil, fmt.Errorf("must specify a Mode")
181 default:

feature/taildrop/taildrop.go1

205:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

feature/taildrop/taildrop.go:205:2

204
205 sort.Slice(files, func(i, j int) bool {
206 return files[i].Started.Before(files[j].Started)

control/controlbase/noiseexplorer_test.go1

143:31var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:143:31

142
143func dh(private_key [32]byte, public_key [32]byte) [32]byte {
144 var ss [32]byte

appc/appconnector_test.go1

375:28add-constantstring literal "*.example.com" appears more than twice; define a constant

appc/appconnector_test.go:375:28

374
375 a.updateDomains([]string{"*.example.com", "example.com"})
376 if _, ok := a.domains["foo.example.com"]; !ok {

feature/condregister/maybe_clientupdate.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_clientupdate.go:8:8

7
8import _ "tailscale.com/feature/clientupdate"
9

ipn/serve_test.go1

285:7boolean-literal-comparisonomit the boolean literal from the logical expression

ipn/serve_test.go:285:7

284
285 if tt.wantErr == true && err == nil {
286 t.Errorf("Expected an error but got none")

appc/appconnector_test.go1

748:6cognitive-complexityfunction has cognitive complexity 8; maximum is 7

appc/appconnector_test.go:748:6

747
748func TestRateLogger(t *testing.T) {
749 clock := tstest.Clock{}

derp/derpserver/derpserver.go1

911:18confusing-namingname accept differs from Accept only by capitalization

derp/derpserver/derpserver.go:911:18

910
911func (s *Server) accept(ctx context.Context, nc derp.Conn, brw *bufio.ReadWriter, remoteAddr string, connNum int64) error {
912 br := brw.Reader

control/controlbase/noiseexplorer_test.go1

197:60confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/noiseexplorer_test.go:197:60

196
197func getHkdf(ck [32]byte, ikm []byte) ([32]byte, [32]byte, [32]byte) {
198 var k1 [32]byte

tempfork/sshtest/ssh/keys.go1

1074:6constructor-interface-returnNewSignerFromSigner returns interface Signer although its concrete result is consistently *wrappedSigner; return the concrete type

tempfork/sshtest/ssh/keys.go:1074:6

1073// example, with keys kept in hardware modules.
1074func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
1075 pubKey, err := NewPublicKey(signer.Public())

tsconsensus/tsconsensus_test.go1

174:55context-as-argumentcontext.Context should be the first parameter

tsconsensus/tsconsensus_test.go:174:55

173
174func waitForNodesToBeTaggedInStatus(t testing.TB, ctx context.Context, ts *tsnet.Server, nodeKeys []key.NodePublic, tag string) {
175 t.Helper()

ipn/auditlog/auditlog.go1

98:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

ipn/auditlog/auditlog.go:98:2

97 done chan struct{} // closed when the flush worker exits.
98 ctx context.Context // canceled when the logger is stopped.
99 ctxCancel context.CancelFunc // cancels ctx.

client/web/web.go1

725:18cyclomatic-complexityfunction complexity is 25; maximum is 10

client/web/web.go:725:18

724// and returns an authResponse indicating the current auth state and any steps the user needs to take.
725func (s *Server) serveAPIAuth(w http.ResponseWriter, r *http.Request) {
726 var resp authResponse

cmd/connector-gen/aws.go1

58:3deep-exitprocess-exit calls should be confined to main or init

cmd/connector-gen/aws.go:58:3

57 if err != nil {
58 log.Fatal(err)
59 }

cmd/k8s-operator/tsrecorder.go1

32:2deprecated-api-usagetailscale.com/client/tailscale is deprecated: the official control plane client is available at [tailscale.com/client/tailscale/v2].

cmd/k8s-operator/tsrecorder.go:32:2

31 "sigs.k8s.io/controller-runtime/pkg/reconcile"
32 "tailscale.com/client/tailscale"
33 tsoperator "tailscale.com/k8s-operator"

atomicfile/atomicfile.go1

33:4discarded-error-resulterror result returned by f.Close is discarded

atomicfile/atomicfile.go:33:4

32 if err != nil {
33 f.Close()
34 os.Remove(tmpName)

cmd/k8s-operator/metrics_resources.go1

39:1doc-comment-perioddocumentation comment should end with punctuation

cmd/k8s-operator/metrics_resources.go:39:1

38// Duplicating it here allows us to avoid importing prometheus-operator library.
39// https://github.com/prometheus-operator/prometheus-operator/blob/bb4514e0d5d69f20270e29cfd4ad39b87865ccdf/pkg/apis/monitoring/v1/servicemonitor_types.go#L40
40type ServiceMonitor struct {

cmd/k8s-operator/svc-for-pg.go1

118:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/svc-for-pg.go:118:3

117 if err != nil {
118 if strings.Contains(err.Error(), optimisticLockErrorMsg) {
119 logger.Infof("optimistic lock error, retrying: %s", err)

tempfork/sshtest/ssh/messages.go1

693:26empty-conditional-blockempty block should be removed or documented

tempfork/sshtest/ssh/messages.go:693:26

692 length += (bitLen + 7) / 8
693 } else if n.Sign() == 0 {
694 // A zero is the zero length string

feature/tap/tap_linux.go1

119:2enforce-switch-styledefault clause should be the last switch clause

feature/tap/tap_linux.go:119:2

118 switch et {
119 default:
120 if tapDebug {

appc/appconnector_test.go1

365:13error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:365:13

364 if err := a.ObserveDNSResponse(dnsResponse("foo.example.com.", "192.0.0.8")); err != nil {
365 t.Errorf("ObserveDNSResponse: %v", err)
366 }

tempfork/sshtest/ssh/messages.go1

40:6error-type-namingerror implementation type should have an Error suffix

tempfork/sshtest/ssh/messages.go:40:6

39// the error type returned from mux.Wait()
40type disconnectMsg struct {
41 Reason uint32 `sshtype:"1"`

tempfork/sshtest/ssh/certs_test.go1

238:4excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

tempfork/sshtest/ssh/certs_test.go:238:4

237 }
238 _, _, _, err := NewServerConn(c1, &conf)
239 errc <- err

appc/appctest/appctest.go1

56:27exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appctest/appctest.go:56:27

55// possible duplicates.
56func (rc *RouteCollector) Routes() []netip.Prefix {
57 return rc.routes

cmd/containerboot/egressservices.go1

1:1file-length-limitfile has 766 lines; maximum is 500

cmd/containerboot/egressservices.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/sts.go1

959:55flag-parameterboolean parameter debug controls function flow

cmd/k8s-operator/sts.go:959:55

958
959func enableEndpoints(ss *appsv1.StatefulSet, metrics, debug bool) {
960 for i, c := range ss.Spec.Template.Spec.Containers {

chirp/chirp.go1

1:1formatfile is not formatted

chirp/chirp.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt chirp/chirp.go`

client/web/web_test.go1

260:6function-lengthfunction has 23 statements and 176 lines; maximum is 50 statements or 75 lines

client/web/web_test.go:260:6

259
260func TestGetTailscaleBrowserSession(t *testing.T) {
261 userA := &tailcfg.UserProfile{ID: tailcfg.UserID(1)}

k8s-operator/sessionrecording/ws/message.go1

206:6function-result-limitfunction returns 4 values; maximum is 3

k8s-operator/sessionrecording/ws/message.go:206:6

205// fragmentDimensions returns payload length as well as payload offset and mask offset.
206func fragmentDimensions(b []byte, maskSet bool) (payloadLength, payloadOffset, maskOffset uint64, _ error) {
207

cmd/tailscale/cli/cli_test.go1

942:3identical-switch-branchesswitch repeats a case body

cmd/tailscale/cli/cli_test.go:942:3

941 continue
942 case "WantRunning", "Persist", "LoggedOut":
943 // All explicitly handled (ignored) by checkForAccidentalSettingReverts.

client/web/web.go1

1250:6import-shadowingidentifier url shadows an imported package

client/web/web.go:1250:6

1249 }
1250 if url := n.BrowseToURL; url != nil && printAuthURL(*url) {
1251 return *url, nil

ssh/tailssh/incubator.go1

1022:5inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

ssh/tailssh/incubator.go:1022:5

1021 if _, ok := tios.CC[k]; ok {
1022 tios.CC[k] = uint8(v)
1023 continue

tempfork/acme/acme_test.go1

630:12inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

tempfork/acme/acme_test.go:630:12

629 for i := 0; i < maxNonces; i++ {
630 c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
631 }

client/tailscale/tailscale_test.go1

12:23insecure-url-schemeURL uses insecure http scheme

client/tailscale/tailscale_test.go:12:23

11func TestClientBuildURL(t *testing.T) {
12 c := Client{BaseURL: "http://127.0.0.1:1234"}
13 for _, tt := range []struct {

tstime/mono/mono.go1

115:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tstime/mono/mono.go:115:7

114// across different invocations of the Go process. This is best-effort only.
115func (t *Time) UnmarshalJSON(data []byte) error {
116 var tt time.Time

cmd/containerboot/main.go1

556:7max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/containerboot/main.go:556:7

555 var rulesInstalled bool
556 for _, egressAddr := range egressAddrs {
557 ea := egressAddr.Addr()

cmd/viewer/tests/tests.go1

72:6max-public-structsfile declares more than 5 exported structs

cmd/viewer/tests/tests.go:72:6

71
72type OnlyGetClone struct {
73 SinViewerPorFavor bool

client/web/web.go1

1361:3modifies-parameterassignment modifies parameter prefix

client/web/web.go:1361:3

1360 if !strings.HasPrefix(prefix, "/") {
1361 prefix = "/" + prefix
1362 }

net/dns/manager_linux_test.go1

343:2modifies-value-receiverassignment modifies value receiver m

net/dns/manager_linux_test.go:343:2

342func (m memFS) WriteFile(name string, contents []byte, perm os.FileMode) error {
343 m[name] = string(contents)
344 return nil

client/local/tailnetlock.go1

164:8nested-structsmove nested anonymous struct types to named declarations

client/local/tailnetlock.go:164:8

163func (lc *Client) NetworkLockGenRecoveryAUM(ctx context.Context, removeKeys []tkatype.KeyID, forkFrom tka.AUMHash) ([]byte, error) {
164 vr := struct {
165 Keys []tkatype.KeyID

cmd/k8s-operator/ingress-for-pg.go1

168:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/ingress-for-pg.go:168:3

167 logger.Infof("error validating tailscale IngressClass: %v.", err)
168 return false, nil
169 }

control/controlhttp/http_test.go1

275:4nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

control/controlhttp/http_test.go:275:4

274 a.proxyFunc = func(*http.Request) (*url.URL, error) {
275 return nil, nil
276 }

feature/taildrop/resume_test.go1

56:4no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

feature/taildrop/resume_test.go:56:4

55 must.Do(err)
56 defer close()
57 offset, r, err := resumeReader(r, next)

clientupdate/clientupdate.go1

453:4no-else-after-returnremove else and unindent its body after the return

clientupdate/clientupdate.go:453:4

452 return err
453 } else if updated {
454 up.Logf("Updated %s to use the %s track", aptSourcesFile, up.Track)

cmd/tailscale/cli/configure-synology-cert.go1

27:6no-initreplace init with explicit initialization

cmd/tailscale/cli/configure-synology-cert.go:27:6

26
27func init() {
28 maybeConfigSynologyCertCmd = synologyConfigureCertCmd

cmd/stunstamp/stunstamp.go1

568:4no-naked-returnreturn values must be explicit

cmd/stunstamp/stunstamp.go:568:4

567 if err != nil {
568 return
569 }

client/systray/logo.go1

53:2no-package-varpackage variables introduce mutable global state

client/systray/logo.go:53:2

52 // but indicates that the loading animation should be shown.
53 loading = tsLogo{dots: [9]byte{'l', 'o', 'a', 'd', 'i', 'n', 'g'}}
54

tempfork/sshtest/ssh/ssh_gss.go1

118:3overwritten-before-usethis value of rest is overwritten before use

tempfork/sshtest/ssh/ssh_gss.go:118:3

117 )
118 desiredMech, rest, ok = parseString(rest)
119 if !ok {

client/local/tailnetlock.go1

6:9package-commentspackage should have a documentation comment

client/local/tailnetlock.go:6:9

5
6package local
7

version_tailscale_test.go1

6:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

version_tailscale_test.go:6:9

5
6package tailscaleroot
7

cmd/containerboot/kube_test.go1

301:10range-value-addresstaking the address of range value name can be misleading

cmd/containerboot/kube_test.go:301:10

300 var actual map[string][]byte
301 kc := &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
302 GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {

cmd/k8s-operator/sts.go1

620:7receiver-namingreceiver name a is inconsistent with sts

cmd/k8s-operator/sts.go:620:7

619
620func (a *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.SugaredLogger, sts *tailscaleSTSConfig, headlessSvc *corev1.Service, proxySecrets []string) (*appsv1.StatefulSet, error) {
621 ss := new(appsv1.StatefulSet)

cmd/tailscale/cli/file.go1

204:2redefines-builtin-ididentifier print shadows a predeclared identifier

cmd/tailscale/cli/file.go:204:2

203 var prevContentCount int64
204 print := func() {
205 currContentCount := contentCount()

client/web/web_test.go1

1212:73redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:1212:73

1211func TestPeerCapabilities(t *testing.T) {
1212 userOwnedStatus := &ipnstate.Status{Self: &ipnstate.PeerStatus{UserID: tailcfg.UserID(1)}}
1213 tags := views.SliceOf[string]([]string{"tag:server"})

wgengine/magicsock/magicsock.go1

2452:2redundant-final-returnomit the unnecessary return at the end of a resultless function

wgengine/magicsock/magicsock.go:2452:2

2451 }
2452 return
2453}

net/dns/resolver/tsdns_test.go1

208:4single-case-switchswitch with one case can be replaced by an if statement

net/dns/resolver/tsdns_test.go:208:4

207 }
208 switch ah.Name.String() {
209 case "query-info.test.":

cmd/k8s-operator/operator.go1

945:3slice-preallocationpreallocate reqs with capacity len(range source) before appending once per iteration

cmd/k8s-operator/operator.go:945:3

944
945 reqs := make([]reconcile.Request, 0)
946 seenIngs := make(set.Set[string])

client/tailscale/acl.go1

189:46standard-http-method-constantreplace the HTTP method literal with http.MethodPost

client/tailscale/acl.go:189:46

188 path := c.BuildTailnetURL("acl")
189 req, err := http.NewRequestWithContext(ctx, "POST", path, bytes.NewBuffer(body))
190 if err != nil {

client/tailscale/devices.go1

101:1task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/devices.go:101:1

100//
101// TODO: Support other DeviceFieldsOpts.
102// In the future, users should be able to create their own DeviceFieldsOpts

client/tailscale/tailscale.go1

30:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/tailscale/tailscale.go:30:1

29
30const defaultAPIBase = "https://api.tailscale.com"
31

cmd/natc/ippool/consensusippool_test.go1

38:15unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/natc/ippool/consensusippool_test.go:38:15

37 result := c.ipp.Apply(&raft.Log{Data: b})
38 return result.(tsconsensus.CommandResult), nil
39}

net/proxymux/mux_test.go1

85:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

net/proxymux/mux_test.go:85:2

84 s.t.Helper()
85 resp, err := c.Get(s.targetURL)
86 if wantErr {

ipn/desktop/sessions_windows.go1

634:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:634:2

633 _WM_NCCREATE = 129
634 _WM_QUIT = 18
635 _WM_NCDESTROY = 130

net/dns/noop.go1

15:24unexported-returnexported function returns an unexported type

net/dns/noop.go:15:24

14
15func NewNoopManager() (noopManager, error) {
16 return noopManager{}, nil

ssh/tailssh/tailssh.go1

744:4unnecessary-formatformatting call has no formatting directive

ssh/tailssh/tailssh.go:744:4

743 s.cancelCtx(userVisibleError{
744 fmt.Sprintf("Access revoked.\r\n"),
745 context.Canceled,

envknob/envknob.go1

340:2unreachable-codestatement is unreachable after unconditional control flow

envknob/envknob.go:340:2

339 log.Fatalf("invalid integer environment variable %s: %v", envVar, val)
340 panic("unreachable")
341}

cmd/containerboot/serve_test.go1

204:63unused-parameterparameter cfg is unused

cmd/containerboot/serve_test.go:204:63

203
204func (m *fakeLocalClient) SetServeConfig(ctx context.Context, cfg *ipn.ServeConfig) error {
205 m.setServeCalled = true

cmd/derper/bootstrap_dns_test.go1

40:7unused-receiverreceiver b is unused

cmd/derper/bootstrap_dns_test.go:40:7

39
40func (b *bitbucketResponseWriter) Write(p []byte) (int, error) { return len(p), nil }
41

tempfork/sshtest/ssh/channel.go1

174:11use-anyuse any instead of interface{}

tempfork/sshtest/ssh/channel.go:174:11

173 // Pending internal channel messages.
174 msg chan interface{}
175

client/web/web.go1

182:15use-errors-newreplace fmt.Errorf with errors.New for a static message

client/web/web.go:182:15

181 default:
182 return nil, fmt.Errorf("invalid Mode provided")
183 }

ipn/auditlog/auditlog.go1

393:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

ipn/auditlog/auditlog.go:393:2

392 // the front of the queue.
393 sort.Slice(deduped, func(i, j int) bool {
394 return deduped[i].TimeStamp.Before(deduped[j].TimeStamp)

control/controlbase/noiseexplorer_test.go1

150:6var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:150:6

149func generateKeypair() keypair {
150 var public_key [32]byte
151 var private_key [32]byte

appc/appconnector_test.go1

548:49add-constantstring literal "1.2.3.1/32" appears more than twice; define a constant

appc/appconnector_test.go:548:49

547 // one route the same, one different
548 a.UpdateDomainsAndRoutes([]string{}, prefixes("1.2.3.1/32", "1.2.3.3/32"))
549 a.Wait(ctx)

feature/condregister/maybe_debugportmapper.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_debugportmapper.go:8:8

7
8import _ "tailscale.com/feature/debugportmapper"
9

ipn/serve_test.go1

290:7boolean-literal-comparisonomit the boolean literal from the logical expression

ipn/serve_test.go:290:7

289
290 if tt.wantErr == false && err != nil {
291 t.Errorf("Got an error, but didn't expect one: %v", err)

appc/observe.go1

20:24cognitive-complexityfunction has cognitive complexity 56; maximum is 7

appc/observe.go:20:24

19// advised to advertise the discovered route.
20func (e *AppConnector) ObserveDNSResponse(res []byte) error {
21 var p dnsmessage.Parser

doctor/doctor.go1

78:20confusing-namingname Name differs from name only by capitalization

doctor/doctor.go:78:20

77
78func (c checkFunc) Name() string { return c.name }
79func (c checkFunc) Run(ctx context.Context, log logger.Logf) error { return c.run(ctx, log) }

control/controlbase/noiseexplorer_test.go1

282:46confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/noiseexplorer_test.go:282:46

281
282func split(ss *symmetricstate) (cipherstate, cipherstate) {
283 tempK1, tempK2, _ := getHkdf(ss.ck, []byte{})

wgengine/router/router_fake.go1

12:6constructor-interface-returnNewFake returns interface Router although its concrete result is consistently fakeRouter; return the concrete type

wgengine/router/router_fake.go:12:6

11// returns nil errors.
12func NewFake(logf logger.Logf) Router {
13 return fakeRouter{logf: logf}

tsconsensus/tsconsensus_test.go1

295:55context-as-argumentcontext.Context should be the first parameter

tsconsensus/tsconsensus_test.go:295:55

294// LocalClient Status calls that show the first node as Online.
295func startNodesAndWaitForPeerStatus(t testing.TB, ctx context.Context, clusterTag string, nNodes int) ([]*participant, *testcontrol.Server, string) {
296 t.Helper()

ipn/ipnauth/actor.go1

114:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

ipn/ipnauth/actor.go:114:2

113 Actor
114 ctx context.Context
115}

client/web/web.go1

934:18cyclomatic-complexityfunction complexity is 19; maximum is 10

client/web/web.go:934:18

933
934func (s *Server) serveGetNodeData(w http.ResponseWriter, r *http.Request) {
935 st, err := s.lc.Status(r.Context())

cmd/connector-gen/github.go1

49:3deep-exitprocess-exit calls should be confined to main or init

cmd/connector-gen/github.go:49:3

48 if err != nil {
49 log.Fatal(err)
50 }

cmd/netlogfmt/main.go1

200:15deprecated-api-usagetailscale.com/types/ipproto.String is deprecated: use MarshalText instead.

cmd/netlogfmt/main.go:200:15

199 if cc.Proto > 0 {
200 row[0] += cc.Proto.String() + ":"
201 }

atomicfile/atomicfile.go1

34:4discarded-error-resulterror result returned by os.Remove is discarded

atomicfile/atomicfile.go:34:4

33 f.Close()
34 os.Remove(tmpName)
35 }

cmd/k8s-operator/metrics_resources.go1

46:1doc-comment-perioddocumentation comment should end with punctuation

cmd/k8s-operator/metrics_resources.go:46:1

45
46// https://github.com/prometheus-operator/prometheus-operator/blob/bb4514e0d5d69f20270e29cfd4ad39b87865ccdf/pkg/apis/monitoring/v1/servicemonitor_types.go#L55
47type ServiceMonitorSpec struct {

cmd/k8s-operator/svc.go1

127:3early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/svc.go:127:3

126 if err := a.maybeProvision(ctx, logger, svc); err != nil {
127 if strings.Contains(err.Error(), optimisticLockErrorMsg) {
128 logger.Infof("optimistic lock error, retrying: %s", err)

tempfork/sshtest/ssh/messages.go1

741:26empty-conditional-blockempty block should be removed or documented

tempfork/sshtest/ssh/messages.go:741:26

740 length += nBytes
741 } else if n.Sign() == 0 {
742 // A zero is the zero length string

ipn/ipnlocal/peerapi.go1

786:2enforce-switch-styledefault clause should be the last switch clause

ipn/ipnlocal/peerapi.go:786:2

785 switch r.Method {
786 default:
787 return nil, "bad HTTP method"

appc/appconnector_test.go1

615:14error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:615:14

614 if err := a.ObserveDNSResponse(res); err != nil {
615 t.Errorf("ObserveDNSResponse: %v", err)
616 }

util/syspolicy/setting/errors.go1

38:6error-type-namingerror implementation type should have an Error suffix

util/syspolicy/setting/errors.go:38:6

37// type information of the underlying error.
38type ErrorText string
39

tempfork/sshtest/ssh/certs_test.go1

247:3excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

tempfork/sshtest/ssh/certs_test.go:247:3

246 }
247 _, _, _, err = NewClientConn(c2, test.addr, config)
248

appc/appctest/appctest.go1

60:27exported-declaration-commentexported function or method should have a comment beginning with its name

appc/appctest/appctest.go:60:27

59
60func (rc *RouteCollector) SetRoutes(routes []netip.Prefix) error {
61 rc.routes = routes

cmd/containerboot/main.go1

1:1file-length-limitfile has 895 lines; maximum is 500

cmd/containerboot/main.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/svc-for-pg.go1

651:185flag-parameterboolean parameter shouldBeAdvertised controls function flow

cmd/k8s-operator/svc-for-pg.go:651:185

650
651func (a *HAServiceReconciler) maybeUpdateAdvertiseServicesConfig(ctx context.Context, svc *corev1.Service, pgName string, serviceName tailcfg.ServiceName, cfg *ingressservices.Config, shouldBeAdvertised bool, logger *zap.SugaredLogger) (err error) {
652 logger.Debugf("checking advertisement for service '%s'", serviceName)

client/local/local.go1

1:1formatfile is not formatted

client/local/local.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt client/local/local.go`

client/web/web_test.go1

439:6function-lengthfunction has 15 statements and 91 lines; maximum is 50 statements or 75 lines

client/web/web_test.go:439:6

438// 2023-10-18: These tests currently cover tailscale auth mode (not platform auth).
439func TestAuthorizeRequest(t *testing.T) {
440 // Create self and remoteNode owned by same user.

net/dnscache/dnscache.go1

194:20function-result-limitfunction returns 4 values; maximum is 3

net/dnscache/dnscache.go:194:20

193// with a nil error.
194func (r *Resolver) LookupIP(ctx context.Context, host string) (ip, v6 netip.Addr, allIPs []netip.Addr, err error) {
195 if r.SingleHostStaticResult != nil {

cmd/tailscale/cli/cli_test.go1

945:3identical-switch-branchesswitch repeats a case body

cmd/tailscale/cli/cli_test.go:945:3

944 continue
945 case "OSVersion", "DeviceModel":
946 // Only used by Android, which doesn't have a CLI mode anyway, so

client/web/web.go1

1286:2import-shadowingidentifier url shadows an imported package

client/web/web.go:1286:2

1285 s.logf("tailscaleUp(reauth=%v) ...", opt.Reauthenticate)
1286 url, err := s.tailscaleUp(r.Context(), st, opt)
1287 s.logf("tailscaleUp = (URL %v, %v)", url != "", err)

ssh/tailssh/incubator.go1

1026:5inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

ssh/tailssh/incubator.go:1026:5

1025 if _, ok := tios.Opts[k]; ok {
1026 tios.Opts[k] = v > 0
1027 continue

tsconsensus/authorization_test.go1

31:30inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

tsconsensus/authorization_test.go:31:30

30 return &ipnstate.PeerStatus{
31 ID: tailcfg.StableNodeID(fmt.Sprintf("%d", i)),
32 Tags: &tags,

client/tailscale/tailscale_test.go1

21:14insecure-url-schemeURL uses insecure http scheme

client/tailscale/tailscale_test.go:21:14

20 elements: []any{"devices"},
21 want: "http://127.0.0.1:1234/api/v2/devices",
22 },

tstime/tstime.go1

216:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

tstime/tstime.go:216:7

215
216func (d *GoDuration) UnmarshalText(b []byte) error {
217 d2, err := time.ParseDuration(string(b))

cmd/containerboot/main.go1

558:8max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/containerboot/main.go:558:8

557 ea := egressAddr.Addr()
558 if ea.Is4() || (ea.Is6() && nfr.HasIPV6NAT()) {
559 rulesInstalled = true

cmd/viewer/tests/tests.go1

76:6max-public-structsfile declares more than 5 exported structs

cmd/viewer/tests/tests.go:76:6

75
76type StructWithEmbedded struct {
77 A *StructWithPtrs

client/web/web.go1

1364:3modifies-parameterassignment modifies parameter prefix

client/web/web.go:1364:3

1363 if !strings.HasSuffix(prefix, "/") {
1364 prefix += "/"
1365 }

net/packet/icmp4.go1

75:2modifies-value-receiverassignment modifies value receiver h

net/packet/icmp4.go:75:2

74 // The caller does not need to set this.
75 h.IPProto = ipproto.ICMPv4
76

client/systray/systray.go1

101:18nested-structsmove nested anonymous struct types to named declarations

client/systray/systray.go:101:18

100
101 rebuildCh chan struct{} // triggers a menu rebuild
102 accountsCh chan ipn.ProfileID

cmd/k8s-operator/ingress-for-pg.go1

182:4nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/ingress-for-pg.go:182:4

181 logger.Infof("ProxyGroup does not exist")
182 return false, nil
183 }

control/controlhttp/http_test.go1

792:65nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

control/controlhttp/http_test.go:792:65

791 DialPlan: plan,
792 proxyFunc: func(*http.Request) (*url.URL, error) { return nil, nil },
793 omitCertErrorLogging: true,

health/health_test.go1

58:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

health/health_test.go:58:3

57 })
58 defer unregister(w)
59 if i%2 == 0 {

clientupdate/clientupdate.go1

599:5no-else-after-returnremove else and unindent its body after the return

clientupdate/clientupdate.go:599:5

598 return err
599 } else if updated {
600 up.Logf("Updated %s to use the %s track", yumRepoConfigFile, up.Track)

cmd/tailscale/cli/configure_apple.go1

15:6no-initreplace init with explicit initialization

cmd/tailscale/cli/configure_apple.go:15:6

14
15func init() {
16 maybeSysExtCmd = sysExtCmd

cmd/tailscale/cli/cli.go1

164:3no-naked-returnreturn values must be explicit

cmd/tailscale/cli/cli.go:164:3

163 })
164 return
165 }

client/systray/logo.go1

56:2no-package-varpackage variables introduce mutable global state

client/systray/logo.go:56:2

55 // loadingIcons are shown in sequence as an animated loading icon.
56 loadingLogos = []tsLogo{
57 {dots: [9]byte{

tstest/integration/vms/vms_test.go1

599:3overwritten-before-usethis value of err is overwritten before use

tstest/integration/vms/vms_test.go:599:3

598
599 msg, err := sess.Output(
600 fmt.Sprintf(

client/systray/logo.go1

6:9package-commentspackage should have a documentation comment

client/systray/logo.go:6:9

5
6package systray
7

version_test.go1

4:9package-directory-mismatchpackage tailscaleroot does not match directory tailscale

version_test.go:4:9

3
4package tailscaleroot
5

cmd/containerboot/kube_test.go1

301:10range-value-addresstaking the address of range value tc can be misleading

cmd/containerboot/kube_test.go:301:10

300 var actual map[string][]byte
301 kc := &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
302 GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {

cmd/k8s-operator/svc-for-pg.go1

584:7receiver-namingreceiver name a is inconsistent with r

cmd/k8s-operator/svc-for-pg.go:584:7

583
584func (a *HAServiceReconciler) backendRoutesSetup(ctx context.Context, serviceName, replicaName, pgName string, wantsCfg *ingressservices.Config, logger *zap.SugaredLogger) (bool, error) {
585 logger.Debugf("checking backend routes for service '%s'", serviceName)

cmd/tailscale/cli/serve_legacy.go1

736:36redefines-builtin-ididentifier max shadows a predeclared identifier

cmd/tailscale/cli/serve_legacy.go:736:36

735
736func elipticallyTruncate(s string, max int) string {
737 if len(s) <= max {

client/web/web_test.go1

1233:43redundant-conversionconversion from tailcfg.UserID to the identical type is redundant

client/web/web_test.go:1233:43

1232 whois: &apitype.WhoIsResponse{
1233 UserProfile: &tailcfg.UserProfile{ID: tailcfg.UserID(2)},
1234 Node: &tailcfg.Node{ID: tailcfg.NodeID(1)},

net/neterror/neterror.go1

28:2single-case-switchswitch with one case can be replaced by an if statement

net/neterror/neterror.go:28:2

27 }
28 switch runtime.GOOS {
29 case "linux":

cmd/k8s-operator/operator.go1

1330:2slice-preallocationpreallocate reqs with capacity len(range source) before appending once per iteration

cmd/k8s-operator/operator.go:1330:2

1329 }
1330 reqs := make([]reconcile.Request, 0)
1331 for _, ep := range epsList.Items {

client/tailscale/acl.go1

333:46standard-http-method-constantreplace the HTTP method literal with http.MethodPost

client/tailscale/acl.go:333:46

332 path := c.BuildTailnetURL("acl", "preview")
333 req, err := http.NewRequestWithContext(ctx, "POST", path, bytes.NewBuffer(body))
334 if err != nil {

client/tailscale/devices.go1

157:2task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/devices.go:157:2

156 // If status code was not successful, return the error.
157 // TODO: Change the check for the StatusCode to include other 2XX success codes.
158 if resp.StatusCode != http.StatusOK {

client/web/auth.go1

73:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/web/auth.go:73:1

72
73var (
74 errNoSession = errors.New("no-browser-session")

cmd/natc/ippool/consensusippool_test.go1

278:17unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/natc/ippool/consensusippool_test.go:278:17

277 }
278 snap := fsmSnap.(fsmSnapshot)
279

prober/prober_test.go1

733:4unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

prober/prober_test.go:733:4

732
733 resp, err := http.DefaultClient.Do(req)
734 if err != nil {

ipn/desktop/sessions_windows.go1

635:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:635:2

634 _WM_QUIT = 18
635 _WM_NCDESTROY = 130
636

net/netmon/netmon_darwin.go1

54:37unexported-returnexported function returns an unexported type

net/netmon/netmon_darwin.go:54:37

53
54func (m *darwinRouteMon) Receive() (message, error) {
55 for {

tempfork/acme/types.go1

115:10unnecessary-formatformatting call has no formatting directive

tempfork/acme/types.go:115:10

114 if len(e.Subproblems) > 0 {
115 str += fmt.Sprintf("; subproblems:")
116 for _, sp := range e.Subproblems {

envknob/envknob.go1

360:2unreachable-codestatement is unreachable after unconditional control flow

envknob/envknob.go:360:2

359 log.Fatalf("invalid integer environment variable %s: %v", envVar, val)
360 panic("unreachable")
361}

cmd/containerboot/serve_test.go1

209:36unused-parameterparameter ctx is unused

cmd/containerboot/serve_test.go:209:36

208
209func (m *fakeLocalClient) CertPair(ctx context.Context, domain string) (certPEM, keyPEM []byte, err error) {
210 return nil, nil, nil

cmd/derper/bootstrap_dns_test.go1

42:7unused-receiverreceiver b is unused

cmd/derper/bootstrap_dns_test.go:42:7

41
42func (b *bitbucketResponseWriter) WriteHeader(statusCode int) {}
43

tempfork/sshtest/ssh/channel.go1

222:36use-anyuse any instead of interface{}

tempfork/sshtest/ssh/channel.go:222:36

221
222func (ch *channel) sendMessage(msg interface{}) error {
223 if debugMux {

client/web/web.go1

210:16use-errors-newreplace fmt.Errorf with errors.New for a static message

client/web/web.go:210:16

209 if opts.NewAuthURL == nil {
210 return nil, fmt.Errorf("must provide a NewAuthURL implementation")
211 }

ipn/ipnstate/ipnstate.go1

196:2use-slices-sortuse slices.Sort or slices.SortFunc when possible

ipn/ipnstate/ipnstate.go:196:2

195 }
196 sort.Slice(kk, func(i, j int) bool { return kk[i].Less(kk[j]) })
197 return kk

control/controlbase/noiseexplorer_test.go1

151:6var-namingidentifier should use MixedCaps rather than underscores

control/controlbase/noiseexplorer_test.go:151:6

150 var public_key [32]byte
151 var private_key [32]byte
152 _, _ = rand.Read(private_key[:])

appc/appconnector_test.go1

553:40add-constantstring literal "1.2.3.2/32" appears more than twice; define a constant

appc/appconnector_test.go:553:40

552 // the real one does)
553 wantRoutes := prefixes("1.2.3.1/32", "1.2.3.2/32", "1.2.3.1/32", "1.2.3.3/32")
554 wantRemovedRoutes := []netip.Prefix{}

feature/condregister/maybe_doctor.go1

8:8blank-importsblank import should be justified by a comment

feature/condregister/maybe_doctor.go:8:8

7
8import _ "tailscale.com/feature/doctor"
9

net/tstun/wrap.go1

1050:5boolean-literal-comparisonomit the boolean literal from the logical expression

net/tstun/wrap.go:1050:5

1049 }
1050 if gso.NeedsCsum != true {
1051 return

atomicfile/atomicfile.go1

21:6cognitive-complexityfunction has cognitive complexity 8; maximum is 7

atomicfile/atomicfile.go:21:6

20// filename already exists but is not a regular file, WriteFile returns an error.
21func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
22 fi, err := os.Stat(filename)

doctor/doctor.go1

79:20confusing-namingname Run differs from run only by capitalization

doctor/doctor.go:79:20

78func (c checkFunc) Name() string { return c.name }
79func (c checkFunc) Run(ctx context.Context, log logger.Logf) error { return c.run(ctx, log) }
80

control/controlbase/noiseexplorer_test.go1

329:95confusing-resultsadjacent unnamed results of the same type should be named

control/controlbase/noiseexplorer_test.go:329:95

328
329func writeMessageB(hs *handshakestate, payload []byte) ([32]byte, messagebuffer, cipherstate, cipherstate) {
330 ne, ns, ciphertext := emptyKey, []byte{}, []byte{}

wgengine/userspace.go1

284:6constructor-interface-returnNewUserspaceEngine returns interface Engine although its concrete result is consistently *userspaceEngine; return the concrete type

wgengine/userspace.go:284:6

283// Tailscale Engine running on it.
284func NewUserspaceEngine(logf logger.Logf, conf Config) (_ Engine, reterr error) {
285 var closePool closeOnErrorPool

tsconsensus/tsconsensus_test.go1

333:47context-as-argumentcontext.Context should be the first parameter

tsconsensus/tsconsensus_test.go:333:47

332// become leader before adding other nodes.
333func createConsensusCluster(t testing.TB, ctx context.Context, clusterTag string, participants []*participant, cfg Config) {
334 t.Helper()

ipn/ipnauth/test_actor.go1

22:2context-stored-in-structdo not store context.Context in a struct; pass it explicitly to each operation

ipn/ipnauth/test_actor.go:22:2

21 CID ClientID // non-zero if the actor represents a connected LocalAPI client
22 Ctx context.Context // context associated with the actor
23 LocalSystem bool // whether the actor represents the special Local System account on Windows

client/web/web.go1

1177:18cyclomatic-complexityfunction complexity is 13; maximum is 10

client/web/web.go:1177:18

1176// If reauthentication has been requested, an authURL is returned to complete device registration.
1177func (s *Server) tailscaleUp(ctx context.Context, st *ipnstate.Status, opt tailscaleUpOptions) (authURL string, retErr error) {
1178 origAuthURL := st.AuthURL

cmd/connector-gen/github.go1

55:3deep-exitprocess-exit calls should be confined to main or init

cmd/connector-gen/github.go:55:3

54 if err := json.NewDecoder(r.Body).Decode(&ghm); err != nil {
55 log.Fatal(err)
56 }

cmd/tailscale/cli/cert.go1

206:9deprecated-api-usagesoftware.sslmate.com/src/go-pkcs12.Encode is deprecated: for the same behavior, use LegacyRC2.Encode; for better compatibility, use Legacy.Encode; for better security, use Modern.Encode.

cmd/tailscale/cli/cert.go:206:9

205 // fighting Windows.
206 return pkcs12.Encode(rand.Reader, cert.PrivateKey, certs[0], certs[1:], "" /* no password */)
207}

atomicfile/atomicfile_test.go1

27:22discarded-error-resulterror result returned by os.Remove is discarded

atomicfile/atomicfile_test.go:27:22

26 path = filepath.Join("/tmp", filename)
27 t.Cleanup(func() { os.Remove(path) })
28 } else {

cmd/k8s-operator/metrics_resources.go1

67:1doc-comment-perioddocumentation comment should end with punctuation

cmd/k8s-operator/metrics_resources.go:67:1

66// this ServiceMonitor.
67// https://github.com/prometheus-operator/prometheus-operator/blob/bb4514e0d5d69f20270e29cfd4ad39b87865ccdf/pkg/apis/monitoring/v1/servicemonitor_types.go#L88
68type ServiceMonitorNamespaceSelector struct {

cmd/k8s-operator/tsrecorder.go1

270:4early-returninvert the condition and return early to reduce nesting

cmd/k8s-operator/tsrecorder.go:270:4

269 if err := r.Delete(ctx, &sa); err != nil {
270 if apierrors.IsNotFound(err) {
271 logger.Debugf("ServiceAccount %s not found, likely already deleted", sa.Name)

util/singleflight/singleflight.go1

269:32empty-conditional-blockempty block should be removed or documented

util/singleflight/singleflight.go:269:32

268 }
269 } else if c.err == errGoexit {
270 // Already in the process of goexit, no need to call again

ipn/ipnlocal/ssh.go1

169:2enforce-switch-styledefault clause should be the last switch clause

ipn/ipnlocal/ssh.go:169:2

168 switch typ {
169 default:
170 return nil, fmt.Errorf("unsupported key type %q", typ)

appc/appconnector_test.go1

696:14error-stringserror string should not be capitalized or end with punctuation

appc/appconnector_test.go:696:14

695 if err := a.ObserveDNSResponse(res); err != nil {
696 t.Errorf("ObserveDNSResponse: %v", err)
697 }

tempfork/sshtest/ssh/certs_test.go1

358:4excessive-blank-identifiersassignment discards three or more results; name meaningful results or simplify the return contract

tempfork/sshtest/ssh/certs_test.go:358:4

357
358 _, _, _, err = NewClientConn(c2, "", config)
359 if err != nil {

appc/observe.go1

20:24exported-declaration-commentexported function or method should have a comment beginning with its name

appc/observe.go:20:24

19// advised to advertise the discovered route.
20func (e *AppConnector) ObserveDNSResponse(res []byte) error {
21 var p dnsmessage.Parser

cmd/containerboot/main_test.go1

1:1file-length-limitfile has 1679 lines; maximum is 500

cmd/containerboot/main_test.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause

cmd/k8s-operator/tsrecorder_test.go1

233:86flag-parameterboolean parameter shouldExist controls function flow

cmd/k8s-operator/tsrecorder_test.go:233:86

232
233func expectRecorderResources(t *testing.T, fc client.WithWatch, tsr *tsapi.Recorder, shouldExist bool) {
234 t.Helper()

client/local/tailnetlock.go1

1:1formatfile is not formatted

client/local/tailnetlock.go:1:1

1// Copyright (c) Tailscale Inc & AUTHORS
2// SPDX-License-Identifier: BSD-3-Clause
  • Fix (safe): run `strider fmt client/local/tailnetlock.go`

client/web/web_test.go1

531:6function-lengthfunction has 24 statements and 303 lines; maximum is 50 statements or 75 lines

client/web/web_test.go:531:6

530
531func TestServeAuth(t *testing.T) {
532 user := &tailcfg.UserProfile{LoginName: "user@example.com", ID: tailcfg.UserID(1)}

net/dnscache/dnscache.go1

252:20function-result-limitfunction returns 4 values; maximum is 3

net/dnscache/dnscache.go:252:20

251
252func (r *Resolver) lookupIPCache(host string) (ip, ip6 netip.Addr, allIPs []netip.Addr, ok bool) {
253 r.mu.Lock()

cmd/tailscale/cli/cli_test.go1

949:3identical-switch-branchesswitch repeats a case body

cmd/tailscale/cli/cli_test.go:949:3

948 continue
949 case "NotepadURLs":
950 // TODO(bradfitz): https://github.com/tailscale/tailscale/issues/1830

client/web/web.go1

1320:2import-shadowingidentifier path shadows an imported package

client/web/web.go:1320:2

1319func (s *Server) proxyRequestToLocalAPI(w http.ResponseWriter, r *http.Request) {
1320 path := strings.TrimPrefix(r.URL.Path, "/api/local")
1321 if r.URL.Path == path { // missing prefix

tempfork/sshtest/ssh/session.go1

464:17inefficient-map-lookupreuse the map value obtained by the comma-ok lookup

tempfork/sshtest/ssh/session.go:464:17

463 if _, ok := signals[Signal(wm.signal)]; ok {
464 wm.status += signals[Signal(wm.signal)]
465 }

tsconsensus/tsconsensus_test.go1

349:26inefficient-sprintffmt.Sprintf is unnecessary for this conversion; use strconv.Itoa

tsconsensus/tsconsensus_test.go:349:26

348 participants[i].sm = &fsm{}
349 myCfg := addIDedLogger(fmt.Sprintf("%d", i), cfg)
350 c, err := Start(ctx, participants[i].ts, participants[i].sm, BootstrapOpts{Tag: clusterTag}, myCfg)

client/tailscale/tailscale_test.go1

26:14insecure-url-schemeURL uses insecure http scheme

client/tailscale/tailscale_test.go:26:14

25 elements: []any{"tailnet", "example.com"},
26 want: "http://127.0.0.1:1234/api/v2/tailnet/example.com",
27 },

types/geo/point.go1

178:7marshal-receivermarshal and unmarshal methods should use a consistent receiver type

types/geo/point.go:178:7

177// an error is returned.
178func (p *Point) UnmarshalBinary(data []byte) error {
179 if len(data) < 8 { // Two uint32s are 8 bytes long

cmd/containerboot/main.go1

561:9max-control-nestingcontrol-flow nesting exceeds 5 levels

cmd/containerboot/main.go:561:9

560 log.Printf("Installing forwarding rules for destination %v", ea.String())
561 if err := installEgressForwardingRule(ctx, ea.String(), addrs, nfr); err != nil {
562 return fmt.Errorf("installing egress proxy rules for destination %s: %v", ea.String(), err)

cmd/viewer/tests/tests.go1

81:6max-public-structsfile declares more than 5 exported structs

cmd/viewer/tests/tests.go:81:6

80
81type GenericIntStruct[T constraints.Integer] struct {
82 Value T

client/web/web.go1

1372:3modifies-parameterassignment modifies parameter prefix

client/web/web.go:1372:3

1371 }
1372 prefix = strings.TrimSuffix(prefix, "/")
1373 http.StripPrefix(prefix, h).ServeHTTP(w, r)

net/packet/icmp6.go1

78:2modifies-value-receiverassignment modifies value receiver h

net/packet/icmp6.go:78:2

77 // The caller does not need to set this.
78 h.IPProto = ipproto.ICMPv6
79

client/systray/systray.go1

116:29nested-structsmove nested anonymous struct types to named declarations

client/systray/systray.go:116:29

115
116 menu.rebuildCh = make(chan struct{}, 1)
117 menu.accountsCh = make(chan ipn.ProfileID)

cmd/k8s-operator/ingress-for-pg.go1

195:3nil-error-returnthis branch proves an error is non-nil but returns nil in an error result

cmd/k8s-operator/ingress-for-pg.go:195:3

194 r.recorder.Event(ing, corev1.EventTypeWarning, "InvalidIngressConfiguration", err.Error())
195 return false, nil
196 }

ipn/ipnlocal/cert_test.go1

350:5nil-value-with-nil-errornil payload is returned with a nil error; return a meaningful value or a descriptive error

ipn/ipnlocal/cert_test.go:350:5

349 getCertPemWasCalled = true
350 return nil, nil
351 }

metrics/metrics_test.go1

58:3no-defer-in-loopdefer inside a loop runs at function exit, not iteration exit

metrics/metrics_test.go:58:3

57 }
58 defer f.Close()
59 t.Logf("fds for #%v = %v", i, CurrentFDs())

clientupdate/clientupdate.go1

1141:4no-else-after-returnremove else and unindent its body after the return

clientupdate/clientupdate.go:1141:4

1140 return this, other, nil
1141 } else {
1142 return other, this, nil

cmd/tailscale/cli/configure_linux.go1

17:6no-initreplace init with explicit initialization

cmd/tailscale/cli/configure_linux.go:17:6

16
17func init() {
18 maybeSystrayCmd = systrayConfigCmd

cmd/tailscale/cli/cli_test.go1

657:2no-naked-returnreturn values must be explicit

cmd/tailscale/cli/cli_test.go:657:2

656 fs.Parse(flagArgs) // populates args
657 return
658}

client/systray/logo.go1

135:2no-package-varpackage variables introduce mutable global state

client/systray/logo.go:135:2

134 // exitNodeOnline is the Tailscale logo with an additional arrow overlay in the corner.
135 exitNodeOnline = tsLogo{
136 dots: [9]byte{

util/topk/topk_test.go1

110:4overwritten-before-usethis value of out is overwritten before use

util/topk/topk_test.go:110:4

109 }
110 out = topk.AppendTop(out[:0]) // should not allocate
111 _ = out // appease linter

client/tailscale/acl.go1

6:9package-commentspackage should have a documentation comment

client/tailscale/acl.go:6:9

5
6package tailscale
7

cmd/containerboot/kube_test.go1

301:50range-value-addresstaking the address of range value name can be misleading

cmd/containerboot/kube_test.go:301:50

300 var actual map[string][]byte
301 kc := &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
302 GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {

cmd/k8s-operator/svc-for-pg.go1

651:7receiver-namingreceiver name a is inconsistent with r

cmd/k8s-operator/svc-for-pg.go:651:7

650
651func (a *HAServiceReconciler) maybeUpdateAdvertiseServicesConfig(ctx context.Context, svc *corev1.Service, pgName string, serviceName tailcfg.ServiceName, cfg *ingressservices.Config, shouldBeAdvertised bool, logger *zap.SugaredLogger) (err error) {
652 logger.Debugf("checking advertisement for service '%s'", serviceName)

control/controlbase/conn_test.go1

36:8redefines-builtin-ididentifier max shadows a predeclared identifier

control/controlbase/conn_test.go:36:8

35 // of the Noise spec).
36 const max = 65535
37 if maxCiphertextSize > max {

client/web/web_test.go1

1234:36redundant-conversionconversion from tailcfg.NodeID to the identical type is redundant

client/web/web_test.go:1234:36

1233 UserProfile: &tailcfg.UserProfile{ID: tailcfg.UserID(2)},
1234 Node: &tailcfg.Node{ID: tailcfg.NodeID(1)},
1235 CapMap: tailcfg.PeerCapMap{

net/netmon/interfaces_windows.go1

160:3single-case-switchswitch with one case can be replaced by an if statement

net/netmon/interfaces_windows.go:160:3

159 ifs, err := getInterfaces(family, winipcfg.GAAFlagIncludeAllInterfaces, func(iface *winipcfg.IPAdapterAddresses) bool {
160 switch iface.IfType {
161 case winipcfg.IfTypeSoftwareLoopback:

cmd/k8s-operator/operator.go1

1388:3slice-preallocationpreallocate reqs with capacity len(range source) before appending once per iteration

cmd/k8s-operator/operator.go:1388:3

1387 }
1388 reqs := make([]reconcile.Request, 0)
1389 for _, ing := range ingList.Items {

client/tailscale/acl.go1

493:46standard-http-method-constantreplace the HTTP method literal with http.MethodPost

client/tailscale/acl.go:493:46

492 path := c.BuildTailnetURL("acl", "validate")
493 req, err := http.NewRequestWithContext(ctx, "POST", path, bytes.NewBuffer(postData))
494 if err != nil {

client/tailscale/devices.go1

196:2task-commentTODO comment should be resolved or linked to an owned work item

client/tailscale/devices.go:196:2

195 // If status code was not successful, return the error.
196 // TODO: Change the check for the StatusCode to include other 2XX success codes.
197 if resp.StatusCode != http.StatusOK {

client/web/qnap.go1

35:1top-level-declaration-ordertop-level declarations should be ordered as const, var, type, then func

client/web/qnap.go:35:1

34
35type qnapAuthResponse struct {
36 AuthPassed int `xml:"authPassed"`

cmd/natc/ippool/consensusippool_test.go1

330:17unchecked-type-assertionuse the checked two-result form of the type assertion

cmd/natc/ippool/consensusippool_test.go:330:17

329 }
330 snap := fsmSnap.(fsmSnapshot)
331

prober/prober_test.go1

801:2unclosed-http-response-bodylocally acquired HTTP response body is not directly closed or transferred before replacement or function exit

prober/prober_test.go:801:2

800
801 resp, err := http.DefaultClient.Do(req)
802 if err != nil {

ipn/desktop/sessions_windows.go1

641:2unexported-namingunexported identifier should not begin with an underscore

ipn/desktop/sessions_windows.go:641:2

640 // https://web.archive.org/web/20250207012421/https://learn.microsoft.com/en-us/windows/win32/termserv/wm-wtssession-change
641 _WM_WTSSESSION_CHANGE = 0x02B1
642)