Skip to content
This repository was archived by the owner on Jul 13, 2025. It is now read-only.

Commit 7efd102

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents ead33e8 + e649227 commit 7efd102

File tree

269 files changed

+16215
-3895
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

269 files changed

+16215
-3895
lines changed

.golangci.yml

Lines changed: 100 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,110 @@
1+
version: "2"
2+
# Configuration for how we run golangci-lint
3+
# Timeout of 5m was the default in v1.
4+
run:
5+
timeout: 5m
16
linters:
27
# Don't enable any linters by default; just the ones that we explicitly
38
# enable in the list below.
4-
disable-all: true
9+
default: none
510
enable:
611
- bidichk
7-
- gofmt
8-
- goimports
912
- govet
1013
- misspell
1114
- revive
12-
13-
# Configuration for how we run golangci-lint
14-
run:
15-
timeout: 5m
16-
17-
issues:
18-
# Excluding configuration per-path, per-linter, per-text and per-source
19-
exclude-rules:
20-
# These are forks of an upstream package and thus are exempt from stylistic
21-
# changes that would make pulling in upstream changes harder.
22-
- path: tempfork/.*\.go
23-
text: "File is not `gofmt`-ed with `-s` `-r 'interface{} -> any'`"
24-
- path: util/singleflight/.*\.go
25-
text: "File is not `gofmt`-ed with `-s` `-r 'interface{} -> any'`"
26-
27-
# Per-linter settings are contained in this top-level key
28-
linters-settings:
29-
gofmt:
30-
rewrite-rules:
31-
- pattern: 'interface{}'
32-
replacement: 'any'
33-
34-
govet:
15+
settings:
3516
# Matches what we use in corp as of 2023-12-07
36-
enable:
37-
- asmdecl
38-
- assign
39-
- atomic
40-
- bools
41-
- buildtag
42-
- cgocall
43-
- copylocks
44-
- deepequalerrors
45-
- errorsas
46-
- framepointer
47-
- httpresponse
48-
- ifaceassert
49-
- loopclosure
50-
- lostcancel
51-
- nilfunc
52-
- nilness
53-
- printf
54-
- reflectvaluecompare
55-
- shift
56-
- sigchanyzer
57-
- sortslice
58-
- stdmethods
59-
- stringintconv
60-
- structtag
61-
- testinggoroutine
62-
- tests
63-
- unmarshal
64-
- unreachable
65-
- unsafeptr
66-
- unusedresult
67-
settings:
68-
printf:
69-
# List of print function names to check (in addition to default)
70-
funcs:
71-
- github.com/tailscale/tailscale/types/logger.Discard
72-
# NOTE(andrew-d): this doesn't currently work because the printf
73-
# analyzer doesn't support type declarations
74-
#- github.com/tailscale/tailscale/types/logger.Logf
75-
76-
revive:
77-
enable-all-rules: false
78-
ignore-generated-header: true
17+
govet:
18+
enable:
19+
- asmdecl
20+
- assign
21+
- atomic
22+
- bools
23+
- buildtag
24+
- cgocall
25+
- copylocks
26+
- deepequalerrors
27+
- errorsas
28+
- framepointer
29+
- httpresponse
30+
- ifaceassert
31+
- loopclosure
32+
- lostcancel
33+
- nilfunc
34+
- nilness
35+
- printf
36+
- reflectvaluecompare
37+
- shift
38+
- sigchanyzer
39+
- sortslice
40+
- stdmethods
41+
- stringintconv
42+
- structtag
43+
- testinggoroutine
44+
- tests
45+
- unmarshal
46+
- unreachable
47+
- unsafeptr
48+
- unusedresult
49+
settings:
50+
printf:
51+
# List of print function names to check (in addition to default)
52+
funcs:
53+
- github.com/tailscale/tailscale/types/logger.Discard
54+
# NOTE(andrew-d): this doesn't currently work because the printf
55+
# analyzer doesn't support type declarations
56+
#- github.com/tailscale/tailscale/types/logger.Logf
57+
revive:
58+
enable-all-rules: false
59+
rules:
60+
- name: atomic
61+
- name: context-keys-type
62+
- name: defer
63+
arguments: [[
64+
# Calling 'recover' at the time a defer is registered (i.e. "defer recover()") has no effect.
65+
"immediate-recover",
66+
# Calling 'recover' outside of a deferred function has no effect
67+
"recover",
68+
# Returning values from a deferred function has no effect
69+
"return",
70+
]]
71+
- name: duplicated-imports
72+
- name: errorf
73+
- name: string-of-int
74+
- name: time-equal
75+
- name: unconditional-recursion
76+
- name: useless-break
77+
- name: waitgroup-by-value
78+
exclusions:
79+
generated: lax
80+
presets:
81+
- comments
82+
- common-false-positives
83+
- legacy
84+
- std-error-handling
7985
rules:
80-
- name: atomic
81-
- name: context-keys-type
82-
- name: defer
83-
arguments: [[
84-
# Calling 'recover' at the time a defer is registered (i.e. "defer recover()") has no effect.
85-
"immediate-recover",
86-
# Calling 'recover' outside of a deferred function has no effect
87-
"recover",
88-
# Returning values from a deferred function has no effect
89-
"return",
90-
]]
91-
- name: duplicated-imports
92-
- name: errorf
93-
- name: string-of-int
94-
- name: time-equal
95-
- name: unconditional-recursion
96-
- name: useless-break
97-
- name: waitgroup-by-value
86+
# These are forks of an upstream package and thus are exempt from stylistic
87+
# changes that would make pulling in upstream changes harder.
88+
- path: tempfork/.*\.go
89+
text: File is not `gofmt`-ed with `-s` `-r 'interface{} -> any'`
90+
- path: util/singleflight/.*\.go
91+
text: File is not `gofmt`-ed with `-s` `-r 'interface{} -> any'`
92+
paths:
93+
- third_party$
94+
- builtin$
95+
- examples$
96+
formatters:
97+
enable:
98+
- gofmt
99+
- goimports
100+
settings:
101+
gofmt:
102+
rewrite-rules:
103+
- pattern: interface{}
104+
replacement: any
105+
exclusions:
106+
generated: lax
107+
paths:
108+
- third_party$
109+
- builtin$
110+
- examples$

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,7 @@ We require [Developer Certificate of
7171
Origin](https://en.wikipedia.org/wiki/Developer_Certificate_of_Origin)
7272
`Signed-off-by` lines in commits.
7373

74-
See `git log` for our commit message style. It's basically the same as
75-
[Go's style](https://go.dev/wiki/CommitMessage).
74+
See [commit-messages.md](docs/commit-messages.md) (or skim `git log`) for our commit message style.
7675

7776
## About Us
7877

build_dist.sh

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,26 @@ EOF
2828
exit 0
2929
fi
3030

31-
tags=""
31+
tags="${TAGS:-}"
3232
ldflags="-X tailscale.com/version.longStamp=${VERSION_LONG} -X tailscale.com/version.shortStamp=${VERSION_SHORT}"
3333

3434
# build_dist.sh arguments must precede go build arguments.
3535
while [ "$#" -gt 1 ]; do
3636
case "$1" in
3737
--extra-small)
38+
if [ ! -z "${TAGS:-}" ]; then
39+
echo "set either --extra-small or \$TAGS, but not both"
40+
exit 1
41+
fi
3842
shift
3943
ldflags="$ldflags -w -s"
40-
tags="${tags:+$tags,}ts_omit_aws,ts_omit_bird,ts_omit_tap,ts_omit_kube,ts_omit_completion,ts_omit_ssh,ts_omit_wakeonlan,ts_omit_capture"
44+
tags="${tags:+$tags,}ts_omit_aws,ts_omit_bird,ts_omit_tap,ts_omit_kube,ts_omit_completion,ts_omit_ssh,ts_omit_wakeonlan,ts_omit_capture,ts_omit_relayserver,ts_omit_taildrop"
4145
;;
4246
--box)
47+
if [ ! -z "${TAGS:-}" ]; then
48+
echo "set either --box or \$TAGS, but not both"
49+
exit 1
50+
fi
4351
shift
4452
tags="${tags:+$tags,}ts_include_cli"
4553
;;

