Skip to content

Commit f02c76d

Browse files
authored
Merge pull request #139 from roadrunner-server/fix/run-as-user-lookup
fix: fail init on run-as user lookup error instead of falling back to uid 0
2 parents ca9e3a7 + 4772b03 commit f02c76d

7 files changed

Lines changed: 437 additions & 74 deletions

File tree

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ require (
3939
github.com/tklauser/numcpus v0.12.0 // indirect
4040
github.com/yusufpapurcu/wmi v1.2.4 // indirect
4141
go.yaml.in/yaml/v3 v3.0.4 // indirect
42-
golang.org/x/sync v0.20.0 // indirect
43-
golang.org/x/sys v0.45.0 // indirect
44-
golang.org/x/text v0.37.0 // indirect
42+
golang.org/x/sync v0.21.0 // indirect
43+
golang.org/x/sys v0.46.0 // indirect
44+
golang.org/x/text v0.38.0 // indirect
4545
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
4646
gopkg.in/yaml.v3 v3.0.1 // indirect
4747
)

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo
6060
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
6161
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
6262
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
63-
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
64-
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
63+
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
64+
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
6565
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6666
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
67-
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
68-
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
69-
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
70-
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
67+
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
68+
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
69+
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
70+
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
7171
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
7272
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
7373
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

go.work.sum

Lines changed: 264 additions & 0 deletions
Large diffs are not rendered by default.

plugin.go

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"log/slog"
66
"os"
77
"os/user"
8+
"runtime"
89
"strconv"
910
"strings"
1011
"sync"
@@ -25,10 +26,44 @@ type Plugin struct {
2526
preparedCmd []string
2627
preparedEnvs []string
2728

29+
ids *ids
30+
2831
log *slog.Logger
2932
factory pool.Factory
3033
}
3134

