From 2ffda2baa2bf3112aa74f8f1b608c5d89193bfd4 Mon Sep 17 00:00:00 2001 From: Lucas Bickel <116588+hairmare@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:13:20 +0200 Subject: [PATCH] fix: middleware refactor and more tests (#44) * refactor HandleFunc into a bunch of middlewares * add tests for Authenticate and LoadEvent middleware --- app/app.go | 4 +- app/handler.go | 30 +++------ app/handler_test.go | 17 +++-- app/models/eventData.go | 9 +++ app/server.go | 138 +++++++++++++++++++++++--------------- app/server_test.go | 143 ++++++++++++++++++++++++++++++++-------- go.mod | 20 +++--- go.sum | 59 +++++++++++++++++ 8 files changed, 299 insertions(+), 121 deletions(-) create mode 100644 app/models/eventData.go diff --git a/app/app.go b/app/app.go index 99ff4fd..c717fad 100644 --- a/app/app.go +++ b/app/app.go @@ -3,7 +3,7 @@ package app import ( "errors" - cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/adfinis-sygroup/mopsos/app/models" "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -27,7 +27,7 @@ func NewApp(c *Config, db *gorm.DB) (*App, error) { func (a *App) Run() { // eventChan is used to asynchronously pass events receiver from the Server to the Handler - eventChan := make(chan cloudevents.Event) + eventChan := make(chan models.EventData) // handle events in background goroutine go func() { diff --git a/app/handler.go b/app/handler.go index d200c3a..64b0e8e 100644 --- a/app/handler.go +++ b/app/handler.go @@ -3,8 +3,6 @@ package app import ( "context" - otelObs "github.com/cloudevents/sdk-go/observability/opentelemetry/v2/client" - cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/sirupsen/logrus" "gorm.io/gorm" "gorm.io/gorm/clause" @@ -26,36 +24,24 @@ func NewHandler(enableTracing bool, db *gorm.DB) *Handler { } // HandleEvents blocks on the queue and handles events -func (h *Handler) HandleEvents(eventChan chan cloudevents.Event) error { +func (h *Handler) HandleEvents(eventChan chan models.EventData) error { // block on the event channel while ranging over its contents - for event := range eventChan { - err := h.HandleEvent(event) + for data := range eventChan { + err := h.HandleEvent(data) if err != nil { - logrus.WithField("event", event).WithError(err).Error("failed to handle event") + logrus.WithField("event", data.Event).WithError(err).Error("failed to handle event") } } return nil } -func (h *Handler) HandleEvent(event cloudevents.Event) error { - log := logrus.WithField("event", event) +func (h *Handler) HandleEvent(data models.EventData) error { + log := logrus.WithField("event", data.Event) log.Debug("received event") ctx := context.Background() - if h.enableTracing { - ctx = otelObs.ExtractDistributedTracingExtension(ctx, event) - } - - record := &models.Record{} - - err := event.DataAs(record) - if err != nil { - log.WithError(err).Errorf("failed to unmarshal event data") - return err - } - - log.WithField("record", record).Debug("creating record") + log.WithField("record", data.Record).Debug("creating record") h.database.WithContext(ctx).Clauses( clause.OnConflict{ @@ -67,7 +53,7 @@ func (h *Handler) HandleEvent(event cloudevents.Event) error { }, UpdateAll: true, }, - ).Create(record) + ).Create(&data.Record) return nil } diff --git a/app/handler_test.go b/app/handler_test.go index 202d0b9..d30c79a 100644 --- a/app/handler_test.go +++ b/app/handler_test.go @@ -18,7 +18,7 @@ import ( "github.com/adfinis-sygroup/mopsos/app/models" ) -func eventStub(record *models.Record) cloudevents.Event { +func eventStub(record *models.Record) models.EventData { ctx := context.Background() evt := cloudevents.NewEvent(cloudevents.VersionV1) @@ -47,12 +47,15 @@ func eventStub(record *models.Record) cloudevents.Event { fmt.Printf("%+v\n", ctx) fmt.Printf("%+v\n", evt) - return evt + return models.EventData{ + Event: evt, + Record: *record, + } } func Test_Handler_HandleEvent(t *testing.T) { type args struct { - event cloudevents.Event + eventData models.EventData } tests := []struct { name string @@ -62,7 +65,7 @@ func Test_Handler_HandleEvent(t *testing.T) { { name: "simple event with minimal data", args: args{ - event: eventStub( + eventData: eventStub( &models.Record{ ClusterName: "test", ApplicationName: "test", @@ -74,7 +77,7 @@ func Test_Handler_HandleEvent(t *testing.T) { { name: "event with complete data", args: args{ - event: eventStub( + eventData: eventStub( &models.Record{ ClusterName: "cluster-name", InstanceId: "cluster-instance", @@ -88,7 +91,7 @@ func Test_Handler_HandleEvent(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - evt := tt.args.event + evt := tt.args.eventData.Event evtRecord := &models.Record{} err := evt.DataAs(evtRecord) if err != nil { @@ -107,7 +110,7 @@ func Test_Handler_HandleEvent(t *testing.T) { h := mopsos.NewHandler(true, gdb) - if err := h.HandleEvent(evt); (err != nil) != tt.wantErr { + if err := h.HandleEvent(tt.args.eventData); (err != nil) != tt.wantErr { t.Errorf("Handler.HandleEvent() error = %v, wantErr %v", err, tt.wantErr) } diff --git a/app/models/eventData.go b/app/models/eventData.go new file mode 100644 index 0000000..da3f7fe --- /dev/null +++ b/app/models/eventData.go @@ -0,0 +1,9 @@ +package models + +import cloudevents "github.com/cloudevents/sdk-go/v2" + +// EventData is the data structure for passing events between the server and the handler +type EventData struct { + Event cloudevents.Event + Record Record +} diff --git a/app/server.go b/app/server.go index 6db155e..a58a84c 100644 --- a/app/server.go +++ b/app/server.go @@ -7,9 +7,8 @@ import ( "github.com/adfinis-sygroup/mopsos/app/models" otelObs "github.com/cloudevents/sdk-go/observability/opentelemetry/v2/client" - cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/cloudevents/sdk-go/v2/binding" - "github.com/cloudevents/sdk-go/v2/protocol" + "github.com/cloudevents/sdk-go/v2/event" httproto "github.com/cloudevents/sdk-go/v2/protocol/http" http_logrus "github.com/improbable-eng/go-httpwares/logging/logrus" "github.com/sirupsen/logrus" @@ -20,9 +19,15 @@ import ( type Server struct { config *Config - EventChan chan<- cloudevents.Event + EventChan chan<- models.EventData } +type eventContext string + +var ContextUsername eventContext = "mopsos.username" +var ContextEvent eventContext = "mopsos.event" +var ContextRecord eventContext = "mopsos.record" + // NewServer creates a server that receives CloudEvents from the network func NewServer(cfg *Config) *Server { return &Server{ @@ -33,37 +38,81 @@ func NewServer(cfg *Config) *Server { // Start starts the server and listens for incoming events func (s *Server) Start() { mux := http.NewServeMux() - mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { - // an example API handler - err := json.NewEncoder(w).Encode(map[string]bool{"ok": true}) - if err != nil { - logrus.WithError(err).Error("error encoding response") - } - }) - mux.Handle("/webhook", otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() + mux.HandleFunc("/health", s.HandleHealthCheck) + mux.Handle("/webhook", otelhttp.NewHandler( + s.Authenticate( + s.LoadEvent( + s.Validate( + http.HandlerFunc(s.HandleWebhook), + ), + ), + ), + "webhook-receiver"), + ) + + logrus.WithField("listener", s.config.HttpListener).Info("Starting server") + loggingMiddleware := http_logrus.Middleware( + logrus.WithFields(logrus.Fields{}), + )(mux) + logrus.Fatal(http.ListenAndServe(s.config.HttpListener, loggingMiddleware)) +} +// WithEventChannel sets the event channel for the server +func (s *Server) WithEventChannel(eventChan chan<- models.EventData) *Server { + s.EventChan = eventChan + return s +} + +// Authenticate middleware handles checking credentials +func (s *Server) Authenticate(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // get basic auth credentials username, password, ok := r.BasicAuth() if !ok { http.Error(w, "missing Authorization header", http.StatusUnauthorized) return } - if !s.checkAuth(username, password) { + + logrus.WithFields(logrus.Fields{ + "username": username, + }).Debug("checking credentials") + if s.config.BasicAuthUsers[username] != password { http.Error(w, "invalid credentials", http.StatusUnauthorized) return } + ctx := context.WithValue(r.Context(), ContextUsername, username) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +// LoadEvent middlerware loads event from the request +func (s *Server) LoadEvent(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // get event message := httproto.NewMessageFromHttpRequest(r) - event, err := binding.ToEvent(context.TODO(), message) + event, err := binding.ToEvent(r.Context(), message) if err != nil { logrus.WithError(err).Error("failed to decode event") return } + if s.config.EnableTracing { + // inject the span context into the event so it can be use i.e. while inserting to the database + otelObs.InjectDistributedTracingExtension(r.Context(), *event) + } + logrus.Debugf("received event: %v", event) - // TODO consider how to harmonise this with what the handler does later on + ctx := context.WithValue(r.Context(), ContextEvent, event) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +// Validate middleware handles checking received events for validity +func (s *Server) Validate(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + event := r.Context().Value(ContextEvent).(*event.Event) record := &models.Record{} + if err := event.DataAs(record); err != nil { logrus.WithError(err).Errorf("failed to unmarshal event data") http.Error(w, "failed to unmarshal event data", http.StatusInternalServerError) @@ -71,53 +120,34 @@ func (s *Server) Start() { } // reject record that have not been sent from the right auth - if record.ClusterName != username { + if record.ClusterName != r.Context().Value(ContextUsername).(string) { http.Error(w, "event data does not match username", http.StatusUnauthorized) return } - err = s.HandleReceivedEvent(ctx, *event) - if err != nil { - logrus.WithError(err).Error("failed to handle event") - return - } - // return 202 accepted once the event is on the queue - w.WriteHeader(http.StatusAccepted) - }), "webhook-receiver")) - - logrus.WithField("listener", s.config.HttpListener).Info("Starting server") - loggingMiddleware := http_logrus.Middleware( - logrus.WithFields(logrus.Fields{}), - )(mux) - logrus.Fatal(http.ListenAndServe(s.config.HttpListener, loggingMiddleware)) + ctx := context.WithValue(r.Context(), ContextRecord, record) + next.ServeHTTP(w, r.WithContext(ctx)) + }) } -// WithEventChannel sets the event channel for the server -func (s *Server) WithEventChannel(eventChan chan<- cloudevents.Event) *Server { - s.EventChan = eventChan - return s +func (s *Server) HandleHealthCheck(w http.ResponseWriter, r *http.Request) { + // an example API handler + err := json.NewEncoder(w).Encode(map[string]bool{"ok": true}) + if err != nil { + logrus.WithError(err).Error("error encoding response") + } } -// HandleReceivedEvent is the handler for the cloudevents receiver, public for testing -func (s *Server) HandleReceivedEvent(ctx context.Context, event cloudevents.Event) protocol.Result { - - if s.config.EnableTracing { - // inject the span context into the event so it can be use i.e. while inserting to the database - otelObs.InjectDistributedTracingExtension(ctx, event) - } +func (s *Server) HandleWebhook(w http.ResponseWriter, r *http.Request) { + // get middleware data from context + event := r.Context().Value(ContextEvent).(*event.Event) + record := r.Context().Value(ContextRecord).(*models.Record) // send the event to the main app via the async channel - s.EventChan <- event - - logrus.Debugf("received event: %v", event) - - return nil -} - -// checkAuth checks if the username and password are correct -func (s *Server) checkAuth(username, password string) bool { - logrus.WithFields(logrus.Fields{ - "username": username, - }).Debug("checking credentials") - return s.config.BasicAuthUsers[username] == password + s.EventChan <- models.EventData{ + Event: *event, + Record: *record, + } + // return 202 accepted once the event is on the queue + w.WriteHeader(http.StatusAccepted) } diff --git a/app/server_test.go b/app/server_test.go index bb2c37b..05b6127 100644 --- a/app/server_test.go +++ b/app/server_test.go @@ -1,53 +1,142 @@ package app_test import ( - "context" + "bytes" + "net/http" + "net/http/httptest" "testing" cloudevents "github.com/cloudevents/sdk-go/v2" "gorm.io/gorm" mopsos "github.com/adfinis-sygroup/mopsos/app" + "github.com/adfinis-sygroup/mopsos/app/models" ) -func Test_ServerHandleReceivedEvent(t *testing.T) { +func newApp() (*mopsos.App, *gorm.DB, chan models.EventData) { dbMock := &gorm.DB{} a, _ := mopsos.NewApp(&mopsos.Config{ HttpListener: ":8080", EnableTracing: false, TracingTarget: "", + + BasicAuthUsers: map[string]string{ + "username": "password", + }, }, dbMock) - eventChan := make(chan cloudevents.Event) + + eventChan := make(chan models.EventData) a.Server.WithEventChannel(eventChan) - ctx := context.TODO() - mockEvent := cloudevents.NewEvent( - cloudevents.VersionV1, - ) - mockEvent.SetType("test") - go func() { - err := a.Server.HandleReceivedEvent(ctx, mockEvent) - if err != nil { - t.Errorf("error: %v", err) - } - }() - for i := range eventChan { - if i.Type() != "test" { - t.Errorf("error: %v", i.Type()) - } - close(eventChan) - } + return a, dbMock, eventChan } func Test_ServerWithEventChannel(t *testing.T) { - dbMock := &gorm.DB{} - a, _ := mopsos.NewApp(&mopsos.Config{ - HttpListener: ":8080", - EnableTracing: false, - }, dbMock) - eventChan := make(chan cloudevents.Event) + a, _, eventChan := newApp() + a.Server.WithEventChannel(eventChan) if a.Server.EventChan != eventChan { - t.Errorf("error: %v", "event channel not set") + t.Errorf("event channel not set") + } +} + +func Test_Authenticate(t *testing.T) { + a, _, _ := newApp() + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Context().Value(mopsos.ContextUsername) != "username" { + t.Error("username not set") + } + }) + + req := httptest.NewRequest(http.MethodGet, "http://example.com", nil) + req.SetBasicAuth("username", "password") + + res := httptest.NewRecorder() + + auth := a.Server.Authenticate(handler) + auth.ServeHTTP(res, req) + + if res.Result().StatusCode != http.StatusOK { + t.Errorf("status code should be 200") + } + +} + +func Test_AuthenticateNoHeader(t *testing.T) { + a, _, _ := newApp() + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Error("handler should not be called") + }) + + req := httptest.NewRequest(http.MethodGet, "http://example.com", nil) + + res := httptest.NewRecorder() + + auth := a.Server.Authenticate(handler) + auth.ServeHTTP(res, req) + + if res.Result().StatusCode != http.StatusUnauthorized { + t.Errorf("status code should be 401") + } +} + +func Test_AuthenticateInvalidUser(t *testing.T) { + a, _, _ := newApp() + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + t.Error("handler should not be called") + }) + + req := httptest.NewRequest(http.MethodGet, "http://example.com", nil) + req.SetBasicAuth("username", "invalid") + + res := httptest.NewRecorder() + + auth := a.Server.Authenticate(handler) + auth.ServeHTTP(res, req) + + if res.Result().StatusCode != http.StatusUnauthorized { + t.Errorf("status code should be 401") + } +} + +func Test_LoadEvent(t *testing.T) { + a, _, _ := newApp() + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + event := r.Context().Value(mopsos.ContextEvent).(*cloudevents.Event) + if event.Type() != "test" { + t.Errorf("event type should be test") + } + }) + + body := []byte(`{"specversion":"1.0","type":"test"}`) + req := httptest.NewRequest(http.MethodPost, "http://example.com/webhook", bytes.NewReader(body)) + req.Header.Add("Content-Type", "application/cloudevents+json") + + res := httptest.NewRecorder() + + load := a.Server.LoadEvent(handler) + load.ServeHTTP(res, req) + + req.Body.Close() +} + +func Test_HandleHealthCheck(t *testing.T) { + a, _, _ := newApp() + + req := httptest.NewRequest(http.MethodGet, "http://example.com/health", nil) + res := httptest.NewRecorder() + + a.Server.HandleHealthCheck(res, req) + + if res.Result().StatusCode != http.StatusOK { + t.Errorf("status code should be 200") + } + expected := "{\"ok\":true}\n" + if res.Body.String() != expected { + t.Errorf("body should be %v got %s", expected, res.Body.String()) } } diff --git a/go.mod b/go.mod index 9f7c597..466a2c9 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.10.1 + github.com/spf13/viper v1.11.0 github.com/uptrace/opentelemetry-go-extra/otelgorm v0.1.12 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 go.opentelemetry.io/otel v1.6.3 @@ -24,10 +24,10 @@ require ( require ( github.com/benbjohnson/clock v1.3.0 // indirect - github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/glebarez/go-sqlite v1.15.1 // indirect + github.com/glebarez/go-sqlite v1.16.0 // indirect github.com/go-chi/chi v1.5.4 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -55,6 +55,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.4.1 // indirect @@ -69,16 +70,17 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect - golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect - golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/text v0.3.7 // indirect - google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7 // indirect + google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/ini.v1 v1.66.4 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - modernc.org/libc v1.14.12 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + modernc.org/libc v1.15.0 // indirect modernc.org/mathutil v1.4.1 // indirect modernc.org/memory v1.0.7 // indirect - modernc.org/sqlite v1.15.2 // indirect + modernc.org/sqlite v1.16.0 // indirect ) diff --git a/go.sum b/go.sum index dbef795..2acaa8d 100644 --- a/go.sum +++ b/go.sum @@ -28,12 +28,16 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= @@ -75,6 +79,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -134,6 +140,8 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/glebarez/go-sqlite v1.15.1 h1:1gRIcUp1EFZ9wn7qBVFte332R6elCC6nJl4+YWu7SNI= github.com/glebarez/go-sqlite v1.15.1/go.mod h1:rAfxRB8nJkvpDoj3sCegn4Sm/w4xX3o2lx7GiJ5vs0k= +github.com/glebarez/go-sqlite v1.16.0 h1:h28rHued+hGof3fNLksBcLwz/a71fiGZ/eIJHK0SsLI= +github.com/glebarez/go-sqlite v1.16.0/go.mod h1:i8/JtqoqzBAFkrUTxbQFkQ05odCOds3j7NlDaXjqiPY= github.com/glebarez/sqlite v1.4.1 h1:IrFURFnrjiPhRW8D8N7YvUssBNzfbrTb4xN6Mk7W7rM= github.com/glebarez/sqlite v1.4.1/go.mod h1:OI0VEF6vz0qLnOr3ooLCuVdsxwNrPlo9Bscqjg9x2bM= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= @@ -239,6 +247,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= @@ -255,6 +265,7 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -275,6 +286,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -387,6 +399,7 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -416,6 +429,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= +github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -448,6 +463,7 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -474,6 +490,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= +github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -501,8 +519,11 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -584,6 +605,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -665,8 +688,11 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5 h1:bRb386wvrE+oBNdF1d/Xh9mQrfQ4ecYhW5qJ5GvTGT4= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -684,7 +710,9 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -767,9 +795,16 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f h1:rlezHXNlxYWvBCzNses9Dlc7nGFaNMJeqLolcmQSSZY= golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -856,6 +891,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -888,6 +924,10 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -959,9 +999,20 @@ google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7 h1:HOL66YCI20JvN2hVk6o2YIp9i/3RvzVUz82PqNr7fXw= google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9 h1:XGQ6tc+EnM35IAazg4y6AHmUg4oK8NXsXaILte1vRlk= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -990,6 +1041,7 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1065,6 +1117,7 @@ modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g modernc.org/cc/v3 v3.35.20/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.35.22/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/cc/v3 v3.35.24/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= +modernc.org/cc/v3 v3.35.25/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60= modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= @@ -1110,6 +1163,8 @@ modernc.org/ccgo/v3 v3.15.14/go.mod h1:144Sz2iBCKogb9OKwsu7hQEub3EVgOlyI8wMUPGKU modernc.org/ccgo/v3 v3.15.15/go.mod h1:z5qltXjU4PJl0pE5nhYQCvA9DhPHiWsl5GWl89+NSYE= modernc.org/ccgo/v3 v3.15.16/go.mod h1:XbKRMeMWMdq712Tr5ECgATYMrzJ+g9zAZEj2ktzBe24= modernc.org/ccgo/v3 v3.15.17/go.mod h1:bofnFkpRFf5gLY+mBZIyTW6FEcp26xi2lgOFk2Rlvs0= +modernc.org/ccgo/v3 v3.15.18/go.mod h1:/2lv3WjHyanEr2sAPdGKRC38n6f0werut9BRXUjjX+A= +modernc.org/ccgo/v3 v3.15.19/go.mod h1:TDJj+DxR26pkDteH2E5WQDj/xlmtsX7JdzkJkaZhOVU= modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= @@ -1161,6 +1216,8 @@ modernc.org/libc v1.14.10/go.mod h1:y1MtIWhwpJFpLYm6grAThtuXJKEsY6xkdZmXbRngIdo= modernc.org/libc v1.14.11/go.mod h1:l5/Mz/GrZwOqzwRHA3abgSCnSeJzzTl+Ify0bAwKbAw= modernc.org/libc v1.14.12 h1:pUBZTYoISfbb4pCf4PECENpbvwDBxeKc+/dS9LyOWFM= modernc.org/libc v1.14.12/go.mod h1:fJdoe23MHu2ruPQkFPPqCpToDi5cckzsbmkI6Ez0LqQ= +modernc.org/libc v1.15.0 h1:/CTHjQ1QO5mkLDeQICuA9Vh0YvhQTMqtCF2urQTaod8= +modernc.org/libc v1.15.0/go.mod h1:H1OKCu+NYa9+uQG8WsP7DndMBP61I4PWH8ivWhbdoWQ= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= @@ -1174,6 +1231,8 @@ modernc.org/memory v1.0.7/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.15.2 h1:Es0SrEJUQHH7rt6uC/Zh2gHQ0AUhgB+F2RQqpXf3MNs= modernc.org/sqlite v1.15.2/go.mod h1:2P9bWfawhYMpYsBELqKREE+LFZo4uPApOuqszlZ7QX8= +modernc.org/sqlite v1.16.0 h1:DdvOGaWN0y+X7t2L7RUD63gcwbVjYZjcBZnA68g44EI= +modernc.org/sqlite v1.16.0/go.mod h1:Jwe13ItpESZ+78K5WS6+AjXsUg+JvirsjN3iIDO4C8k= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/tcl v1.11.2/go.mod h1:BRzgpajcGdS2qTxniOx9c/dcxjlbA7p12eJNmiriQYo= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=