client/local/local.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1504,7 +1504,7 @@ func (lc *Client) SwitchProfile(ctx context.Context, profile ipn.ProfileID) erro
15041504
// If the profile is the current profile, an empty profile
15051505
// will be selected as if SwitchToEmptyProfile was called.
15061506
func (lc *Client) DeleteProfile(ctx context.Context, profile ipn.ProfileID) error {
1507-
_, err := lc.send(ctx, "DELETE", "/localapi/v0/profiles"+url.PathEscape(string(profile)), http.StatusNoContent, nil)
1507+
_, err := lc.send(ctx, "DELETE", "/localapi/v0/profiles/"+url.PathEscape(string(profile)), http.StatusNoContent, nil)
15081508
return err
15091509
}
15101510

client/local/local_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import (
99
"context"
1010
"net"
1111
"net/http"
12-
"net/http/httptest"
1312
"testing"
1413

1514
"tailscale.com/tstest/deptest"
15+
"tailscale.com/tstest/nettest"
1616
"tailscale.com/types/key"
1717
)
1818

@@ -36,15 +36,15 @@ func TestGetServeConfigFromJSON(t *testing.T) {
3636
}
3737

3838
func TestWhoIsPeerNotFound(t *testing.T) {
39-
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
39+
nw := nettest.GetNetwork(t)
40+
ts := nettest.NewHTTPServer(nw, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
4041
w.WriteHeader(404)
4142
}))
4243
defer ts.Close()
4344

