From 01b0e760fac670c125158a3be495144d83ffb692 Mon Sep 17 00:00:00 2001 From: Alec Thomas Date: Fri, 22 Sep 2023 17:04:15 +1000 Subject: [PATCH] feat: add support for authentication plugins (#416) Authentication plugins accept the FTL endpoint URL as their argument and output one or more HTTP headers to be used for authentication. These headers will be added to every outbound request. There's an internal initial working proof of concept authentication plugin that uses [kooky](https://github.com/browserutils/kooky) to authenticate using an oauth2-proxy cookie. This seems to work well. --------- Co-authored-by: github-actions[bot] --- authn/authn.go | 187 ++++++++++++++++++++++++++++++++ backend/common/rpc/rpc.go | 66 ++++++----- cmd/ftl/main.go | 17 ++- examples/go.mod | 5 + examples/go.sum | 16 +++ examples/online-boutique/go.mod | 5 + examples/online-boutique/go.sum | 16 +++ go.mod | 10 +- go.sum | 23 +++- 9 files changed, 305 insertions(+), 40 deletions(-) create mode 100644 authn/authn.go diff --git a/authn/authn.go b/authn/authn.go new file mode 100644 index 0000000000..65170c98c2 --- /dev/null +++ b/authn/authn.go @@ -0,0 +1,187 @@ +package authn + +import ( + "bufio" + "context" + "fmt" + "io" + "net/http" + "net/url" + "os/user" + "strings" + "sync" + "time" + + "github.com/alecthomas/errors" + "github.com/zalando/go-keyring" + + "github.com/TBD54566975/ftl/backend/common/exec" + "github.com/TBD54566975/ftl/backend/common/log" +) + +// GetAuthenticationHeaders returns authentication headers for the given endpoint. +// +// "authenticators" are authenticator executables to use for each endpoint. The key is the URL of the endpoint, the +// value is the name/path of the authenticator executable. The authenticator executable will be called with the URL as +// the first argument, and output a list of headers to stdout to use for authentication. +// +// If the endpoint is already authenticated, the existing credentials will be returned. Additionally, credentials will +// be cached across runs in the keyring. +func GetAuthenticationHeaders(ctx context.Context, endpoint *url.URL, authenticators map[string]string) (http.Header, error) { + logger := log.FromContext(ctx).Scope(endpoint.Hostname()) + + endpoint = &url.URL{ + Scheme: endpoint.Scheme, + Host: endpoint.Host, + User: endpoint.User, + } + + usr, err := user.Current() + if err != nil { + return nil, errors.WithStack(err) + } + + // First, check if we have credentials in the keyring and that they work. + keyringKey := "ftl+" + endpoint.String() + logger.Debugf("Trying keyring key %s", keyringKey) + creds, err := keyring.Get(keyringKey, usr.Name) + if errors.Is(err, keyring.ErrNotFound) { + logger.Tracef("No credentials found in keyring") + } else if err != nil { + return nil, errors.WithStack(err) + } else { + logger.Tracef("Credentials found in keyring: %s", creds) + if headers, err := checkAuth(ctx, logger, endpoint, creds); err != nil { + return nil, errors.WithStack(err) + } else if headers != nil { + return headers, nil + } + } + + // Next, try the authenticator. + logger.Debugf("Trying authenticator") + authenticator, ok := authenticators[endpoint.Hostname()] + if !ok { + logger.Tracef("No authenticator found in %s", authenticators) + return nil, nil + } + + cmd := exec.Command(ctx, log.Error, ".", authenticator, endpoint.String()) + out := &strings.Builder{} + cmd.Stdout = out + err = cmd.Run() + if err != nil { + return nil, errors.Wrapf(err, "authenticator %s failed", authenticator) + } + + creds = out.String() + if headers, err := checkAuth(ctx, logger, endpoint, creds); err != nil { + return nil, errors.WithStack(err) + } else if headers != nil { + logger.Debugf("Authenticator %s succeeded", authenticator) + w := &strings.Builder{} + for name, values := range headers { + for _, value := range values { + fmt.Printf("%s: %s\r\n", name, value) + } + } + err = keyring.Set(keyringKey, usr.Name, w.String()) + if err != nil { + logger.Warnf("Failed to save credentials to keyring: %s", err) + } + return headers, nil + } + + return nil, nil +} + +// Check credentials and return authenticating headers if we're able to successfully authenticate. +func checkAuth(ctx context.Context, logger *log.Logger, endpoint *url.URL, creds string) (http.Header, error) { + // Parse the headers + headers := http.Header{} + buf := bufio.NewScanner(strings.NewReader(creds)) + logger.Tracef("Parsing credentials") + for buf.Scan() { + line := buf.Text() + name, value, ok := strings.Cut(line, ":") + if !ok { + return nil, errors.Errorf("invalid header %q", line) + } + headers[name] = append(headers[name], strings.TrimSpace(value)) + } + if buf.Err() != nil { + return nil, errors.WithStack(buf.Err()) + } + + // Issue a HEAD request with the headers to verify we get a 200 back. + client := &http.Client{ + Timeout: time.Second * 5, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + req, err := http.NewRequestWithContext(ctx, http.MethodHead, endpoint.String(), nil) + if err != nil { + return nil, errors.WithStack(err) + } + logger.Debugf("Authentication probe: %s %s", req.Method, req.URL) + for header, values := range headers { + for _, value := range values { + req.Header.Add(header, value) + } + } + logger.Tracef("Authenticating with headers %s", headers) + resp, err := client.Do(req) + if err != nil { + return nil, errors.WithStack(err) + } + defer resp.Body.Close() //nolint:gosec + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + logger.Debugf("Endpoint returned %d for authenticated request", resp.StatusCode) + logger.Debugf("Response headers: %s", resp.Header) + logger.Debugf("Response body: %s", body) + return nil, nil + } + logger.Debugf("Successfully authenticated with %s", headers) + return headers, nil +} + +// Transport returns a transport that will authenticate requests to the given endpoints. +func Transport(next http.RoundTripper, authenticators map[string]string) http.RoundTripper { + return &authnTransport{ + authenticators: authenticators, + credentials: map[string]http.Header{}, + next: next, + } +} + +type authnTransport struct { + lock sync.RWMutex + authenticators map[string]string + credentials map[string]http.Header + next http.RoundTripper +} + +func (a *authnTransport) RoundTrip(r *http.Request) (*http.Response, error) { + a.lock.RLock() + creds, ok := a.credentials[r.URL.Hostname()] + a.lock.RUnlock() + if !ok { + var err error + creds, err = GetAuthenticationHeaders(r.Context(), r.URL, a.authenticators) + if err != nil { + return nil, errors.Wrapf(err, "failed to get authentication headers for %s", r.URL.Hostname()) + } + a.lock.Lock() + a.credentials[r.URL.Hostname()] = creds + a.lock.Unlock() + } + for header, values := range creds { + for _, value := range values { + r.Header.Add(header, value) + } + } + resp, err := a.next.RoundTrip(r) + return resp, errors.WithStack(err) +} diff --git a/backend/common/rpc/rpc.go b/backend/common/rpc/rpc.go index 403888e61f..d021c406eb 100644 --- a/backend/common/rpc/rpc.go +++ b/backend/common/rpc/rpc.go @@ -13,59 +13,67 @@ import ( "github.com/jpillora/backoff" "golang.org/x/net/http2" + "github.com/TBD54566975/ftl/authn" "github.com/TBD54566975/ftl/backend/common/log" ftlv1 "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1" ) -var ( - dialer = &net.Dialer{ - Timeout: time.Second * 10, - } - h2cClient = func() *http.Client { - var netTransport = &http2.Transport{ +// InitialiseClients HTTP clients used by the RPC system. +// +// "authenticators" are authenticator executables to use for each endpoint. The key is the URL of the endpoint, the +// value is the path to the authenticator executable. +func InitialiseClients(authenticators map[string]string) { + // We can't have a client-wide timeout because it also applies to + // streaming RPCs, timing them out. + h2cClient = &http.Client{ + Transport: authn.Transport(&http2.Transport{ AllowHTTP: true, - DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) { + DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) { conn, err := dialer.Dial(network, addr) return conn, errors.WithStack(err) }, - } - return &http.Client{ - // We can't have a client-wide timeout because it also applies to - // streaming RPCs, timing them out. - // Timeout: time.Second * 10, - Transport: netTransport, - } - }() - tlsClient = func() *http.Client { - netTransport := &http2.Transport{ + }, authenticators), + } + tlsClient = &http.Client{ + Transport: authn.Transport(&http2.Transport{ DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { tlsDialer := tls.Dialer{Config: config, NetDialer: dialer} conn, err := tlsDialer.DialContext(ctx, network, addr) return conn, errors.WithStack(err) }, - } - return &http.Client{ - // We can't have a client-wide timeout because it also applies to - // streaming RPCs, timing them out. - // Timeout: time.Second * 10, - Transport: netTransport, - } - }() + }, authenticators), + } +} + +var ( + dialer = &net.Dialer{ + Timeout: time.Second * 10, + } + h2cClient *http.Client + tlsClient *http.Client ) type Pingable interface { Ping(context.Context, *connect.Request[ftlv1.PingRequest]) (*connect.Response[ftlv1.PingResponse], error) } +// GetHTTPClient returns a HTTP client usable for the given URL. +func GetHTTPClient(url string) *http.Client { + if h2cClient == nil { + panic("rpc.InitialiseClients() must be called before GetHTTPClient()") + } + if strings.HasPrefix(url, "http://") { + return h2cClient + } + return tlsClient +} + // ClientFactory is a function that creates a new client and is typically one of // the New*Client functions generated by protoc-gen-connect-go. type ClientFactory[Client Pingable] func(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) Client func Dial[Client Pingable](factory ClientFactory[Client], baseURL string, errorLevel log.Level, opts ...connect.ClientOption) Client { - client := tlsClient - if strings.HasPrefix(baseURL, "http://") { - client = h2cClient - } + client := GetHTTPClient(baseURL) opts = append(opts, DefaultClientOptions(errorLevel)...) return factory(client, baseURL, opts...) } diff --git a/cmd/ftl/main.go b/cmd/ftl/main.go index f2fcc326e2..f9b4824419 100644 --- a/cmd/ftl/main.go +++ b/cmd/ftl/main.go @@ -9,10 +9,11 @@ import ( "syscall" "github.com/alecthomas/kong" + kongtoml "github.com/alecthomas/kong-toml" "github.com/bufbuild/connect-go" _ "github.com/TBD54566975/ftl/backend/common/automaxprocs" // Set GOMAXPROCS to match Linux container CPU quota. - log2 "github.com/TBD54566975/ftl/backend/common/log" + "github.com/TBD54566975/ftl/backend/common/log" "github.com/TBD54566975/ftl/backend/common/rpc" "github.com/TBD54566975/ftl/protos/xyz/block/ftl/v1/ftlv1connect" ) @@ -21,9 +22,12 @@ var version = "dev" type CLI struct { Version kong.VersionFlag `help:"Show version."` - LogConfig log2.Config `embed:"" prefix:"log-" group:"Logging:"` + Config kong.ConfigFlag `help:"Load configuration from TOML file." placeholder:"FILE"` + LogConfig log.Config `embed:"" prefix:"log-" group:"Logging:"` Endpoint *url.URL `default:"http://127.0.0.1:8892" help:"FTL endpoint to bind/connect to." env:"FTL_ENDPOINT"` + Authenticators map[string]string `help:"Authenticators to use for FTL endpoints." mapsep:"," env:"FTL_AUTHENTICATORS" placeholder:"HOST=EXE,…"` + Status statusCmd `cmd:"" help:"Show FTL status."` PS psCmd `cmd:"" help:"List deployments."` Serve serveCmd `cmd:"" help:"Start the FTL server."` @@ -40,6 +44,7 @@ var cli CLI func main() { kctx := kong.Parse(&cli, kong.Description(`FTL - Towards a 𝝺-calculus for large-scale systems`), + kong.Configuration(kongtoml.Loader, ".ftl.toml", "~/.ftl.toml"), kong.AutoGroup(func(parent kong.Visitable, flag *kong.Flag) *kong.Group { node, ok := parent.(*kong.Command) if !ok { @@ -54,13 +59,15 @@ func main() { }, ) + rpc.InitialiseClients(cli.Authenticators) + // Set the log level for child processes. os.Setenv("LOG_LEVEL", cli.LogConfig.Level.String()) ctx, cancel := context.WithCancel(context.Background()) - logger := log2.Configure(os.Stderr, cli.LogConfig) - ctx = log2.ContextWithLogger(ctx, logger) + logger := log.Configure(os.Stderr, cli.LogConfig) + ctx = log.ContextWithLogger(ctx, logger) // Handle signals. sigch := make(chan os.Signal, 1) @@ -86,6 +93,6 @@ func main() { func makeDialer[Client rpc.Pingable](newClient func(connect.HTTPClient, string, ...connect.ClientOption) Client) func() (Client, error) { return func() (Client, error) { - return rpc.Dial(newClient, cli.Endpoint.String(), log2.Error), nil + return rpc.Dial(newClient, cli.Endpoint.String(), log.Error), nil } } diff --git a/examples/go.mod b/examples/go.mod index e6946b0a1a..ec45039619 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -11,19 +11,24 @@ require ( github.com/alecthomas/errors v0.4.0 // indirect github.com/alecthomas/participle/v2 v2.0.0 // indirect github.com/alecthomas/types v0.7.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect github.com/bufbuild/connect-go v1.8.0 // indirect github.com/bufbuild/connect-grpcreflect-go v1.1.0 // indirect github.com/bufbuild/connect-opentelemetry-go v0.3.0 // indirect + github.com/danieljoos/wincred v1.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/iancoleman/strcase v0.2.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/rs/cors v1.9.0 // indirect github.com/swaggest/jsonschema-go v0.3.59 // indirect github.com/swaggest/refl v1.2.0 // indirect + github.com/zalando/go-keyring v0.2.1 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect diff --git a/examples/go.sum b/examples/go.sum index 723de06c1d..7465084921 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -10,6 +10,8 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= @@ -20,6 +22,9 @@ github.com/bufbuild/connect-grpcreflect-go v1.1.0 h1:T0FKu1y9zZW4cjHuF+Q7jIN6ek8 github.com/bufbuild/connect-grpcreflect-go v1.1.0/go.mod h1:AxcY2fSAr+oQQuu+K35qy2VDtX+LWr7SrS2SvfjY898= github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk= github.com/bufbuild/connect-opentelemetry-go v0.3.0/go.mod h1:r1ppyTtu1EWeRodk4Q/JbyQhIWtO7eR3GoRDzjeEcNU= +github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -29,6 +34,9 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -58,6 +66,9 @@ github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= @@ -70,6 +81,8 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc= +github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= @@ -99,6 +112,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= diff --git a/examples/online-boutique/go.mod b/examples/online-boutique/go.mod index a5ccd17664..c1b863e219 100644 --- a/examples/online-boutique/go.mod +++ b/examples/online-boutique/go.mod @@ -16,18 +16,23 @@ require ( github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.0.0 // indirect github.com/alecthomas/types v0.7.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect github.com/bufbuild/connect-go v1.8.0 // indirect github.com/bufbuild/connect-grpcreflect-go v1.1.0 // indirect github.com/bufbuild/connect-opentelemetry-go v0.3.0 // indirect + github.com/danieljoos/wincred v1.1.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/iancoleman/strcase v0.2.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/rs/cors v1.9.0 // indirect github.com/swaggest/jsonschema-go v0.3.59 // indirect github.com/swaggest/refl v1.2.0 // indirect + github.com/zalando/go-keyring v0.2.1 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect diff --git a/examples/online-boutique/go.sum b/examples/online-boutique/go.sum index b76bb29f91..0ad1144229 100644 --- a/examples/online-boutique/go.sum +++ b/examples/online-boutique/go.sum @@ -10,6 +10,8 @@ github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= @@ -20,6 +22,9 @@ github.com/bufbuild/connect-grpcreflect-go v1.1.0 h1:T0FKu1y9zZW4cjHuF+Q7jIN6ek8 github.com/bufbuild/connect-grpcreflect-go v1.1.0/go.mod h1:AxcY2fSAr+oQQuu+K35qy2VDtX+LWr7SrS2SvfjY898= github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk= github.com/bufbuild/connect-opentelemetry-go v0.3.0/go.mod h1:r1ppyTtu1EWeRodk4Q/JbyQhIWtO7eR3GoRDzjeEcNU= +github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -29,6 +34,9 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -60,6 +68,9 @@ github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= @@ -72,6 +83,8 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc= +github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw= go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= @@ -101,6 +114,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= diff --git a/go.mod b/go.mod index 19e12deeca..a717bff18d 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/TBD54566975/ftl go 1.21 require ( - github.com/BurntSushi/toml v1.2.1 - github.com/alecthomas/kong v0.7.1 + github.com/BurntSushi/toml v1.3.2 + github.com/alecthomas/kong v0.8.0 + github.com/alecthomas/kong-toml v0.0.0-20230922031405-31cfb1264a3b github.com/bufbuild/connect-go v1.8.0 github.com/go-logr/logr v1.2.4 github.com/golang/protobuf v1.5.3 @@ -17,6 +18,7 @@ require ( github.com/rs/cors v1.9.0 github.com/swaggest/jsonschema-go v0.3.59 github.com/titanous/json5 v1.0.0 + github.com/zalando/go-keyring v0.2.1 go.opentelemetry.io/otel v1.16.0 go.opentelemetry.io/otel/metric v1.16.0 go.opentelemetry.io/otel/trace v1.16.0 @@ -30,13 +32,17 @@ require ( require ( github.com/alecthomas/repr v0.2.0 // indirect + github.com/alessio/shellescape v1.4.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/danieljoos/wincred v1.1.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/swaggest/refl v1.2.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect diff --git a/go.sum b/go.sum index c128ac64d9..8e36dd15b2 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= @@ -44,14 +44,18 @@ github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKB github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= github.com/alecthomas/errors v0.4.0 h1:zDIapqdw7gVx2BrQpw3Ll5YRGFuaiB0ywcjesqT0RIE= github.com/alecthomas/errors v0.4.0/go.mod h1:0DQf6/xQp3f9rv+k72g2NmeTW2lC74kXA6b/8dN9BwY= -github.com/alecthomas/kong v0.7.1 h1:azoTh0IOfwlAX3qN9sHWTxACE2oV8Bg2gAwBsMwDQY4= -github.com/alecthomas/kong v0.7.1/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= +github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= +github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= +github.com/alecthomas/kong-toml v0.0.0-20230922031405-31cfb1264a3b h1:A+PJz+8ULrnKZJYNwaefLGcXwAy5mnv0eD9zsx0PdYc= +github.com/alecthomas/kong-toml v0.0.0-20230922031405-31cfb1264a3b/go.mod h1:d0aHX/kbCSdgQSg7ZUQzSTbBCh02sjSu8RT3YF2TKzA= github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g= github.com/alecthomas/participle/v2 v2.0.0/go.mod h1:rAKZdJldHu8084ojcWevWAL8KmEU+AT+Olodb+WoN2Y= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/types v0.7.1 h1:zU49e5jp0MS4sVDq0yEX4uX/jX7aVpvwd+Rm632ZpEQ= github.com/alecthomas/types v0.7.1/go.mod h1:t7PnU03TVweFpbPVKaeLtFykjJD8rqiBJ7gfkp6UvLQ= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/bool64/dev v0.2.29 h1:x+syGyh+0eWtOzQ1ItvLzOGIWyNWnyjXpHIcpF2HvL4= github.com/bool64/dev v0.2.29/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= @@ -79,6 +83,8 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/danieljoos/wincred v1.1.0 h1:3RNcEpBg4IhIChZdFRSdlQt1QjCp1sMAPIrOnm7Yf8g= +github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -102,6 +108,9 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -213,6 +222,8 @@ github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4 github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= @@ -233,6 +244,7 @@ github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -255,6 +267,8 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/zalando/go-keyring v0.2.1 h1:MBRN/Z8H4U5wEKXiD67YbDAr5cj/DOStmSga70/2qKc= +github.com/zalando/go-keyring v0.2.1/go.mod h1:g63M2PPn0w5vjmEbwAX3ib5I+41zdm4esSETOn9Y6Dw= 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= @@ -555,6 +569,7 @@ gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=