35+
// ids holds a resolved run-as user's numeric uid/gid pair.
36+
type ids struct {
37+
uid int
38+
gid int
39+
}
40+
41+
// resolveUser looks the user up in the user database and returns its ids.
42+
func resolveUser(name string) (*ids, error) {
43+
usr, err := user.Lookup(name)
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
return parseIDs(usr)
49+
}
50+
51+
// parseIDs converts the user database's textual ids to ints; non-numeric ids
52+
// are rejected.
53+
func parseIDs(usr *user.User) (*ids, error) {
54+
uid, err := strconv.Atoi(usr.Uid)
55+
if err != nil {
56+
return nil, errors.Errorf("failed to parse the user id %q: %v", usr.Uid, err)
57+
}
58+
59+
gid, err := strconv.Atoi(usr.Gid)
60+
if err != nil {
61+
return nil, errors.Errorf("failed to parse the group id %q: %v", usr.Gid, err)
62+
}
63+
64+
return &ids{uid: uid, gid: gid}, nil
65+
}
66+
3267
// Init application provider.
3368
func (p *Plugin) Init(cfg Configurer, log NamedLogger) error {
3469
const op = errors.Op("server_plugin_init")
@@ -53,6 +88,20 @@ func (p *Plugin) Init(cfg Configurer, log NamedLogger) error {
5388

5489
p.log = log.NamedLogger(PluginName)
5590

91+
// resolve the configured run-as user's uid/gid once
92+
if p.cfg.User != "" {
93+
// process.ExecuteFromUser is a no-op on Windows, and Windows uids (SIDs)
94+
// are not numeric — reject the option explicitly instead of failing on Atoi.
95+
if runtime.GOOS == "windows" {
96+
return errors.E(op, errors.Init, errors.Str("server.user is not supported on windows"))
97+
}
98+
99+
p.ids, err = resolveUser(p.cfg.User)
100+
if err != nil {
101+
return errors.E(op, errors.Init, err)
102+
}
103+
}
104+
56105
p.preparedCmd = prepareCmd(p.cfg.Command)
57106

58107
p.preparedEnvs = append(os.Environ(), RrRelay+"="+p.cfg.Relay)
@@ -146,41 +195,20 @@ func (p *Plugin) NewPoolWithOptions(ctx context.Context, cfg *pool.Config, env m
146195
return pl, nil
147196
}
148197

149-
// userInfo looks up the user once and returns uid and gid as ints.
150-
func (p *Plugin) userInfo() (uid int, gid int) {
151-
if p.cfg.User == "" {
152-
return 0, 0
153-
}
154-
155-
usr, err := user.Lookup(p.cfg.User)
156-
if err != nil {
157-
p.log.Error("failed to get user", "id", p.cfg.User)
158-
return 0, 0
159-
}
160-
161-
uid, err = strconv.Atoi(usr.Uid)
162-
if err != nil {
163-
p.log.Error("failed to parse user id", "id", p.cfg.User)
164-
return 0, 0
165-
}
166-
167-
gid, err = strconv.Atoi(usr.Gid)
168-
if err != nil {
169-
p.log.Error("failed to parse group id", "id", p.cfg.User)
170-
return 0, 0
171-
}
172-
173-
return uid, gid
174-
}
175-
176198
// UID returns a user id (if specified by user)
177199
func (p *Plugin) UID() int {
178-
uid, _ := p.userInfo()
179-
return uid
200+
if p.ids == nil {
201+
return 0
202+
}
203+
204+
return p.ids.uid
180205
}
181206

182207
// GID returns a group id (if specified by user)
183208
func (p *Plugin) GID() int {
184-
_, gid := p.userInfo()
185-
return gid
209+
if p.ids == nil {
210+
return 0
211+
}
212+
213+
return p.ids.gid
186214
}

plugin_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package server
33
import (
44
"log/slog"
55
"os"
6+
"os/user"
7+
"runtime"
8+
"strconv"
69
"testing"
710
"time"
811

@@ -77,6 +80,74 @@ func TestCommandUnknownUser(t *testing.T) {
7780
})
7881
}
7982

83+
func TestInitResolvesUser(t *testing.T) {
84+
if runtime.GOOS == "windows" {
85+
t.Skip("server.user is not supported on windows")
86+
}
87+
88+
current, err := user.Current()
89+
require.NoError(t, err)
90+
91+
log := slog.New(slog.NewTextHandler(os.Stderr, nil))
92+
p := &Plugin{
93+
preparedEnvs: make([]string, 0),
94+
cfg: &Config{},
95+
log: log,
96+
}
97+
98+
v := viper.New()
99+
v.Set("server.command", "php php_test_files/client.php echo pipes")
100+
v.Set("server.user", current.Username)
101+
102+
cfg, err := InitMockCfg(v)
103+
require.NoError(t, err)
104+
require.NoError(t, p.Init(cfg, NewTestLogger(log)))
105+
106+
uid, err := strconv.Atoi(current.Uid)
107+
require.NoError(t, err)
108+
gid, err := strconv.Atoi(current.Gid)
109+
require.NoError(t, err)
110+
111+
require.Equal(t, uid, p.UID())
112+
require.Equal(t, gid, p.GID())
113+
}
114+
115+
func TestParseIDs(t *testing.T) {
116+
resolved, err := parseIDs(&user.User{Uid: "1000", Gid: "1000"})
117+
require.NoError(t, err)
118+
require.Equal(t, &ids{uid: 1000, gid: 1000}, resolved)
119+
120+
resolved, err = parseIDs(&user.User{Uid: "S-1-5-21", Gid: "1000"})
121+
require.ErrorContains(t, err, "failed to parse the user id")
122+
require.Nil(t, resolved)
123+
124+
resolved, err = parseIDs(&user.User{Uid: "1000", Gid: "S-1-5-21"})
125+
require.ErrorContains(t, err, "failed to parse the group id")
126+
require.Nil(t, resolved)
127+
}
128+
129+
func TestInitUnknownUser(t *testing.T) {
130+
log := slog.New(slog.NewTextHandler(os.Stderr, nil))
131+
p := &Plugin{
132+
preparedEnvs: make([]string, 0),
133+
cfg: &Config{},
134+
log: log,
135+
}
136+
137+
v := viper.New()
138+
v.Set("server.command", "php php_test_files/client.php echo pipes")
139+
v.Set("server.user", "rr-definitely-missing-user")
140+
141+
cfg, err := InitMockCfg(v)
142+
require.NoError(t, err)
143+
144+
err = p.Init(cfg, NewTestLogger(log))
145+
require.Error(t, err)
146+
// the failed resolution must leave the ids unset, reading as 0/0
147+
require.Equal(t, 0, p.UID())
148+
require.Equal(t, 0, p.GID())
149+
}
150+
80151
func TestCommand1(t *testing.T) {
81152
log := slog.New(slog.NewTextHandler(os.Stderr, nil))
82153
p := &Plugin{

tests/go.mod

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ require (
3939
github.com/joho/godotenv v1.5.1 // indirect
4040
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
4141
github.com/libdns/libdns v1.1.1 // indirect
42-
github.com/mattn/go-colorable v0.1.14 // indirect
42+
github.com/mattn/go-colorable v0.1.15 // indirect
4343
github.com/mattn/go-isatty v0.0.22 // indirect
4444
github.com/mholt/acmez v1.2.0 // indirect
4545
github.com/mholt/acmez/v3 v3.1.6 // indirect
@@ -49,10 +49,10 @@ require (
4949
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
5050
github.com/prometheus/client_golang v1.23.2 // indirect
5151
github.com/prometheus/client_model v0.6.2 // indirect
52-
github.com/prometheus/common v0.67.5 // indirect
52+
github.com/prometheus/common v0.68.1 // indirect
5353
github.com/prometheus/procfs v0.20.1 // indirect
5454
github.com/quic-go/qpack v0.6.0 // indirect
55-
github.com/quic-go/quic-go v0.59.1 // indirect
55+
github.com/quic-go/quic-go v0.60.0 // indirect
5656
github.com/roadrunner-server/api-go/v6 v6.0.0-beta.12 // indirect
5757
github.com/roadrunner-server/api-plugins/v6 v6.0.0-beta.2 // indirect
5858
github.com/roadrunner-server/context v1.3.0 // indirect
@@ -80,17 +80,16 @@ require (
8080
go.uber.org/multierr v1.11.0 // indirect
8181
go.uber.org/zap v1.28.0 // indirect
8282
go.uber.org/zap/exp v0.3.0 // indirect
83-
go.yaml.in/yaml/v2 v2.4.4 // indirect
8483
go.yaml.in/yaml/v3 v3.0.4 // indirect
85-
golang.org/x/crypto v0.52.0 // indirect
86-
golang.org/x/mod v0.36.0 // indirect
87-
golang.org/x/net v0.55.0 // indirect
88-
golang.org/x/sync v0.20.0 // indirect
89-
golang.org/x/sys v0.45.0 // indirect
90-
golang.org/x/text v0.37.0 // indirect
84+
golang.org/x/crypto v0.53.0 // indirect
85+
golang.org/x/mod v0.37.0 // indirect
86+
golang.org/x/net v0.56.0 // indirect
87+
golang.org/x/sync v0.21.0 // indirect
88+
golang.org/x/sys v0.46.0 // indirect
89+
golang.org/x/text v0.38.0 // indirect
9190
golang.org/x/tools v0.45.0 // indirect
92-
google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa // indirect
93-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
91+
google.golang.org/genproto v0.0.0-20260608224507-4308a22a1bab // indirect
92+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab // indirect
9493
google.golang.org/grpc v1.81.1 // indirect
9594
google.golang.org/protobuf v1.36.11 // indirect
9695
gopkg.in/yaml.v3 v3.0.1 // indirect

tests/go.sum

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYq
5858
github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ=
5959
github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U=
6060
github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
61-
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
62-
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
61+
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
62+
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
6363
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
6464
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
6565
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
@@ -78,14 +78,15 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h
7878
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
7979
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
8080
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
81-
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
82-
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
81+
github.com/prometheus/common v0.68.1 h1:omjRRl4QP4komogpXuhfeOiisQg7xdy8VM1UY+pStaY=
82+
github.com/prometheus/common v0.68.1/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y=
8383
github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc=
8484
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
85+
github.com/quic-go/go-ossfuzz-seeds v0.1.0 h1:APacT+iIaNF6fd8AGEiN3bT/Jtkd2jz4v4TzM7MFjy0=
8586
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
8687
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
87-
github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
88-
github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
88+
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
89+
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
8990
github.com/roadrunner-server/api-go/v6 v6.0.0-beta.12 h1:FcRcCvW9OfQvH45SFsI21VoHpOOov56OvOSnO4UKvXs=
9091
github.com/roadrunner-server/api-go/v6 v6.0.0-beta.12/go.mod h1:prGWJ2GoF5YD5PIG7Tb6VKulU3bWoFwr9DCwgxheb80=
9192
github.com/roadrunner-server/api-plugins/v6 v6.0.0-beta.2 h1:GqsZzWQ5jMXRF1O/b8IqFz9PLpS7Ui0K4OyACLql2MI=
@@ -176,28 +177,28 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
176177
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
177178
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
178179
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
179-
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
180-
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
181-
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
182-
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
183-
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
184-
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
185-
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
186-
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
180+
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
181+
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
182+
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
183+
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
184+
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
185+
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
186+
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
187+
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
187188
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
188189
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
189-
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
190-
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
191-
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
192-
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
190+
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
191+
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
192+
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
193+
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
193194
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
194195
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
195196
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
196197
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
197-
google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa h1:mfj8IS4EA4VAR9a6QDVxTQkLY64iBybb5QI1B4pXrpE=
198-
google.golang.org/genproto v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:fuT7yonGw1Iq2oa+YC0fyqPPQJkgo/54gPNC6VitOkI=
199-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
200-
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
198+
google.golang.org/genproto v0.0.0-20260608224507-4308a22a1bab h1:bG8JpL3dfsvJKRgrh7yMkswdxzBqQDRYqkLDHo3+708=
199+
google.golang.org/genproto v0.0.0-20260608224507-4308a22a1bab/go.mod h1:cVHIikDNAdx8ISZeW+2rYkEMf3xn0GSaBYmVnWXQBUo=
200+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab h1:cY0oV1VnAqvaim8VsR8ZyEKAudzbRJMRGwD3W/L7yOw=
201+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260608224507-4308a22a1bab/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
201202
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
202203
google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I=
203204
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=

0 commit comments

Comments
 (0)