4445
lc := &Client{
4546
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
46-
var std net.Dialer
47-
return std.DialContext(ctx, network, ts.Listener.Addr().(*net.TCPAddr).String())
47+
return nw.Dial(ctx, network, ts.Listener.Addr().String())
4848
},
4949
}
5050
var k key.NodePublic

client/systray/logo.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import (
1111
"image"
1212
"image/color"
1313
"image/png"
14+
"runtime"
1415
"sync"
1516
"time"
1617

1718
"fyne.io/systray"
19+
ico "github.com/Kodeworks/golang-image-ico"
1820
"github.com/fogleman/gg"
1921
)
2022

@@ -251,7 +253,13 @@ func (logo tsLogo) renderWithBorder(borderUnits int) *bytes.Buffer {
251253
}
252254

253255
b := bytes.NewBuffer(nil)
254-
png.Encode(b, dc.Image())
256+
257+
// Encode as ICO format on Windows, PNG on all other platforms.
258+
if runtime.GOOS == "windows" {
259+
_ = ico.Encode(b, dc.Image())
260+
} else {
261+
_ = png.Encode(b, dc.Image())
262+
}
255263
return b
256264
}
257265

client/systray/systray.go

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
package systray
88

99
import (
10+
"bytes"
1011
"context"
1112
"errors"
1213
"fmt"
14+
"image"
1315
"io"
1416
"log"
1517
"net/http"
@@ -23,6 +25,7 @@ import (
2325
"time"
2426

2527
"fyne.io/systray"
28+
ico "github.com/Kodeworks/golang-image-ico"
2629
"github.com/atotto/clipboard"
2730
dbus "github.com/godbus/dbus/v5"
2831
"github.com/toqueteos/webbrowser"
@@ -81,12 +84,13 @@ type Menu struct {
8184
bgCancel context.CancelFunc
8285

8386
// Top-level menu items
84-
connect *systray.MenuItem
85-
disconnect *systray.MenuItem
86-
self *systray.MenuItem
87-
exitNodes *systray.MenuItem
88-
more *systray.MenuItem
89-
quit *systray.MenuItem
87+
connect *systray.MenuItem
88+
disconnect *systray.MenuItem
89+
self *systray.MenuItem
90+
exitNodes *systray.MenuItem
91+
more *systray.MenuItem
92+
rebuildMenu *systray.MenuItem
93+
quit *systray.MenuItem
9094

9195
rebuildCh chan struct{} // triggers a menu rebuild
9296
accountsCh chan ipn.ProfileID
@@ -292,6 +296,17 @@ func (menu *Menu) rebuild() {
292296
})
293297
}
294298

299+
// TODO(#15528): this menu item shouldn't be necessary at all,
300+
// but is at least more discoverable than having users switch profiles or exit nodes.
301+
menu.rebuildMenu = systray.AddMenuItem("Rebuild menu", "Fix missing menu items")
302+
onClick(ctx, menu.rebuildMenu, func(ctx context.Context) {
303+
select {
304+
case <-ctx.Done():
305+
case menu.rebuildCh <- struct{}{}:
306+
}
307+
})
308+
menu.rebuildMenu.Enable()
309+
295310
menu.quit = systray.AddMenuItem("Quit", "Quit the app")
296311
menu.quit.Enable()
297312

@@ -330,6 +345,20 @@ func setRemoteIcon(menu *systray.MenuItem, urlStr string) {
330345
resp, err := http.Get(urlStr)
331346
if err == nil && resp.StatusCode == http.StatusOK {
332347
b, _ = io.ReadAll(resp.Body)
348+
349+
// Convert image to ICO format on Windows
350+
if runtime.GOOS == "windows" {
351+
im, _, err := image.Decode(bytes.NewReader(b))
352+
if err != nil {
353+
return
354+
}
355+
buf := bytes.NewBuffer(nil)
356+
if err := ico.Encode(buf, im); err != nil {
357+
return
358+
}
359+
b = buf.Bytes()
360+
}
361+
333362
httpCache[urlStr] = b
334363
resp.Body.Close()
335364
}

0 commit comments

Comments
 (0)