You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ze...@apache.org on 2023/06/21 14:38:36 UTC

[arrow-adbc] branch main updated: feat(go/adbc/driver/flightsql): Add cookie middleware option (#825)

This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new 17a13f9f feat(go/adbc/driver/flightsql): Add cookie middleware option (#825)
17a13f9f is described below

commit 17a13f9f5e6ee0c6f5d3fa7951b74fa5cbb6a96b
Author: Matt Topol <zo...@gmail.com>
AuthorDate: Wed Jun 21 10:38:31 2023 -0400

    feat(go/adbc/driver/flightsql): Add cookie middleware option (#825)
    
    Fixes #716
---
 docs/source/driver/flight_sql.rst                  |   6 +
 go/adbc/driver/flightsql/flightsql_adbc.go         |  33 ++++-
 .../driver/flightsql/flightsql_adbc_server_test.go | 152 +++++++++++++++++----
 go/adbc/go.mod                                     |  22 ++-
 go/adbc/go.sum                                     |  44 +++---
 5 files changed, 190 insertions(+), 67 deletions(-)

diff --git a/docs/source/driver/flight_sql.rst b/docs/source/driver/flight_sql.rst
index f0f7363a..3721c779 100644
--- a/docs/source/driver/flight_sql.rst
+++ b/docs/source/driver/flight_sql.rst
@@ -222,6 +222,12 @@ These options map 1:1 with the options in FlightClientOptions:
     defaults to 16 MiB since Flight services tend to return larger
     reponse payloads.  Should be a positive integer number of bytes.
 
+``adbc.flight.sql.rpc.with_cookie_middleware``
+    Enable or disable middleware that processes and handles "set-cookie"
+    metadata headers returned from the server and sends "Cookie" headers
+    back from the client. Value should be ``true`` or ``false``. Default
+    is ``false``.
+
 Custom Call Headers
 -------------------
 
diff --git a/go/adbc/driver/flightsql/flightsql_adbc.go b/go/adbc/driver/flightsql/flightsql_adbc.go
index 03bdefac..e038354c 100644
--- a/go/adbc/driver/flightsql/flightsql_adbc.go
+++ b/go/adbc/driver/flightsql/flightsql_adbc.go
@@ -80,6 +80,7 @@ const (
 	OptionTimeoutQuery        = "adbc.flight.sql.rpc.timeout_seconds.query"
 	OptionTimeoutUpdate       = "adbc.flight.sql.rpc.timeout_seconds.update"
 	OptionRPCCallHeaderPrefix = "adbc.flight.sql.rpc.call_header."
+	OptionCookieMiddleware    = "adbc.flight.sql.rpc.with_cookie_middleware"
 	infoDriverName            = "ADBC Flight SQL Driver - Go"
 )
 
@@ -184,12 +185,13 @@ func (d *dbDialOpts) rebuild() {
 }
 
 type database struct {
-	uri        *url.URL
-	creds      credentials.TransportCredentials
-	user, pass string
-	hdrs       metadata.MD
-	timeout    timeoutOption
-	dialOpts   dbDialOpts
+	uri           *url.URL
+	creds         credentials.TransportCredentials
+	user, pass    string
+	hdrs          metadata.MD
+	timeout       timeoutOption
+	dialOpts      dbDialOpts
+	enableCookies bool
 
 	alloc memory.Allocator
 }
@@ -327,6 +329,7 @@ func (d *database) SetOptions(cnOptions map[string]string) error {
 		}
 		delete(cnOptions, OptionWithBlock)
 	}
+
 	if val, ok := cnOptions[OptionWithMaxMsgSize]; ok {
 		var err error
 		var size int
@@ -346,6 +349,20 @@ func (d *database) SetOptions(cnOptions map[string]string) error {
 	}
 	d.dialOpts.rebuild()
 
+	if val, ok := cnOptions[OptionCookieMiddleware]; ok {
+		if val == adbc.OptionValueEnabled {
+			d.enableCookies = true
+		} else if val == adbc.OptionValueDisabled {
+			d.enableCookies = false
+		} else {
+			return adbc.Error{
+				Msg:  fmt.Sprintf("Invalid value for database option '%s': '%s'", OptionCookieMiddleware, val),
+				Code: adbc.StatusInvalidArgument,
+			}
+		}
+		delete(cnOptions, OptionCookieMiddleware)
+	}
+
 	for key, val := range cnOptions {
 		if strings.HasPrefix(key, OptionRPCCallHeaderPrefix) {
 			d.hdrs.Append(strings.TrimPrefix(key, OptionRPCCallHeaderPrefix), val)
@@ -544,6 +561,10 @@ func getFlightClient(ctx context.Context, loc string, d *database) (*flightsql.C
 		},
 	}
 
+	if d.enableCookies {
+		middleware = append(middleware, flight.NewClientCookieMiddleware())
+	}
+
 	uri, err := url.Parse(loc)
 	if err != nil {
 		return nil, adbc.Error{Msg: fmt.Sprintf("Invalid URI '%s': %s", loc, err), Code: adbc.StatusInvalidArgument}
diff --git a/go/adbc/driver/flightsql/flightsql_adbc_server_test.go b/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
index c4b5524f..9d959ac4 100644
--- a/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
+++ b/go/adbc/driver/flightsql/flightsql_adbc_server_test.go
@@ -21,6 +21,9 @@ package flightsql_test
 
 import (
 	"context"
+	"errors"
+	"fmt"
+	"net/textproto"
 	"os"
 	"strings"
 	"testing"
@@ -71,17 +74,17 @@ func (suite *ServerBasedTests) DoSetupSuite(srv flightsql.Server, srvMiddleware
 	suite.Require().NoError(err)
 }
 
-func (suite *ServerBasedTests) DoSetupTest() {
+func (suite *ServerBasedTests) SetupTest() {
 	var err error
 	suite.cnxn, err = suite.db.Open(context.Background())
 	suite.Require().NoError(err)
 }
 
-func (suite *ServerBasedTests) DoTearDownTest() {
+func (suite *ServerBasedTests) TearDownTest() {
 	suite.Require().NoError(suite.cnxn.Close())
 }
 
-func (suite *ServerBasedTests) DoTearDownSuite() {
+func (suite *ServerBasedTests) TearDownSuite() {
 	suite.db = nil
 	suite.s.Shutdown()
 }
@@ -96,6 +99,10 @@ func TestTimeout(t *testing.T) {
 	suite.Run(t, &TimeoutTests{})
 }
 
+func TestCookies(t *testing.T) {
+	suite.Run(t, &CookieTests{})
+}
+
 // ---- AuthN Tests --------------------
 
 type AuthnTestServer struct {
@@ -183,18 +190,6 @@ func (suite *AuthnTests) SetupSuite() {
 	})
 }
 
-func (suite *AuthnTests) SetupTest() {
-	suite.DoSetupTest()
-}
-
-func (suite *AuthnTests) TearDownTest() {
-	suite.DoTearDownTest()
-}
-
-func (suite *AuthnTests) TearDownSuite() {
-	suite.DoTearDownSuite()
-}
-
 func (suite *AuthnTests) TestBearerTokenUpdated() {
 	// apache/arrow-adbc#584: when setting the auth header directly, the client should use any updated token value from the server if given
 	stmt, err := suite.cnxn.NewStatement()
@@ -291,18 +286,6 @@ func (suite *TimeoutTests) SetupSuite() {
 	suite.DoSetupSuite(&TimeoutTestServer{}, nil, nil)
 }
 
-func (suite *TimeoutTests) SetupTest() {
-	suite.DoSetupTest()
-}
-
-func (suite *TimeoutTests) TearDownTest() {
-	suite.DoTearDownTest()
-}
-
-func (suite *TimeoutTests) TearDownSuite() {
-	suite.DoTearDownSuite()
-}
-
 func (ts *TimeoutTests) TestInvalidValues() {
 	keys := []string{
 		"adbc.flight.sql.rpc.timeout_seconds.fetch",
@@ -424,3 +407,118 @@ func (ts *TimeoutTests) TestDontTimeout() {
 	defer expected.Release()
 	ts.Truef(array.RecordEqual(rec, expected), "expected: %s\nactual: %s", expected, rec)
 }
+
+// ---- Cookie Tests --------------------
+type CookieTestServer struct {
+	flightsql.BaseServer
+
+	cur time.Time
+}
+
+func (server *CookieTestServer) GetFlightInfoStatement(ctx context.Context, cmd flightsql.StatementQuery, desc *flight.FlightDescriptor) (*flight.FlightInfo, error) {
+	md := metadata.MD{}
+	md.Append("set-cookie", "foo=bar")
+	md.Append("set-cookie", "bar=baz; Max-Age=1")
+	server.cur = time.Now()
+
+	if err := grpc.SendHeader(ctx, md); err != nil {
+		return nil, err
+	}
+
+	tkt, _ := flightsql.CreateStatementQueryTicket([]byte{})
+	info := &flight.FlightInfo{
+		FlightDescriptor: desc,
+		Endpoint: []*flight.FlightEndpoint{
+			{Ticket: &flight.Ticket{Ticket: tkt}},
+		},
+		TotalRecords: -1,
+		TotalBytes:   -1,
+	}
+
+	return info, nil
+}
+
+func (server *CookieTestServer) DoGetStatement(ctx context.Context, tkt flightsql.StatementQueryTicket) (*arrow.Schema, <-chan flight.StreamChunk, error) {
+	var (
+		foundFoo, foundBar bool
+	)
+
+	cookies := metadata.ValueFromIncomingContext(ctx, "cookie")
+	for _, line := range cookies {
+		line = textproto.TrimString(line)
+
+		var part string
+		for len(line) > 0 {
+			part, line, _ = strings.Cut(line, ";")
+			part = textproto.TrimString(part)
+			if part == "" {
+				continue
+			}
+
+			name, val, _ := strings.Cut(part, "=")
+			name = textproto.TrimString(name)
+			if len(val) > 1 && val[0] == '"' && val[len(val)-1] == '"' {
+				val = val[1 : len(val)-1]
+			}
+
+			switch name {
+			case "foo":
+				if val == "bar" {
+					foundFoo = true
+				}
+			case "bar":
+				if val == "baz" {
+					foundBar = true
+				}
+			default:
+				return nil, nil, fmt.Errorf("found unexpected cookie '%s' = '%s'", name, val)
+			}
+		}
+	}
+
+	if !foundFoo {
+		return nil, nil, errors.New("missing cookie 'foo'='bar'")
+	}
+
+	if !foundBar && time.Now().Before(server.cur.Add(1*time.Second)) {
+		return nil, nil, errors.New("missing cookie 'bar'='baz'")
+	}
+
+	sc := arrow.NewSchema([]arrow.Field{{Name: "a", Type: arrow.PrimitiveTypes.Int32, Nullable: true}}, nil)
+	rec, _, err := array.RecordFromJSON(memory.DefaultAllocator, sc, strings.NewReader(`[{"a": 5}]`))
+	if err != nil {
+		return nil, nil, err
+	}
+
+	ch := make(chan flight.StreamChunk)
+	go func() {
+		defer close(ch)
+		ch <- flight.StreamChunk{
+			Data: rec,
+			Desc: nil,
+			Err:  nil,
+		}
+	}()
+	return sc, ch, nil
+}
+
+type CookieTests struct {
+	ServerBasedTests
+}
+
+func (suite *CookieTests) SetupSuite() {
+	suite.DoSetupSuite(&CookieTestServer{}, nil, map[string]string{
+		driver.OptionCookieMiddleware: adbc.OptionValueEnabled,
+	})
+}
+
+func (suite *CookieTests) TestCookieUsage() {
+	stmt, err := suite.cnxn.NewStatement()
+	suite.Require().NoError(err)
+	defer stmt.Close()
+
+	suite.Require().NoError(stmt.SetSqlQuery("timeout"))
+	reader, _, err := stmt.ExecuteQuery(context.Background())
+	suite.Require().NoError(err)
+	defer reader.Release()
+}
diff --git a/go/adbc/go.mod b/go/adbc/go.mod
index c01265db..21bfad3e 100644
--- a/go/adbc/go.mod
+++ b/go/adbc/go.mod
@@ -20,14 +20,14 @@ module github.com/apache/arrow-adbc/go/adbc
 go 1.18
 
 require (
-	github.com/apache/arrow/go/v13 v13.0.0-20230612164931-b642707f6de7
+	github.com/apache/arrow/go/v13 v13.0.0-20230620164925-94af6c3c9646
 	github.com/bluele/gcache v0.0.2
 	github.com/google/uuid v1.3.0
 	github.com/snowflakedb/gosnowflake v1.6.21
 	github.com/stretchr/testify v1.8.2
 	golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
-	golang.org/x/sync v0.2.0
-	golang.org/x/tools v0.9.1
+	golang.org/x/sync v0.3.0
+	golang.org/x/tools v0.10.0
 	google.golang.org/grpc v1.54.0
 	google.golang.org/protobuf v1.30.0
 )
@@ -65,7 +65,7 @@ require (
 	github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.4 // indirect
-	github.com/google/flatbuffers v23.5.9+incompatible // indirect
+	github.com/google/flatbuffers v23.5.26+incompatible // indirect
 	github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
@@ -82,12 +82,12 @@ require (
 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/sirupsen/logrus v1.9.0 // indirect
 	github.com/zeebo/xxh3 v1.0.2 // indirect
-	golang.org/x/crypto v0.9.0 // indirect
-	golang.org/x/mod v0.10.0 // indirect
-	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/sys v0.8.0 // indirect
-	golang.org/x/term v0.8.0 // indirect
-	golang.org/x/text v0.9.0 // indirect
+	golang.org/x/crypto v0.10.0 // indirect
+	golang.org/x/mod v0.11.0 // indirect
+	golang.org/x/net v0.11.0 // indirect
+	golang.org/x/sys v0.9.0 // indirect
+	golang.org/x/term v0.9.0 // indirect
+	golang.org/x/text v0.10.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
@@ -102,5 +102,3 @@ require (
 	modernc.org/strutil v1.1.3 // indirect
 	modernc.org/token v1.1.0 // indirect
 )
-
-replace github.com/apache/arrow/go/v12 v12.0.0 => github.com/apache/arrow/go/v12 v12.0.0-20230428025921-06d49ee63e26
diff --git a/go/adbc/go.sum b/go/adbc/go.sum
index d861fbbe..97634848 100644
--- a/go/adbc/go.sum
+++ b/go/adbc/go.sum
@@ -14,10 +14,10 @@ github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvK
 github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
 github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
 github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/apache/arrow/go/v12 v12.0.0-20230428025921-06d49ee63e26 h1:30dVB4xxWsw05PFJnTTpebmxdpDJeEbX7xDwUMCFwDk=
-github.com/apache/arrow/go/v12 v12.0.0-20230428025921-06d49ee63e26/go.mod h1:weuTY7JvTG/HDPtMQxEUp7pU73vkLWMLpY67QwZ/WWw=
-github.com/apache/arrow/go/v13 v13.0.0-20230612164931-b642707f6de7 h1:/IGOeniBVzIXM2HWFKOhUTw8cE9DLxrvqSam8NYgFSA=
-github.com/apache/arrow/go/v13 v13.0.0-20230612164931-b642707f6de7/go.mod h1:W69eByFNO0ZR30q1/7Sr9d83zcVZmF2MiP3fFYAWJOc=
+github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc=
+github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg=
+github.com/apache/arrow/go/v13 v13.0.0-20230620164925-94af6c3c9646 h1:hLcsUn9hiiD7jDfJDKOe1tBfOL5v0wgrya5S8XXqzLw=
+github.com/apache/arrow/go/v13 v13.0.0-20230620164925-94af6c3c9646/go.mod h1:W69eByFNO0ZR30q1/7Sr9d83zcVZmF2MiP3fFYAWJOc=
 github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY=
 github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU=
 github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY=
@@ -85,8 +85,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/flatbuffers v23.5.9+incompatible h1:mTPHyMn3/qO7lvBcm5S9p0olWUQgtQhBf2QWiz1U3qA=
-github.com/google/flatbuffers v23.5.9+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/flatbuffers v23.5.26+incompatible h1:M9dgRyhJemaM4Sw8+66GHBu8ioaQmyPLg1b8VwK5WJg=
+github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -150,20 +150,20 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
 github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
-golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
+golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
 golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
 golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
-golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
+golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
+golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -171,16 +171,16 @@ golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
+golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
+golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
+golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
-golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
+golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
+golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=