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=