From 34a1dbf800ec34310545fab4f3670791e3ff2aec Mon Sep 17 00:00:00 2001 From: Danielle Miu <29378233+DanielleMiu@users.noreply.github.com> Date: Thu, 31 Oct 2024 13:10:04 -0400 Subject: [PATCH] [fix] allow IPv6 controllers, workers, and targets Co-authored-by: Damian Debkowski --- enos/ci/bootstrap/main.tf | 3 +- enos/enos.hcl | 3 +- internal/alias/target/alias_test.go | 6 +- internal/cmd/base/dev.go | 32 +- internal/cmd/base/listener.go | 33 +- internal/cmd/base/servers.go | 24 +- internal/cmd/commands/connect/connect.go | 24 +- internal/cmd/commands/dev/dev.go | 11 +- internal/cmd/commands/server/server.go | 21 +- internal/cmd/config/config.go | 141 +++++-- internal/cmd/config/config_test.go | 97 +++++ internal/cmd/config/options.go | 15 + .../handlers/targets/target_service.go | 14 +- .../targets/tcp/target_service_test.go | 170 ++++++-- internal/daemon/controller/testing.go | 5 +- internal/daemon/controller/testing_test.go | 25 ++ .../daemon/worker/controller_connection.go | 11 +- internal/daemon/worker/testing.go | 6 +- internal/daemon/worker/testing_test.go | 24 ++ internal/host/plugin/host_address_test.go | 60 ++- internal/host/static/host.go | 3 +- internal/host/static/host_test.go | 36 +- internal/host/static/repository_host.go | 15 +- internal/host/static/repository_host_test.go | 156 +++++++ internal/host/static/testing.go | 24 ++ internal/session/connection.go | 10 + internal/session/connection_test.go | 148 ++++++- internal/session/session.go | 8 +- internal/target/repository.go | 17 +- .../target/tcp/repository_tcp_target_test.go | 177 +++++++- internal/target/tcp/testing_test.go | 121 +++++- internal/tests/api/targets/target_test.go | 33 +- internal/tests/cluster/ipv6_listener_test.go | 71 ++-- .../cluster/multi_controller_worker_test.go | 91 ++++- .../tests/cluster/worker_bytesupdown_test.go | 23 +- internal/tests/cluster/worker_proxy_test.go | 25 +- internal/tests/helper/option.go | 13 + internal/tests/helper/testing_helper.go | 53 ++- internal/util/net.go | 72 ++++ internal/util/net_test.go | 385 ++++++++++++++++++ plugins/boundary/mains/aws/go.mod | 86 ++-- plugins/boundary/mains/aws/go.sum | 240 ++++------- 42 files changed, 1991 insertions(+), 541 deletions(-) create mode 100644 internal/util/net.go create mode 100644 internal/util/net_test.go diff --git a/enos/ci/bootstrap/main.tf b/enos/ci/bootstrap/main.tf index 3c778c49ce..1b9f952fb6 100644 --- a/enos/ci/bootstrap/main.tf +++ b/enos/ci/bootstrap/main.tf @@ -4,7 +4,8 @@ terraform { required_providers { aws = { - source = "hashicorp/aws" + source = "hashicorp/aws" + version = "5.72.1" } } diff --git a/enos/enos.hcl b/enos/enos.hcl index 5bd1d82a53..d71352c566 100644 --- a/enos/enos.hcl +++ b/enos/enos.hcl @@ -14,7 +14,8 @@ terraform "default" { } aws = { - source = "hashicorp/aws" + source = "hashicorp/aws" + version = "5.72.1" } } } diff --git a/internal/alias/target/alias_test.go b/internal/alias/target/alias_test.go index 8bff6d08dc..c9571b61b2 100644 --- a/internal/alias/target/alias_test.go +++ b/internal/alias/target/alias_test.go @@ -157,7 +157,7 @@ func TestCreate(t *testing.T) { a.PublicId, err = db.NewPublicId(ctx, globals.TargetAliasPrefix) require.NoError(t, err) - start := time.Now().UTC() + start := time.Now().UTC().Round(time.Second) err = rw.Create(ctx, a) if c.errContains != "" { @@ -169,8 +169,8 @@ func TestCreate(t *testing.T) { assert.Equal(t, a.Version, uint32(1)) assert.Equal(t, a.ScopeId, c.scope) assert.Equal(t, a.Value, c.value) - assert.GreaterOrEqual(t, a.CreateTime.AsTime(), start) - assert.GreaterOrEqual(t, a.UpdateTime.AsTime(), start) + assert.GreaterOrEqual(t, a.CreateTime.AsTime().Round(time.Second), start) + assert.GreaterOrEqual(t, a.UpdateTime.AsTime().Round(time.Second), start) if c.validate != nil { c.validate(t, a) } diff --git a/internal/cmd/base/dev.go b/internal/cmd/base/dev.go index f930015444..e8881d5d3e 100644 --- a/internal/cmd/base/dev.go +++ b/internal/cmd/base/dev.go @@ -23,6 +23,7 @@ import ( "github.com/hashicorp/boundary/internal/iam" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/types/scope" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/testing/dbtest" capoidc "github.com/hashicorp/cap/oidc" "github.com/jimlambrt/gldap" @@ -242,13 +243,9 @@ func (b *Server) CreateDevLdapAuthMethod(ctx context.Context) error { if purpose != "api" { continue } - host, _, err = net.SplitHostPort(ln.Config.Address) + host, _, err = util.SplitHostPort(ln.Config.Address) if err != nil { - if strings.Contains(err.Error(), "missing port") { - host = ln.Config.Address - } else { - return fmt.Errorf("error splitting host/port: %w", err) - } + return fmt.Errorf("error splitting host/port: %w", err) } } if host == "" { @@ -259,6 +256,16 @@ func (b *Server) CreateDevLdapAuthMethod(ctx context.Context) error { tb := &oidcLogger{} port = testdirectory.FreePort(tb) + + // The util.SplitHostPort() method removes the square brackets that enclose the + // host address when the address type is ipv6. The square brackets must be + // added back, otherwise the gldap server will fail to start due to a parsing + // error. + if ip := net.ParseIP(host); ip != nil { + if ip.To16() != nil { + host = fmt.Sprintf("[%s]", host) + } + } b.DevLdapSetup.testDirectory = testdirectory.Start(tb, testdirectory.WithNoTLS(tb), testdirectory.WithHost(tb, host), @@ -455,15 +462,12 @@ func (b *Server) CreateDevOidcAuthMethod(ctx context.Context) error { if purpose != "api" { continue } - b.DevOidcSetup.hostAddr, b.DevOidcSetup.callbackPort, err = net.SplitHostPort(ln.Config.Address) + b.DevOidcSetup.hostAddr, b.DevOidcSetup.callbackPort, err = util.SplitHostPort(ln.Config.Address) if err != nil { - if strings.Contains(err.Error(), "missing port") { - b.DevOidcSetup.hostAddr = ln.Config.Address - // Use the default API port in the callback - b.DevOidcSetup.callbackPort = "9200" - } else { - return fmt.Errorf("error splitting host/port: %w", err) - } + return fmt.Errorf("error splitting host/port: %w", err) + } + if b.DevOidcSetup.callbackPort == "" { + b.DevOidcSetup.callbackPort = "9200" } } if b.DevOidcSetup.hostAddr == "" { diff --git a/internal/cmd/base/listener.go b/internal/cmd/base/listener.go index 49a32e9bce..bfaad009de 100644 --- a/internal/cmd/base/listener.go +++ b/internal/cmd/base/listener.go @@ -16,6 +16,7 @@ import ( _ "crypto/sha512" "crypto/tls" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-secure-stdlib/listenerutil" "github.com/hashicorp/go-secure-stdlib/reloadutil" "github.com/mitchellh/cli" @@ -137,24 +138,22 @@ func tcpListenerFactory(purpose string, l *listenerutil.ListenerConfig, ui cli.U } } - host, port, err := net.SplitHostPort(l.Address) + host, port, err := util.SplitHostPort(l.Address) if err != nil { - if strings.Contains(err.Error(), "missing port") { - switch purpose { - case "api": - port = "9200" - case "cluster": - port = "9201" - case "proxy": - port = "9202" - case "ops": - port = "9203" - default: - return "", nil, errors.New("no purpose provided for listener and no port discoverable") - } - host = l.Address - } else { - return "", nil, fmt.Errorf("error splitting host/port: %w", err) + return "", nil, fmt.Errorf("error splitting host/port: %w", err) + } + if port == "" { + switch purpose { + case "api": + port = "9200" + case "cluster": + port = "9201" + case "proxy": + port = "9202" + case "ops": + port = "9203" + default: + return "", nil, errors.New("no purpose provided for listener and no port discoverable") } } diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index b5392a53b1..351f8a6f81 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -10,11 +10,9 @@ import ( "errors" "fmt" "io" - "net" "os" "os/signal" "path/filepath" - "regexp" "sort" "strconv" "strings" @@ -58,10 +56,6 @@ const ( WorkerAuthReqFile = "auth_request_token" ) -// This regular expression is used to find all instances of square brackets within a string. -// This regular expression is used to remove the square brackets from an IPv6 address. -var squareBrackets = regexp.MustCompile("\\[|\\]") - func init() { metric.InitializeBuildInfo(prometheus.DefaultRegisterer) } @@ -841,20 +835,14 @@ func (b *Server) SetupWorkerPublicAddress(conf *config.Config, flagValue string) } } - host, port, err := net.SplitHostPort(conf.Worker.PublicAddr) + host, port, err := util.SplitHostPort(conf.Worker.PublicAddr) if err != nil { - if strings.Contains(err.Error(), "missing port") { - port = "9202" - host = conf.Worker.PublicAddr - } else { - return fmt.Errorf("Error splitting public adddress host/port: %w", err) - } + return fmt.Errorf("Error splitting public adddress host/port: %w", err) } - - // remove the square brackets from the ipv6 address because the method - // net.JoinHostPort() will add a second pair of square brackets. - host = squareBrackets.ReplaceAllString(host, "") - conf.Worker.PublicAddr = net.JoinHostPort(host, port) + if port == "" { + port = "9202" + } + conf.Worker.PublicAddr = util.JoinHostPort(host, port) return nil } diff --git a/internal/cmd/commands/connect/connect.go b/internal/cmd/commands/connect/connect.go index dbed3345df..aac30cac66 100644 --- a/internal/cmd/commands/connect/connect.go +++ b/internal/cmd/commands/connect/connect.go @@ -10,7 +10,6 @@ import ( "fmt" "io" "math" - "net" "net/netip" "os" "strconv" @@ -22,6 +21,7 @@ import ( apiproxy "github.com/hashicorp/boundary/api/proxy" "github.com/hashicorp/boundary/api/targets" "github.com/hashicorp/boundary/internal/cmd/base" + "github.com/hashicorp/boundary/internal/util" "github.com/mitchellh/cli" "github.com/posener/complete" "go.uber.org/atomic" @@ -476,14 +476,10 @@ func (c *Command) Run(args []string) (retCode int) { proxyAddr := clientProxy.ListenerAddress(context.Background()) var clientProxyHost, clientProxyPort string - clientProxyHost, clientProxyPort, err = net.SplitHostPort(proxyAddr) + clientProxyHost, clientProxyPort, err = util.SplitHostPort(proxyAddr) if err != nil { - if strings.Contains(err.Error(), "missing port") { - clientProxyHost = proxyAddr - } else { - c.PrintCliError(fmt.Errorf("error splitting listener addr: %w", err)) - return base.CommandCliError - } + c.PrintCliError(fmt.Errorf("error splitting listener addr: %w", err)) + return base.CommandCliError } c.sessInfo.Address = clientProxyHost @@ -605,15 +601,11 @@ func (c *Command) handleExec(clientProxy *apiproxy.ClientProxy, passthroughArgs addr := clientProxy.ListenerAddress(context.Background()) var host, port string var err error - host, port, err = net.SplitHostPort(addr) + host, port, err = util.SplitHostPort(addr) if err != nil { - if strings.Contains(err.Error(), "missing port") { - host = addr - } else { - c.PrintCliError(fmt.Errorf("Error splitting listener addr: %w", err)) - c.execCmdReturnValue.Store(int32(3)) - return - } + c.PrintCliError(fmt.Errorf("Error splitting listener addr: %w", err)) + c.execCmdReturnValue.Store(int32(3)) + return } var args []string diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 77bc225c69..3c0efc6b12 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "math/rand" - "net" "os" "runtime" "strings" @@ -27,6 +26,7 @@ import ( "github.com/hashicorp/boundary/internal/server" "github.com/hashicorp/boundary/internal/server/store" "github.com/hashicorp/boundary/internal/types/scope" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/hashicorp/go-secure-stdlib/strutil" "github.com/hashicorp/nodeenrollment" @@ -592,13 +592,10 @@ func (c *Command) Run(args []string) int { return base.CommandUserError } - host, port, err := net.SplitHostPort(c.flagHostAddress) + host, port, err := util.SplitHostPort(c.flagHostAddress) if err != nil { - if !strings.Contains(err.Error(), "missing port") { - c.UI.Error(fmt.Errorf("Invalid host address specified: %w", err).Error()) - return base.CommandUserError - } - host = c.flagHostAddress + c.UI.Error(fmt.Errorf("Invalid host address specified: %w", err).Error()) + return base.CommandUserError } if port != "" { c.UI.Error(`Port must not be specified as part of the dev host address`) diff --git a/internal/cmd/commands/server/server.go b/internal/cmd/commands/server/server.go index a57c3b8137..232e58bb1f 100644 --- a/internal/cmd/commands/server/server.go +++ b/internal/cmd/commands/server/server.go @@ -26,6 +26,7 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/event" "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-secure-stdlib/mlock" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -355,14 +356,10 @@ func (c *Command) Run(args []string) int { } } for _, upstream := range c.Config.Worker.InitialUpstreams { - host, _, err := net.SplitHostPort(upstream) + host, _, err := util.SplitHostPort(upstream) if err != nil { - if strings.Contains(err.Error(), globals.MissingPortErrStr) { - host = upstream - } else { - c.UI.Error(fmt.Errorf("Invalid worker upstream address %q: %w", upstream, err).Error()) - return base.CommandUserError - } + c.UI.Error(fmt.Errorf("Invalid worker upstream address %q: %w", upstream, err).Error()) + return base.CommandUserError } ip := net.ParseIP(host) if ip != nil { @@ -413,14 +410,10 @@ func (c *Command) Run(args []string) int { if purpose != "cluster" { continue } - host, _, err := net.SplitHostPort(ln.Address) + host, _, err := util.SplitHostPort(ln.Address) if err != nil { - if strings.Contains(err.Error(), globals.MissingPortErrStr) { - host = ln.Address - } else { - c.UI.Error(fmt.Errorf("Invalid cluster listener address %q: %w", ln.Address, err).Error()) - return base.CommandUserError - } + c.UI.Error(fmt.Errorf("Invalid cluster listener address %q: %w", ln.Address, err).Error()) + return base.CommandUserError } ip := net.ParseIP(host) if ip != nil { diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index 6b2dbbc1a4..b66ea720bc 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -15,7 +15,6 @@ import ( "net" "os" "reflect" - "regexp" "strconv" "strings" "time" @@ -103,6 +102,84 @@ listener "tcp" { purpose = "ops" tls_disable = true } +` + + devIpv6ControllerExtraConfig = ` +controller { + name = "dev-controller" + description = "A default controller created in dev mode" +} + +kms "aead" { + purpose = "root" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_root" +} + +kms "aead" { + purpose = "worker-auth" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_worker-auth" +} + +kms "aead" { + purpose = "bsr" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_bsr" +} + +kms "aead" { + purpose = "recovery" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_recovery" +} + +listener "tcp" { + address = "[::1]" + purpose = "api" + tls_disable = true + cors_enabled = true + cors_allowed_origins = ["*"] +} + +listener "tcp" { + address = "[::1]" + purpose = "cluster" +} + +listener "tcp" { + address = "[::1]" + purpose = "ops" + tls_disable = true +} +` + + devIpv6WorkerExtraConfig = ` +listener "tcp" { + address = "[::1]" + purpose = "proxy" +} + +worker { + name = "w_1234567890" + description = "A default worker created in dev mode" + public_addr = "[::1]" + initial_upstreams = ["[::1]"] + tags { + type = ["dev", "local"] + } +} + +kms "aead" { + purpose = "worker-auth-storage" + aead_type = "aes-gcm" + key = "%s" + key_id = "worker-auth-storage" +} ` devWorkerExtraConfig = ` @@ -133,10 +210,6 @@ kms "aead" { defaultCsp = "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; media-src 'self'; manifest-src 'self'; style-src-attr 'self'; frame-ancestors 'self'" ) -// This regular expression is used to find all instances of square brackets within a string. -// This regular expression is used to remove the square brackets from an IPv6 address. -var squareBrackets = regexp.MustCompile("\\[|\\]") - // Config is the configuration for the boundary controller type Config struct { *configutil.SharedConfig `hcl:"-"` @@ -378,15 +451,18 @@ type License struct { // WithAuditEventsEnabled, TestWithErrorEventsEnabled func DevWorker(opt ...Option) (*Config, error) { workerAuthStorageKey := DevKeyGeneration() + opts, err := getOpts(opt...) + if err != nil { + return nil, fmt.Errorf("error parsing options: %w", err) + } hclStr := fmt.Sprintf(devConfig+devWorkerExtraConfig, workerAuthStorageKey) + if opts.withIPv6Enabled { + hclStr = fmt.Sprintf(devConfig+devIpv6WorkerExtraConfig, workerAuthStorageKey) + } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) } - opts, err := getOpts(opt...) - if err != nil { - return nil, fmt.Errorf("error parsing options: %w", err) - } parsed.Eventing.AuditEnabled = opts.withAuditEventsEnabled parsed.Eventing.ObservationsEnabled = opts.withObservationsEnabled parsed.Eventing.SysEventsEnabled = opts.withSysEventsEnabled @@ -414,12 +490,20 @@ func DevKeyGeneration() string { // DevController is a Config that is used for dev mode of Boundary // controllers func DevController(opt ...Option) (*Config, error) { + opts, err := getOpts(opt...) + if err != nil { + return nil, fmt.Errorf("error parsing options: %w", err) + } + controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey) + if opts.withIPv6Enabled { + hclStr = fmt.Sprintf(devConfig+devIpv6ControllerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey) + } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -429,10 +513,6 @@ func DevController(opt ...Option) (*Config, error) { parsed.DevWorkerAuthKey = workerAuthKey parsed.DevBsrKey = bsrKey parsed.DevRecoveryKey = recoveryKey - opts, err := getOpts(opt...) - if err != nil { - return nil, fmt.Errorf("error parsing options: %w", err) - } parsed.Eventing.AuditEnabled = opts.withAuditEventsEnabled parsed.Eventing.ObservationsEnabled = opts.withObservationsEnabled parsed.Eventing.SysEventsEnabled = opts.withSysEventsEnabled @@ -440,13 +520,22 @@ func DevController(opt ...Option) (*Config, error) { return parsed, nil } -func DevCombined() (*Config, error) { +func DevCombined(opt ...Option) (*Config, error) { + opts, err := getOpts(opt...) + if err != nil { + return nil, fmt.Errorf("error parsing options: %w", err) + } + controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() workerAuthStorageKey := DevKeyGeneration() bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() + hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey, workerAuthStorageKey) + if opts.withIPv6Enabled { + hclStr = fmt.Sprintf(devConfig+devIpv6ControllerExtraConfig+devIpv6WorkerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey, workerAuthStorageKey) + } parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -1255,20 +1344,14 @@ func (c *Config) SetupControllerPublicClusterAddress(flagValue string) error { } } - host, port, err := net.SplitHostPort(c.Controller.PublicClusterAddr) + host, port, err := util.SplitHostPort(c.Controller.PublicClusterAddr) if err != nil { - if strings.Contains(err.Error(), "missing port") { - port = "9201" - host = c.Controller.PublicClusterAddr - } else { - return fmt.Errorf("Error splitting public cluster adddress host/port: %w", err) - } + return fmt.Errorf("Error splitting public cluster adddress host/port: %w", err) } - - // remove the square brackets from the ipv6 address because the method - // net.JoinHostPort() will add a second pair of square brackets. - host = squareBrackets.ReplaceAllString(host, "") - c.Controller.PublicClusterAddr = net.JoinHostPort(host, port) + if port == "" { + port = "9201" + } + c.Controller.PublicClusterAddr = util.JoinHostPort(host, port) return nil } @@ -1322,11 +1405,7 @@ func (c *Config) SetupWorkerInitialUpstreams() error { break } // Best effort see if it's a domain name and if not assume it must match - host, _, err := net.SplitHostPort(c.Worker.InitialUpstreams[0]) - if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { - err = nil - host = c.Worker.InitialUpstreams[0] - } + host, _, err := util.SplitHostPort(c.Worker.InitialUpstreams[0]) if err == nil { ip := net.ParseIP(host) if ip == nil { diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index 30449cc7ba..56f4d834b1 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -6,6 +6,7 @@ package config import ( "encoding/base64" "fmt" + "net" "net/http" "os" "testing" @@ -13,6 +14,7 @@ import ( "github.com/hashicorp/boundary/internal/event" "github.com/hashicorp/boundary/internal/ratelimit" + "github.com/hashicorp/boundary/internal/util" configutil "github.com/hashicorp/go-secure-stdlib/configutil/v2" "github.com/hashicorp/go-secure-stdlib/listenerutil" "github.com/hashicorp/go-secure-stdlib/parseutil" @@ -779,6 +781,101 @@ func TestDevWorkerRecordingStoragePath(t *testing.T) { } } +func TestDevControllerIpv6(t *testing.T) { + require, assert := require.New(t), assert.New(t) + // This test only validates that all listeners are utilizing an IPv6 address. + // Other dev controller configurations are validates in TestDevController. + actual, err := DevController(WithIPv6Enabled(true)) + require.NoError(err) + + // expected an error here because we purposely did not provide a port number + // to allow randomly assigned port values + _, _, err = net.SplitHostPort(actual.Controller.PublicClusterAddr) + require.Error(err) + + // assert the square brackets are removed from the host ipv6 address and that the port value is empty + publicAddr, port, err := util.SplitHostPort(actual.Controller.PublicClusterAddr) + require.NoError(err) + assert.Empty(port) + assert.Empty(publicAddr) + + require.NotEmpty(actual.Listeners) + for _, l := range actual.Listeners { + addr, _, err := util.SplitHostPort(l.Address) + require.NoError(err) + ip := net.ParseIP(addr) + assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) + assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) + } +} + +func TestDevWorkerIpv6(t *testing.T) { + require, assert := require.New(t), assert.New(t) + // This test only validates that all listeners are utilizing an IPv6 address. + // Other dev worker configurations are validates in TestDevWorker. + actual, err := DevWorker(WithIPv6Enabled(true)) + require.NoError(err) + + // expected an error here because we purposely did not provide a port number + // to allow randomly assigned port values + _, _, err = net.SplitHostPort(actual.Worker.PublicAddr) + require.Error(err) + + // assert the square brackets are removed from the worker ipv6 address and that the port value is empty + publicAddr, port, err := util.SplitHostPort(actual.Worker.PublicAddr) + require.NoError(err) + assert.Empty(port) + ip := net.ParseIP(publicAddr) + assert.NotNil(ip, "failed to parse worker public address") + assert.NotNil(ip.To16(), "worker public address is not IPv6 %s", actual.Worker.PublicAddr) + + require.NotEmpty(actual.Listeners) + for _, l := range actual.Listeners { + addr, _, err := util.SplitHostPort(l.Address) + require.NoError(err) + ip := net.ParseIP(addr) + assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) + assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) + } +} + +func TestDevCombinedIpv6(t *testing.T) { + require, assert := require.New(t), assert.New(t) + // This test only validates that all listeners are utilizing an IPv6 address. + actual, err := DevCombined(WithIPv6Enabled(true)) + require.NoError(err) + + // expected an error here because we purposely did not provide a port number + // to allow randomly assigned port values for the worker and controller + _, _, err = net.SplitHostPort(actual.Worker.PublicAddr) + require.Error(err) + _, _, err = net.SplitHostPort(actual.Controller.PublicClusterAddr) + require.Error(err) + + // assert the square brackets are removed from the host ipv6 address and that the port value is empty + publicAddr, port, err := util.SplitHostPort(actual.Worker.PublicAddr) + require.NoError(err) + assert.Empty(port) + ip := net.ParseIP(publicAddr) + assert.NotNil(ip, "failed to parse worker public address") + assert.NotNil(ip.To16(), "worker public address is not IPv6 %s", actual.Worker.PublicAddr) + + // assert the square brackets are removed from the controller ipv6 address and that the port value is empty + publicAddr, port, err = util.SplitHostPort(actual.Controller.PublicClusterAddr) + require.NoError(err) + assert.Empty(port) + assert.Empty(publicAddr) + + require.NotEmpty(actual.Listeners) + for _, l := range actual.Listeners { + addr, _, err := util.SplitHostPort(l.Address) + require.NoError(err) + ip := net.ParseIP(addr) + assert.NotNil(ip, "failed to parse listener address for %v", l.Purpose) + assert.NotNil(ip.To16(), "failed to convert address to IPv6 for %v, found %v", l.Purpose, addr) + } +} + func TestDevKeyGeneration(t *testing.T) { t.Parallel() dk := DevKeyGeneration() diff --git a/internal/cmd/config/options.go b/internal/cmd/config/options.go index aed401b7a3..e95564f786 100644 --- a/internal/cmd/config/options.go +++ b/internal/cmd/config/options.go @@ -35,6 +35,7 @@ type options struct { withSysEventsEnabled bool withAuditEventsEnabled bool withObservationsEnabled bool + withIPv6Enabled bool testWithErrorEventsEnabled bool } @@ -59,6 +60,12 @@ func getDefaultOptions() (options, error) { } opts.withObservationsEnabled = obs + ipv6, err := parseutil.ParseBool(os.Getenv("BOUNDARY_ENABLE_TEST_IPV6")) + if err != nil { + return opts, err + } + opts.withIPv6Enabled = ipv6 + errEvents, err := parseutil.ParseBool(os.Getenv("BOUNDARY_ENABLE_TEST_ERROR_EVENTS")) if err != nil { return opts, err @@ -92,6 +99,14 @@ func WithObservationsEnabled(enable bool) Option { } } +// WithIPv6Enabled provides an option for enabling network ipv6 addresses +func WithIPv6Enabled(enable bool) Option { + return func(o *options) error { + o.withIPv6Enabled = enable + return nil + } +} + // TestWithErrorEventsEnabled provides an option for enabling error events // during tests. func TestWithErrorEventsEnabled(_ testing.TB, enable bool) Option { diff --git a/internal/daemon/controller/handlers/targets/target_service.go b/internal/daemon/controller/handlers/targets/target_service.go index e05eeaec49..f6e92d28d1 100644 --- a/internal/daemon/controller/handlers/targets/target_service.go +++ b/internal/daemon/controller/handlers/targets/target_service.go @@ -42,6 +42,7 @@ import ( "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" "github.com/hashicorp/boundary/internal/types/subtypes" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets" fm "github.com/hashicorp/boundary/version" @@ -967,17 +968,10 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession "No host was discovered after checking target address and host sources.") } - // Ensure we don't have a port from the address, which would be unexpected - _, _, err = net.SplitHostPort(h) - switch { - case err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr): - // This is what we expect - case err != nil: + // Ensure we don't have a port from the address + _, err = util.ParseAddress(ctx, h) + if err != nil { return nil, errors.Wrap(ctx, err, op, errors.WithMsg("error when parsing the chosen endpoint host address")) - case err == nil: - return nil, handlers.ApiErrorWithCodeAndMessage( - codes.FailedPrecondition, - "Address specified for use unexpectedly contains a port.") } // Generate the endpoint URL diff --git a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go index 92274e83e1..836c6a28b7 100644 --- a/internal/daemon/controller/handlers/targets/tcp/target_service_test.go +++ b/internal/daemon/controller/handlers/targets/tcp/target_service_test.go @@ -4409,57 +4409,104 @@ func TestAuthorizeSession_Errors(t *testing.T) { assert.Equal(t, 1, num) v.RevokeToken(t, tok1) - workerExists := func(tar target.Target) (version uint32) { + workerExists := func(tar target.Target) target.Target { server.TestKmsWorker(t, conn, wrapper) - return tar.GetVersion() + return tar } - hostSetNoHostExists := func(tar target.Target) (version uint32) { + hostSetNoHostExists := func(tar target.Target) target.Target { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] - - tr, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ + _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - return tr.GetItem().GetVersion() + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } - hostExists := func(tar target.Target) (version uint32) { + hostExists := func(tar target.Target) target.Target { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - apiTar, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ + _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - repo, err := staticHostRepoFn() + hostRepo, err := staticHostRepoFn() + require.NoError(t, err) + _, _, err = hostRepo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) require.NoError(t, err) - _, _, err = repo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"}) + repo, err := repoFn() require.NoError(t, err) - return apiTar.GetItem().GetVersion() + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } - hostWithoutPort := func(tar target.Target) (version uint32) { + hostWithoutPort := func(tar target.Target) target.Target { hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] h := static.TestHosts(t, conn, hc.GetPublicId(), 1)[0] hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) - apiTar, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ + _, err := s.AddTargetHostSources(ctx, &pbs.AddTargetHostSourcesRequest{ + Id: tar.GetPublicId(), + Version: tar.GetVersion(), + HostSourceIds: []string{hs.GetPublicId()}, + }) + require.NoError(t, err) + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar + } + + ipv4HostWithHostPort := func(tar target.Target) target.Target { + hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] + h := static.TestHost(t, conn, hc.GetPublicId(), static.WithAddress("8.8.8.8:22")) + hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] + _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) + _, err := s.SetTargetHostSources(ctx, &pbs.SetTargetHostSourcesRequest{ + Id: tar.GetPublicId(), + Version: tar.GetVersion(), + HostSourceIds: []string{hs.GetPublicId()}, + }) + require.NoError(t, err) + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar + } + + ipv6HostWithHostPort := func(tar target.Target) target.Target { + hc := static.TestCatalogs(t, conn, proj.GetPublicId(), 1)[0] + h := static.TestHost(t, conn, hc.GetPublicId(), static.WithAddress("[2001:4860:4860:0:0:0:0:8888]:22")) + hs := static.TestSets(t, conn, hc.GetPublicId(), 1)[0] + _ = static.TestSetMembers(t, conn, hs.GetPublicId(), []*static.Host{h}) + _, err := s.SetTargetHostSources(ctx, &pbs.SetTargetHostSourcesRequest{ Id: tar.GetPublicId(), Version: tar.GetVersion(), HostSourceIds: []string{hs.GetPublicId()}, }) require.NoError(t, err) - return apiTar.GetItem().GetVersion() + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } - libraryExists := func(tar target.Target) (version uint32) { + libraryExists := func(tar target.Target) target.Target { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4474,17 +4521,21 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - tr, err := s.AddTargetCredentialSources(ctx, + _, err = s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - return tr.GetItem().GetVersion() + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } - misConfiguredlibraryExists := func(tar target.Target) (version uint32) { + misConfiguredlibraryExists := func(tar target.Target) target.Target { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4499,17 +4550,21 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - tr, err := s.AddTargetCredentialSources(ctx, + _, err = s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - return tr.GetItem().GetVersion() + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } - expiredTokenLibrary := func(tar target.Target) (version uint32) { + expiredTokenLibrary := func(tar target.Target) target.Target { credService, err := credentiallibraries.NewService(ctx, iamRepoFn, vaultCredRepoFn, 1000) require.NoError(t, err) clsResp, err := credService.CreateCredentialLibrary(ctx, &pbs.CreateCredentialLibraryRequest{Item: &credlibpb.CredentialLibrary{ @@ -4524,14 +4579,18 @@ func TestAuthorizeSession_Errors(t *testing.T) { }}) require.NoError(t, err) - tr, err := s.AddTargetCredentialSources(ctx, + _, err = s.AddTargetCredentialSources(ctx, &pbs.AddTargetCredentialSourcesRequest{ Id: tar.GetPublicId(), BrokeredCredentialSourceIds: []string{clsResp.GetItem().GetId()}, Version: tar.GetVersion(), }) require.NoError(t, err) - return tr.GetItem().GetVersion() + repo, err := repoFn() + require.NoError(t, err) + tar, err = repo.LookupTarget(ctx, tar.GetPublicId()) + require.NoError(t, err) + return tar } // Generate correlation Id and add it to the context @@ -4543,7 +4602,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { cases := []struct { name string ctx context.Context - setup []func(target.Target) uint32 + setup []func(target.Target) target.Target useTargetId bool wantErr bool wantErrContains string @@ -4552,70 +4611,100 @@ func TestAuthorizeSession_Errors(t *testing.T) { // This one must be run first since it relies on the DB not having any worker details name: "no worker", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{hostExists, libraryExists}, useTargetId: true, wantErrContains: "No workers are available to handle this session", }, { name: "success", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, useTargetId: true, }, { name: "no target", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, useTargetId: false, wantErrContains: "Resource not found", }, { name: "no host port", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostWithoutPort, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostWithoutPort, libraryExists}, useTargetId: true, }, { - name: "host port", + name: "ipv4 target address host port", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{ - workerExists, func(tcpTarget target.Target) uint32 { - tcpTarget.SetAddress("127.0.0.1:22") + setup: []func(tcpTarget target.Target) target.Target{ + workerExists, func(tcpTarget target.Target) target.Target { repo, err := repoFn() require.NoError(t, err) - tcpTarget, _, err = repo.UpdateTarget(ctx, tcpTarget, tcpTarget.GetVersion(), []string{"address"}) + n, err := repo.DeleteTarget(ctx, tcpTarget.GetPublicId()) require.NoError(t, err) - return tcpTarget.GetVersion() + assert.Equal(t, 1, n) + return tcp.TestTarget(ctx, t, conn, tcpTarget.GetProjectId(), tcpTarget.GetName(), target.WithAddress("127.0.0.1:22"), target.WithDefaultPort(22)) }, }, - wantErrContains: "Address specified for use unexpectedly contains a port", + wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", + useTargetId: true, + }, + { + name: "ipv6 target address host port", + ctx: ctxWithCor, + setup: []func(tcpTarget target.Target) target.Target{ + workerExists, func(tcpTarget target.Target) target.Target { + repo, err := repoFn() + require.NoError(t, err) + n, err := repo.DeleteTarget(ctx, tcpTarget.GetPublicId()) + require.NoError(t, err) + assert.Equal(t, 1, n) + return tcp.TestTarget(ctx, t, conn, tcpTarget.GetProjectId(), tcpTarget.GetName(), target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:22"), target.WithDefaultPort(22)) + }, + }, + wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", + useTargetId: true, + }, + { + name: "ipv4 static host port", + ctx: ctxWithCor, + setup: []func(tcpTarget target.Target) target.Target{ipv4HostWithHostPort}, + wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", + useTargetId: true, + }, + { + name: "ipv6 static host port", + ctx: ctxWithCor, + setup: []func(tcpTarget target.Target) target.Target{ipv6HostWithHostPort}, + wantErrContains: "error when parsing the chosen endpoint host address: unknown: error #0: address contains a port", useTargetId: true, }, { name: "no hosts", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostSetNoHostExists, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostSetNoHostExists, libraryExists}, useTargetId: true, wantErrContains: "No host sources or address found for given target", }, { name: "bad library configuration", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, misConfiguredlibraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, misConfiguredlibraryExists}, useTargetId: true, wantErrContains: "external system issue: error #3014: Error making API request", }, { name: "expired token library", ctx: ctxWithCor, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, expiredTokenLibrary}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, expiredTokenLibrary}, useTargetId: true, wantErrContains: "vault.newClient: invalid configuration", }, { name: "no correaltion id", ctx: ctx, - setup: []func(tcpTarget target.Target) uint32{workerExists, hostExists, libraryExists}, + setup: []func(tcpTarget target.Target) target.Target{workerExists, hostExists, libraryExists}, useTargetId: true, wantErrContains: "authorize session: missing correlation id", }, @@ -4626,8 +4715,7 @@ func TestAuthorizeSession_Errors(t *testing.T) { tar := tcp.TestTarget(ctx, t, conn, proj.GetPublicId(), fmt.Sprintf("test-%d", i), target.WithDefaultPort(22)) for _, fn := range tc.setup { - ver := fn(tar) - tar.SetVersion(ver) + tar = fn(tar) } id := tar.GetPublicId() diff --git a/internal/daemon/controller/testing.go b/internal/daemon/controller/testing.go index 41dc57d2ba..abf2e76759 100644 --- a/internal/daemon/controller/testing.go +++ b/internal/daemon/controller/testing.go @@ -503,6 +503,8 @@ type TestControllerOpts struct { WorkerAuthDebuggingEnabled *atomic.Bool DisableRateLimiting bool + + EnableIPv6 bool } func NewTestController(t testing.TB, opts *TestControllerOpts) *TestController { @@ -587,7 +589,8 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController, opts.Config = cfg case opts.Config == nil: - opts.Config, err = config.DevController() + cfgOpts := append([]config.Option{}, config.WithIPv6Enabled(true)) + opts.Config, err = config.DevController(cfgOpts...) if err != nil { t.Fatal(err) } diff --git a/internal/daemon/controller/testing_test.go b/internal/daemon/controller/testing_test.go index 57af31cb5d..52e0bc4eeb 100644 --- a/internal/daemon/controller/testing_test.go +++ b/internal/daemon/controller/testing_test.go @@ -7,7 +7,9 @@ import ( "bytes" "context" "io" + "net" "os" + "strings" "testing" "github.com/hashicorp/boundary/globals" @@ -99,3 +101,26 @@ func Test_TestController(t *testing.T) { assert.NotNil(ws.Bsr()) }) } + +func Test_TestControllerIPv6(t *testing.T) { + require, assert := require.New(t), assert.New(t) + c := NewTestController(t, &TestControllerOpts{ + EnableIPv6: true, + }) + require.NotNil(c) + validateIPv6 := func(addr, name string) { + host, _, err := net.SplitHostPort(addr) + require.NoError(err) + require.NotEmpty(host, "missing host") + ip := net.ParseIP(host) + assert.NotNil(ip, "failed to parse %s", name) + assert.NotNil(ip.To16(), "%s is not IPv6 %s", name, addr) + } + for _, addr := range c.ClusterAddrs() { + validateIPv6(addr, "cluster addr") + } + for _, addr := range c.ApiAddrs() { + addr = strings.ReplaceAll(addr, "http://", "") + validateIPv6(addr, "api addr") + } +} diff --git a/internal/daemon/worker/controller_connection.go b/internal/daemon/worker/controller_connection.go index 33bd766f4d..d766ae00c5 100644 --- a/internal/daemon/worker/controller_connection.go +++ b/internal/daemon/worker/controller_connection.go @@ -14,7 +14,6 @@ import ( "sync/atomic" "time" - "github.com/hashicorp/boundary/globals" "github.com/hashicorp/boundary/internal/cmd/base" "github.com/hashicorp/boundary/internal/daemon/cluster" "github.com/hashicorp/boundary/internal/daemon/cluster/handlers" @@ -50,14 +49,14 @@ func (w *Worker) StartControllerConnections() error { case strings.HasPrefix(addr, "/"): initialAddrs = append(initialAddrs, addr) default: - host, port, err := net.SplitHostPort(addr) - if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { - host, port, err = net.SplitHostPort(net.JoinHostPort(addr, "9201")) - } + host, port, err := util.SplitHostPort(addr) if err != nil { return fmt.Errorf("error parsing upstream address: %w", err) } - initialAddrs = append(initialAddrs, net.JoinHostPort(host, port)) + if port == "" { + port = "9201" + } + initialAddrs = append(initialAddrs, util.JoinHostPort(host, port)) } } diff --git a/internal/daemon/worker/testing.go b/internal/daemon/worker/testing.go index ad57f22b6c..db47dece74 100644 --- a/internal/daemon/worker/testing.go +++ b/internal/daemon/worker/testing.go @@ -236,6 +236,9 @@ type TestWorkerOpts struct { // Enable observation events EnableObservationEvents bool + // Enable IPv6 + EnableIPv6 bool + // Enable error events EnableErrorEvents bool } @@ -272,6 +275,7 @@ func NewTestWorker(t testing.TB, opts *TestWorkerOpts) *TestWorker { configOpts = append(configOpts, config.WithAuditEventsEnabled(opts.EnableAuditEvents)) configOpts = append(configOpts, config.WithSysEventsEnabled(opts.EnableSysEvents)) configOpts = append(configOpts, config.WithObservationsEnabled(opts.EnableObservationEvents)) + configOpts = append(configOpts, config.WithIPv6Enabled(opts.EnableIPv6)) configOpts = append(configOpts, config.TestWithErrorEventsEnabled(t, opts.EnableErrorEvents)) opts.Config, err = config.DevWorker(configOpts...) if err != nil { @@ -561,7 +565,7 @@ func NewTestMultihopWorkers(t testing.TB, // NewAuthorizedPkiTestWorker creates a new test worker with the provided upstreams // and creates it in the provided repo as an authorized worker. It returns // The TestWorker and it's boundary id. -func NewAuthorizedPkiTestWorker(t *testing.T, repo *server.Repository, name string, upstreams []string) (*TestWorker, string) { +func NewAuthorizedPkiTestWorker(t *testing.T, repo *server.Repository, name string, upstreams []string, opt ...config.Option) (*TestWorker, string) { t.Helper() logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, diff --git a/internal/daemon/worker/testing_test.go b/internal/daemon/worker/testing_test.go index 25ae99bdd0..5742bbefc2 100644 --- a/internal/daemon/worker/testing_test.go +++ b/internal/daemon/worker/testing_test.go @@ -209,6 +209,30 @@ func TestNewTestMultihopWorkers(t *testing.T) { require.NoError(t, c.WaitForNextWorkerStatusUpdate(childKmsWorker.Name())) } +func TestWorkerIPv6(t *testing.T) { + require, assert := require.New(t), assert.New(t) + w := NewTestWorker(t, &TestWorkerOpts{ + EnableIPv6: true, + }) + require.NotNil(w) + validateIPv6 := func(addr, name string) { + host, _, err := net.SplitHostPort(addr) + require.NoError(err) + require.NotEmpty(host, "missing host") + ip := net.ParseIP(host) + assert.NotNil(ip, "failed to parse %s", name) + assert.NotNil(ip.To16(), "%s is not IPv6 %s", name, addr) + } + for _, addr := range w.addrs { + validateIPv6(addr, "worker addr") + } + for _, addr := range w.ProxyAddrs() { + validateIPv6(addr, "proxy addr") + } + require.NotNil(w.Worker().proxyListener) + validateIPv6(w.Worker().proxyListener.ProxyListener.Addr().String(), "proxy listener addr") +} + func createTestCert(t *testing.T) ([]byte, ed25519.PublicKey, ed25519.PrivateKey) { pub, priv, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) diff --git a/internal/host/plugin/host_address_test.go b/internal/host/plugin/host_address_test.go index b1afb5dda5..599a4c9397 100644 --- a/internal/host/plugin/host_address_test.go +++ b/internal/host/plugin/host_address_test.go @@ -211,7 +211,7 @@ func TestHostIpAddress_Create(t *testing.T) { wantDbErr: true, }, { - name: "valid", + name: "valid-ipv4", args: args{ hostId: host1.GetPublicId(), address: "1.2.3.4", @@ -223,6 +223,64 @@ func TestHostIpAddress_Create(t *testing.T) { }, }, }, + { + name: "valid-ipv6", + args: args{ + hostId: host1.GetPublicId(), + address: "2001:4860:4860:0:0:0:0:8888", + }, + want: &host.IpAddress{ + IpAddress: &store.IpAddress{ + HostId: host1.GetPublicId(), + Address: "2001:4860:4860:0:0:0:0:8888", + }, + }, + }, + { + name: "valid-abbreviated-ipv6", + args: args{ + hostId: host1.GetPublicId(), + address: "2001:4860:4860::8887", + }, + want: &host.IpAddress{ + IpAddress: &store.IpAddress{ + HostId: host1.GetPublicId(), + Address: "2001:4860:4860::8887", + }, + }, + }, + { + name: "invalid-abbreviated-[ipv6]", + args: args{ + hostId: host1.GetPublicId(), + address: "[2001:4860:4860::8886]", + }, + wantNewErr: true, + }, + { + name: "invalid-[ipv6]", + args: args{ + hostId: host1.GetPublicId(), + address: "[2001:4860:4860:0:0:0:0:8885]", + }, + wantNewErr: true, + }, + { + name: "invalid-abbreviated-[ipv6]:port", + args: args{ + hostId: host1.GetPublicId(), + address: "[2001:4860:4860::8884]:80", + }, + wantNewErr: true, + }, + { + name: "invalid-[ipv6]:port", + args: args{ + hostId: host1.GetPublicId(), + address: "[2001:4860:4860:0:0:0:0:8883]:80", + }, + wantNewErr: true, + }, { name: "duplicate-name", args: args{ diff --git a/internal/host/static/host.go b/internal/host/static/host.go index 1fe420c3a3..ece1cf832b 100644 --- a/internal/host/static/host.go +++ b/internal/host/static/host.go @@ -32,8 +32,9 @@ type Host struct { // Name and description are the only valid options. All other options are // ignored. func NewHost(ctx context.Context, catalogId string, opt ...Option) (*Host, error) { + const op = "static.NewHost" if catalogId == "" { - return nil, errors.New(ctx, errors.InvalidParameter, "static.NewHost", "no catalog id") + return nil, errors.New(ctx, errors.InvalidParameter, op, "no catalog id") } opts := getOpts(opt...) diff --git a/internal/host/static/host_test.go b/internal/host/static/host_test.go index f26239c7da..db05ddcfc3 100644 --- a/internal/host/static/host_test.go +++ b/internal/host/static/host_test.go @@ -131,30 +131,30 @@ func TestHost_New(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - assert := assert.New(t) + require, assert := require.New(t), assert.New(t) got, err := NewHost(ctx, tt.args.catalogId, tt.args.opts...) if tt.wantCreateErr { - assert.Error(err) + require.Error(err) assert.Nil(got) - } else { - assert.NoError(err) - if assert.NotNil(got) { - assert.Emptyf(got.PublicId, "PublicId set") - assert.Equal(tt.want, got) - - id, err := newHostId(ctx) - assert.NoError(err) + return + } + require.NoError(err) + require.NotNil(got) + assert.Emptyf(got.PublicId, "PublicId set") + assert.Equal(tt.want, got) - tt.want.PublicId = id - got.PublicId = id + id, err := newHostId(ctx) + require.NoError(err) + tt.want.PublicId = id + got.PublicId = id - w := db.New(conn) - err2 := w.Create(ctx, got) - if tt.wantWriteErr { - assert.Error(err2) - } - } + w := db.New(conn) + dbWriteErr := w.Create(ctx, got) + if tt.wantWriteErr { + require.Error(dbWriteErr) + return } + require.NoError(dbWriteErr) }) } } diff --git a/internal/host/static/repository_host.go b/internal/host/static/repository_host.go index b4246fdf7f..acf4e970c5 100644 --- a/internal/host/static/repository_host.go +++ b/internal/host/static/repository_host.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/boundary/internal/errors" "github.com/hashicorp/boundary/internal/kms" "github.com/hashicorp/boundary/internal/oplog" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-dbw" ) @@ -44,9 +45,10 @@ func (r *Repository) CreateHost(ctx context.Context, projectId string, h *Host, if projectId == "" { return nil, errors.New(ctx, errors.InvalidParameter, op, "no project id") } - h.Address = strings.TrimSpace(h.Address) - if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { - return nil, errors.New(ctx, errors.InvalidAddress, op, "invalid address") + var err error + h.Address, err = util.ParseAddress(ctx, h.Address) + if err != nil { + return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) } h = h.clone() @@ -138,9 +140,10 @@ func (r *Repository) UpdateHost(ctx context.Context, projectId string, h *Host, case strings.EqualFold("Name", f): case strings.EqualFold("Description", f): case strings.EqualFold("Address", f): - h.Address = strings.TrimSpace(h.Address) - if len(h.Address) < MinHostAddressLength || len(h.Address) > MaxHostAddressLength { - return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidAddress, op, "invalid address") + var err error + h.Address, err = util.ParseAddress(ctx, h.Address) + if err != nil { + return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) } default: return nil, db.NoRowsAffected, errors.New(ctx, errors.InvalidFieldMask, op, fmt.Sprintf("invalid field mask: %s", f)) diff --git a/internal/host/static/repository_host_test.go b/internal/host/static/repository_host_test.go index 88056ba1c2..cbec7485d1 100644 --- a/internal/host/static/repository_host_test.go +++ b/internal/host/static/repository_host_test.go @@ -69,6 +69,21 @@ func TestRepository_CreateHost(t *testing.T) { }, wantIsErr: errors.InvalidParameter, }, + { + name: "valid-dns-name", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "www.google.com", + }, + }, + want: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "www.google.com", + }, + }, + }, { name: "valid-ipv4-address", in: &Host{ @@ -84,6 +99,16 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, + { + name: "invalid-ipv4-address-with-port", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "127.0.0.1:80", + }, + }, + wantIsErr: errors.InvalidAddress, + }, { name: "valid-abbreviated-ipv6-address", in: &Host{ @@ -99,6 +124,16 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, + { + name: "invalid-abbreviated-ipv6-address-with-port", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860::8888]:80", + }, + }, + wantIsErr: errors.InvalidAddress, + }, { name: "valid-ipv6-address", in: &Host{ @@ -114,6 +149,46 @@ func TestRepository_CreateHost(t *testing.T) { }, }, }, + { + name: "invalid-ipv6-address-with-port", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + }, + wantIsErr: errors.InvalidAddress, + }, + { + name: "valid-abbreviated-[ipv6]-address", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860::8888]", + }, + }, + want: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860::8888]", + }, + }, + }, + { + name: "valid-[ipv6]-address", + in: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860:0:0:0:0:8888]", + }, + }, + want: &Host{ + Host: &store.Host{ + CatalogId: catalog.PublicId, + Address: "[2001:4860:4860:0:0:0:0:8888]", + }, + }, + }, { name: "valid-with-name", in: &Host{ @@ -574,6 +649,22 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, + { + name: "change-dns-name", + orig: &Host{ + Host: &store.Host{ + Address: "www.google.com", + }, + }, + chgFn: changeAddress("www.hashicorp.com"), + masks: []string{"Address"}, + want: &Host{ + Host: &store.Host{ + Address: "www.hashicorp.com", + }, + }, + wantCount: 1, + }, { name: "change-ipv4-address", orig: &Host{ @@ -590,6 +681,39 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, + { + name: "change-invalid-ipv4-address", + orig: &Host{ + Host: &store.Host{ + Address: "127.0.0.1", + }, + }, + chgFn: changeAddress("10.0.0.1:80"), + masks: []string{"Address"}, + wantIsErr: errors.InvalidAddress, + }, + { + name: "change-invalid-abbreviated-ipv6-address", + orig: &Host{ + Host: &store.Host{ + Address: "127.0.0.1", + }, + }, + chgFn: changeAddress("[2001:4860:4860::8888]:80"), + masks: []string{"Address"}, + wantIsErr: errors.InvalidAddress, + }, + { + name: "change-invalid-ipv6-address", + orig: &Host{ + Host: &store.Host{ + Address: "127.0.0.1", + }, + }, + chgFn: changeAddress("[2001:4860:4860:0:0:0:0:8888]:80"), + masks: []string{"Address"}, + wantIsErr: errors.InvalidAddress, + }, { name: "change-abbreviated-ipv6-address", orig: &Host{ @@ -622,6 +746,38 @@ func TestRepository_UpdateHost(t *testing.T) { }, wantCount: 1, }, + { + name: "change-abbreviated-[ipv6]-address", + orig: &Host{ + Host: &store.Host{ + Address: "127.0.0.1", + }, + }, + chgFn: changeAddress("[2001:4860:4860::8888]"), + masks: []string{"Address"}, + want: &Host{ + Host: &store.Host{ + Address: "[2001:4860:4860::8888]", + }, + }, + wantCount: 1, + }, + { + name: "change-[ipv6]-address", + orig: &Host{ + Host: &store.Host{ + Address: "127.0.0.1", + }, + }, + chgFn: changeAddress("[2001:4860:4860:0:0:0:0:8888]"), + masks: []string{"Address"}, + want: &Host{ + Host: &store.Host{ + Address: "[2001:4860:4860:0:0:0:0:8888]", + }, + }, + wantCount: 1, + }, { name: "change-short-address", orig: &Host{ diff --git a/internal/host/static/testing.go b/internal/host/static/testing.go index 0e34bb7603..a3dc7b1d58 100644 --- a/internal/host/static/testing.go +++ b/internal/host/static/testing.go @@ -37,6 +37,30 @@ func TestCatalogs(t testing.TB, conn *db.DB, projectId string, count int) []*Hos return cats } +// TestHost creates a static host to the provided DB with the provided catalog id. +// The catalog must have been created previously. If any errors are encountered +// during the creation of the host, the test will fail. +func TestHost(t testing.TB, conn *db.DB, catalogId string, opt ...Option) *Host { + t.Helper() + ctx := context.Background() + assert := assert.New(t) + + host, err := NewHost(ctx, catalogId, opt...) + assert.NoError(err) + assert.NotNil(host) + + id, err := newHostId(ctx) + assert.NoError(err) + assert.NotEmpty(id) + host.PublicId = id + + w := db.New(conn) + err2 := w.Create(ctx, host) + assert.NoError(err2) + + return host +} + // TestHosts creates count number of static hosts to the provided DB // with the provided catalog id. The catalog must have been created previously. // If any errors are encountered during the creation of the host, the test will fail. diff --git a/internal/session/connection.go b/internal/session/connection.go index b4697ad7f9..3941b34904 100644 --- a/internal/session/connection.go +++ b/internal/session/connection.go @@ -5,6 +5,7 @@ package session import ( "context" + "net" "github.com/hashicorp/boundary/internal/db" "github.com/hashicorp/boundary/internal/db/timestamp" @@ -185,5 +186,14 @@ func (c *Connection) validateNewConnection(ctx context.Context) error { if c.UserClientIp == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing user client ip") } + if ip := net.ParseIP(c.ClientTcpAddress); ip == nil { + return errors.New(ctx, errors.InvalidParameter, op, "given client tcp address is not an ip address") + } + if ip := net.ParseIP(c.EndpointTcpAddress); ip == nil { + return errors.New(ctx, errors.InvalidParameter, op, "given endpoint tcp address is not an ip address") + } + if ip := net.ParseIP(c.UserClientIp); ip == nil { + return errors.New(ctx, errors.InvalidParameter, op, "given user client ip is not an ip address") + } return nil } diff --git a/internal/session/connection_test.go b/internal/session/connection_test.go index 0dbe2f8c93..b5f515b1ad 100644 --- a/internal/session/connection_test.go +++ b/internal/session/connection_test.go @@ -31,23 +31,24 @@ func TestConnection_Create(t *testing.T) { userClientIp string } tests := []struct { - name string - args args - want *Connection - wantErr bool - wantIsErr errors.Code - create bool - wantCreateErr bool + name string + args args + want *Connection + wantErr bool + wantIsErr errors.Code + create bool + wantCreateErr bool + expectedErrMsg string }{ { - name: "valid", + name: "valid-ipv4", args: args{ sessionId: s.PublicId, clientTcpAddress: "127.0.0.1", clientTcpPort: 22, endpointTcpAddress: "127.0.0.1", endpointTcpPort: 2222, - userClientIp: "::1", + userClientIp: "127.0.0.2", }, want: &Connection{ SessionId: s.PublicId, @@ -55,10 +56,134 @@ func TestConnection_Create(t *testing.T) { ClientTcpPort: 22, EndpointTcpAddress: "127.0.0.1", EndpointTcpPort: 2222, - UserClientIp: "::1", + UserClientIp: "127.0.0.2", }, create: true, }, + { + name: "valid-ipv6", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860:0:0:0:0:8885", + }, + want: &Connection{ + SessionId: s.PublicId, + ClientTcpAddress: "2001:4860:4860:0:0:0:0:8887", + ClientTcpPort: 22, + EndpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", + EndpointTcpPort: 2222, + UserClientIp: "2001:4860:4860:0:0:0:0:8885", + }, + create: true, + }, + { + name: "valid-abbreviated-ipv6", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860::8887", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860::8886", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860::8885", + }, + want: &Connection{ + SessionId: s.PublicId, + ClientTcpAddress: "2001:4860:4860::8887", + ClientTcpPort: 22, + EndpointTcpAddress: "2001:4860:4860::8886", + EndpointTcpPort: 2222, + UserClientIp: "2001:4860:4860::8885", + }, + create: true, + }, + { + name: "invalid-[ipv6]-client-tcp-address", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "[2001:4860:4860:0:0:0:0:8887]", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860:0:0:0:0:8885", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given client tcp address is not an ip address", + }, + { + name: "invalid-[ipv6]-endpoint-tcp-address", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", + clientTcpPort: 22, + endpointTcpAddress: "[2001:4860:4860:0:0:0:0:8886]", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860:0:0:0:0:8885", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given endpoint tcp address is not an ip address", + }, + { + name: "invalid-[ipv6]-user-client-ip", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860:0:0:0:0:8887", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860:0:0:0:0:8886", + endpointTcpPort: 2222, + userClientIp: "[2001:4860:4860:0:0:0:0:8885]", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given user client ip is not an ip address", + }, + { + name: "invalid-abbreviated-[ipv6]-client-tcp-address", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "[2001:4860:4860::8887]", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860::8886", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860::8885", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given client tcp address is not an ip address", + }, + { + name: "invalid-abbreviated-[ipv6]-endpoint-tcp-address", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860::8887", + clientTcpPort: 22, + endpointTcpAddress: "[2001:4860:4860::8886]", + endpointTcpPort: 2222, + userClientIp: "2001:4860:4860::8885", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given endpoint tcp address is not an ip address", + }, + { + name: "invalid-abbreviated-[ipv6]-user-client-ip", + args: args{ + sessionId: s.PublicId, + clientTcpAddress: "2001:4860:4860::8887", + clientTcpPort: 22, + endpointTcpAddress: "2001:4860:4860::8886", + endpointTcpPort: 2222, + userClientIp: "[2001:4860:4860::8885]", + }, + wantErr: true, + wantIsErr: errors.InvalidParameter, + expectedErrMsg: "given user client ip is not an ip address", + }, { name: "empty-session-id", args: args{ @@ -147,6 +272,9 @@ func TestConnection_Create(t *testing.T) { if tt.wantErr { require.Error(err) assert.True(errors.Match(errors.T(tt.wantIsErr), err)) + if tt.expectedErrMsg != "" { + assert.ErrorContains(err, tt.expectedErrMsg) + } return } require.NoError(err) diff --git a/internal/session/session.go b/internal/session/session.go index 6cbf75fb60..5f8b7b9994 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -472,13 +472,9 @@ func newCert(ctx context.Context, jobId string, addresses []string, exp time.Tim for _, addr := range addresses { // First ensure we aren't looking at ports, regardless of IP or not - host, _, err := net.SplitHostPort(addr) + host, _, err := util.SplitHostPort(addr) if err != nil { - if strings.Contains(err.Error(), "missing port") { - host = addr - } else { - return nil, nil, errors.Wrap(ctx, err, op) - } + return nil, nil, errors.Wrap(ctx, err, op) } // Now figure out if it's an IP address or not. If ParseIP likes it, add // to IP SANs. Otherwise DNS SANs. diff --git a/internal/target/repository.go b/internal/target/repository.go index c91624dba5..d1ec66708c 100644 --- a/internal/target/repository.go +++ b/internal/target/repository.go @@ -22,6 +22,7 @@ import ( "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/resource" "github.com/hashicorp/boundary/internal/types/scope" + "github.com/hashicorp/boundary/internal/util" "github.com/hashicorp/go-dbw" ) @@ -550,7 +551,11 @@ func (r *Repository) CreateTarget(ctx context.Context, target Target, opt ...Opt var address *Address var err error if t.GetAddress() != "" { - t.SetAddress(strings.TrimSpace(t.GetAddress())) + host, err := util.ParseAddress(ctx, t.GetAddress()) + if err != nil { + return nil, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) + } + t.SetAddress(host) address, err = NewAddress(ctx, t.GetPublicId(), t.GetAddress()) if err != nil { return nil, errors.Wrap(ctx, err, op) @@ -650,7 +655,6 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui return nil, db.NoRowsAffected, err } - var addressEndpoint string for _, f := range fieldMaskPaths { switch { case strings.EqualFold("name", f): @@ -663,8 +667,6 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui case strings.EqualFold("egressworkerfilter", f): case strings.EqualFold("ingressworkerfilter", f): case strings.EqualFold("address", f): - target.SetAddress(strings.TrimSpace(target.GetAddress())) - addressEndpoint = target.GetAddress() case strings.EqualFold("storagebucketid", f): case strings.EqualFold("enablesessionrecording", f): default: @@ -698,12 +700,19 @@ func (r *Repository) UpdateTarget(ctx context.Context, target Target, version ui // The Address field is not a part of the target schema in the database. It // is a part of a different table called target_address, which is why the // Address field must be filtered out of the dbMask & nullFields slices. + var addressEndpoint string var updateAddress, deleteAddress bool var filteredDbMask, filteredNullFields []string for _, f := range dbMask { switch { case strings.EqualFold("Address", f): updateAddress = true + address, err := util.ParseAddress(ctx, target.GetAddress()) + if err != nil { + return nil, db.NoRowsAffected, errors.Wrap(ctx, err, op, errors.WithCode(errors.InvalidAddress), errors.WithMsg("invalid address")) + } + target.SetAddress(address) + addressEndpoint = target.GetAddress() default: filteredDbMask = append(filteredDbMask, f) } diff --git a/internal/target/tcp/repository_tcp_target_test.go b/internal/target/tcp/repository_tcp_target_test.go index 6341c86dbf..807578e318 100644 --- a/internal/target/tcp/repository_tcp_target_test.go +++ b/internal/target/tcp/repository_tcp_target_test.go @@ -70,6 +70,23 @@ func TestRepository_CreateTarget(t *testing.T) { }, wantErr: false, }, + { + name: "with-dns-name", + args: args{ + target: func() *tcp.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-dns-name"), + target.WithDescription("with-dns-name"), + target.WithDefaultPort(uint32(22)), + target.WithAddress("www.google.com"), + ) + require.NoError(t, err) + return target.(*tcp.Target) + }(), + }, + wantErr: false, + wantAddress: "www.google.com", + }, { name: "with-ipv4-address", args: args{ @@ -83,7 +100,24 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, + wantErr: false, + wantAddress: "8.8.8.8", + }, + { + name: "with-invalid-ipv4-address-with-port", + args: args{ + target: func() target.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-invalid-ipv4-address-with-port"), + target.WithDescription("with-invalid-ipv4-address-with-port"), + target.WithDefaultPort(80), + target.WithAddress("8.8.8.8:80")) + require.NoError(t, err) + return target + }(), + }, + wantErr: true, + wantIsError: errors.InvalidAddress, }, { name: "with-abbreviated-ipv6-address", @@ -98,7 +132,8 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, + wantErr: false, + wantAddress: "2001:4860:4860::8888", }, { name: "with-ipv6-address", @@ -113,7 +148,72 @@ func TestRepository_CreateTarget(t *testing.T) { return target }(), }, - wantErr: false, + wantErr: false, + wantAddress: "2001:4860:4860::8888", + }, + { + name: "with-abbreviated-[ipv6]-address", + args: args{ + target: func() target.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-abbreviated-[ipv6]-address"), + target.WithDescription("with-abbreviated-[ipv6]-address"), + target.WithDefaultPort(80), + target.WithAddress("[2001:4860:4860::8888]")) + require.NoError(t, err) + return target + }(), + }, + wantErr: false, + wantAddress: "2001:4860:4860::8888", + }, + { + name: "with-invalid-abbreviated-[ipv6]-address-with-port", + args: args{ + target: func() target.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-invalid-abbreviated-[ipv6]-address-with-port"), + target.WithDescription("with-invalid-abbreviated-[ipv6]-address-with-port"), + target.WithDefaultPort(80), + target.WithAddress("[2001:4860:4860::8888]:80")) + require.NoError(t, err) + return target + }(), + }, + wantErr: true, + wantIsError: errors.InvalidAddress, + }, + { + name: "with-[ipv6]-address", + args: args{ + target: func() target.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-[ipv6]-address"), + target.WithDescription("with-[ipv6]-address"), + target.WithDefaultPort(80), + target.WithAddress("[2001:4860:4860:0:0:0:0:8888]")) + require.NoError(t, err) + return target + }(), + }, + wantErr: false, + wantAddress: "2001:4860:4860:0:0:0:0:8888", + }, + { + name: "with-invalid-[ipv6]-address-with-port", + args: args{ + target: func() target.Target { + target, err := target.New(ctx, tcp.Subtype, proj.PublicId, + target.WithName("with-invalid-[ipv6]-address-with-port"), + target.WithDescription("with-invalid-[ipv6]-address-with-port"), + target.WithDefaultPort(80), + target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:80")) + require.NoError(t, err) + return target + }(), + }, + wantErr: true, + wantIsError: errors.InvalidAddress, }, { name: "with-address-whitespace", @@ -388,7 +488,6 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantRowsUpdate: 1, wantHostSources: true, }, - { name: "valid-ipv4-address", args: args{ @@ -401,6 +500,20 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, + wantAddress: "8.8.8.8", + }, + { + name: "invalid-ipv4-address-with-port", + args: args{ + name: "invalid-ipv4-address-with-port" + id, + fieldMaskPaths: []string{"Name", "Address"}, + ProjectId: proj.PublicId, + address: "8.8.8.8:80", + }, + newProjectId: proj.PublicId, + wantErr: true, + wantIsError: errors.InvalidAddress, + wantErrMsg: "invalid address", }, { name: "valid-abbreviated-ipv6-address", @@ -414,6 +527,7 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, + wantAddress: "2001:4860:4860::8888", }, { name: "valid-ipv6-address", @@ -427,6 +541,61 @@ func TestRepository_UpdateTcpTarget(t *testing.T) { wantErr: false, wantRowsUpdate: 1, wantHostSources: false, + wantAddress: "2001:4860:4860::8888", + }, + { + name: "valid-abbreviated-[ipv6]-address", + args: args{ + name: "valid-abbreviated-[ipv6]-address" + id, + fieldMaskPaths: []string{"Name", "Address"}, + ProjectId: proj.PublicId, + address: "[2001:4860:4860::8888]", + }, + newProjectId: proj.PublicId, + wantErr: false, + wantRowsUpdate: 1, + wantHostSources: false, + wantAddress: "2001:4860:4860::8888", + }, + { + name: "invalid-abbreviated-[ipv6]-address-with-port", + args: args{ + name: "invalid-abbreviated-[ipv6]-address-with-port" + id, + fieldMaskPaths: []string{"Name", "Address"}, + ProjectId: proj.PublicId, + address: "[2001:4860:4860::8888]:80", + }, + newProjectId: proj.PublicId, + wantErr: true, + wantIsError: errors.InvalidAddress, + wantErrMsg: "invalid address", + }, + { + name: "valid-[ipv6]-address", + args: args{ + name: "valid-[ipv6]-address" + id, + fieldMaskPaths: []string{"Name", "Address"}, + ProjectId: proj.PublicId, + address: "[2001:4860:4860:0:0:0:0:8888]", + }, + newProjectId: proj.PublicId, + wantErr: false, + wantRowsUpdate: 1, + wantHostSources: false, + wantAddress: "2001:4860:4860:0:0:0:0:8888", + }, + { + name: "invalid-[ipv6]-address-with-port", + args: args{ + name: "invalid-[ipv6]-address-with-port" + id, + fieldMaskPaths: []string{"Name", "Address"}, + ProjectId: proj.PublicId, + address: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + newProjectId: proj.PublicId, + wantErr: true, + wantIsError: errors.InvalidAddress, + wantErrMsg: "invalid address", }, { name: "null-address", diff --git a/internal/target/tcp/testing_test.go b/internal/target/tcp/testing_test.go index 757657cc1e..24dc2a8b04 100644 --- a/internal/target/tcp/testing_test.go +++ b/internal/target/tcp/testing_test.go @@ -19,39 +19,116 @@ import ( ) func Test_TestTcpTarget(t *testing.T) { - require := require.New(t) + t.Parallel() + conn, _ := db.TestSetup(t, "postgres") rw := db.New(conn) wrapper := db.TestWrapper(t) testKms := kms.TestKms(t, conn, wrapper) iamRepo := iam.TestRepo(t, conn, wrapper) - _, proj := iam.TestScopes(t, iamRepo) - ctx := context.Background() repo, err := target.NewRepository(ctx, rw, rw, testKms) - require.NoError(err) + require.NoError(t, err) - cats := static.TestCatalogs(t, conn, proj.PublicId, 1) - hsets := static.TestSets(t, conn, cats[0].GetPublicId(), 2) - var sets []string - for _, s := range hsets { - sets = append(sets, s.PublicId) - } - name := tcp.TestTargetName(t, proj.PublicId) - tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, target.WithHostSources(sets)) - require.NotNil(t) - require.NotEmpty(tar.GetPublicId()) - require.Equal(name, tar.GetName()) + t.Run("with-host-source", func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + _, proj := iam.TestScopes(t, iamRepo) + cats := static.TestCatalogs(t, conn, proj.PublicId, 1) + hsets := static.TestSets(t, conn, cats[0].GetPublicId(), 2) + var sets []string + for _, s := range hsets { + sets = append(sets, s.PublicId) + } + name := tcp.TestTargetName(t, proj.PublicId) + tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, target.WithHostSources(sets)) + require.NotNil(t) + assert.NotEmpty(tar.GetPublicId()) + assert.Equal(name, tar.GetName()) + assert.Empty(tar.GetAddress()) - foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) - foundSources := foundTarget.GetHostSources() + foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId()) + require.NoError(err) - require.NoError(err) - foundIds := make([]string, 0, len(foundSources)) - for _, s := range foundSources { - foundIds = append(foundIds, s.Id()) + foundSources := foundTarget.GetHostSources() + foundIds := make([]string, 0, len(foundSources)) + for _, s := range foundSources { + foundIds = append(foundIds, s.Id()) + } + assert.ElementsMatch(sets, foundIds) + }) + + tests := []struct { + name string + opt []target.Option + wantAddress string + }{ + { + name: "dns-name", + opt: []target.Option{ + target.WithAddress("www.google.com"), + }, + wantAddress: "www.google.com", + }, + { + name: "ipv4-address", + opt: []target.Option{ + target.WithAddress("8.8.8.8"), + }, + wantAddress: "8.8.8.8", + }, + { + name: "ipv4-address-with-port", + opt: []target.Option{ + target.WithAddress("8.8.8.8:80"), + }, + wantAddress: "8.8.8.8:80", + }, + { + name: "ipv6-address", + opt: []target.Option{ + target.WithAddress("2001:4860:4860:0:0:0:0:8888"), + }, + wantAddress: "2001:4860:4860:0:0:0:0:8888", + }, + { + name: "ipv6-address-with-port", + opt: []target.Option{ + target.WithAddress("[2001:4860:4860:0:0:0:0:8888]:80"), + }, + wantAddress: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + { + name: "abbreviated-ipv6-address", + opt: []target.Option{ + target.WithAddress("2001:4860:4860::8888"), + }, + wantAddress: "2001:4860:4860::8888", + }, + { + name: "abbreviated-ipv6-address-with-port", + opt: []target.Option{ + target.WithAddress("[2001:4860:4860::8888]:80"), + }, + wantAddress: "[2001:4860:4860::8888]:80", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + _, proj := iam.TestScopes(t, iamRepo) + name := tcp.TestTargetName(t, proj.PublicId) + tar := tcp.TestTarget(ctx, t, conn, proj.PublicId, name, tt.opt...) + require.NotNil(t) + assert.NotEmpty(tar.GetPublicId()) + assert.Equal(name, tar.GetName()) + if tt.wantAddress != "" { + assert.Equal(tt.wantAddress, tar.GetAddress()) + assert.Empty(tar.GetHostSources()) + } else { + assert.Empty(tar.GetAddress()) + } + }) } - require.ElementsMatch(sets, foundIds) } func Test_TestCredentialLibrary(t *testing.T) { diff --git a/internal/tests/api/targets/target_test.go b/internal/tests/api/targets/target_test.go index 72a6bb1ea9..d00cc28d95 100644 --- a/internal/tests/api/targets/target_test.go +++ b/internal/tests/api/targets/target_test.go @@ -383,7 +383,7 @@ func TestTarget_AddressMutualExclusiveRelationship(t *testing.T) { targets.WithName("test-address"), targets.WithAddress("[::1]"), targets.WithTcpTargetDefaultPort(22)) require.NoError(t, err) require.NotNil(t, targetResp) - require.Equal(t, "[::1]", targetResp.GetItem().Address) + require.Equal(t, "::1", targetResp.GetItem().Address) // Setup host catalog, host set, & host resources hc, err := hostcatalogs.NewClient(client).Create(tc.Context(), "static", proj.GetPublicId()) @@ -477,7 +477,7 @@ func TestTarget_HostSourceMutualExclusiveRelationship(t *testing.T) { updateResp, err = tClient.Update(tc.Context(), targetId, version, targets.WithAddress("[::1]")) require.NoError(t, err) require.NotNil(t, updateResp) - require.Equal(t, "[::1]", updateResp.GetItem().Address) + require.Equal(t, "::1", updateResp.GetItem().Address) require.Empty(t, updateResp.GetItem().HostSourceIds) } @@ -491,24 +491,29 @@ func TestCreateTarget_DirectlyAttachedAddress(t *testing.T) { tClient := targets.NewClient(client) tests := []struct { - name string - address string + name string + address string + expectedAddress string }{ { - name: "target-ipv4-address", - address: "127.0.0.1", + name: "target-ipv4-address", + address: "127.0.0.1", + expectedAddress: "127.0.0.1", }, { - name: "target-ipv6-address", - address: "[2001:4860:4860:0:0:0:0:8888]", + name: "target-ipv6-address", + address: "[2001:4860:4860:0:0:0:0:8888]", + expectedAddress: "2001:4860:4860:0:0:0:0:8888", }, { - name: "target-abbreviated-ipv6-address", - address: "[2001:4860:4860::8888]", + name: "target-abbreviated-ipv6-address", + address: "[2001:4860:4860::8888]", + expectedAddress: "2001:4860:4860::8888", }, { - name: "target-dns-address", - address: "null", + name: "target-dns-address", + address: "www.google.com", + expectedAddress: "www.google.com", }, } for _, tt := range tests { @@ -518,14 +523,14 @@ func TestCreateTarget_DirectlyAttachedAddress(t *testing.T) { targets.WithName(tt.name), targets.WithAddress(tt.address), targets.WithTcpTargetDefaultPort(22)) require.NoError(err) require.NotNil(createResp) - assert.Equal(tt.address, createResp.GetItem().Address) + assert.Equal(tt.expectedAddress, createResp.GetItem().Address) targetId := createResp.GetItem().Id version := createResp.GetItem().Version readResp, err := tClient.Read(tc.Context(), targetId) require.NoError(err) require.NotNil(readResp) - assert.Equal(tt.address, readResp.GetItem().Address) + assert.Equal(tt.expectedAddress, readResp.GetItem().Address) updateResp, err := tClient.Update(tc.Context(), targetId, version, targets.DefaultAddress()) require.NoError(err) diff --git a/internal/tests/cluster/ipv6_listener_test.go b/internal/tests/cluster/ipv6_listener_test.go index 8274de0e16..9d45422193 100644 --- a/internal/tests/cluster/ipv6_listener_test.go +++ b/internal/tests/cluster/ipv6_listener_test.go @@ -5,8 +5,8 @@ package cluster import ( "context" + "sync" "testing" - "time" "github.com/hashicorp/boundary/api" "github.com/hashicorp/boundary/api/scopes" @@ -19,58 +19,73 @@ import ( ) func TestIPv6Listener(t *testing.T) { + t.Parallel() require := require.New(t) logger := hclog.New(&hclog.LoggerOptions{ Level: hclog.Trace, }) - conf, err := config.DevController() + conf, err := config.DevController(config.WithIPv6Enabled(true)) require.NoError(err) - for _, l := range conf.Listeners { - switch l.Purpose[0] { - case "api": - l.Address = "[::1]:9200" - - case "cluster": - l.Address = "[::1]:9201" - } - } - c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, Logger: logger.Named("c1"), }) defer c1.Shutdown() - helper.ExpectWorkers(t, c1) + c2 := c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ + Config: conf, + Logger: c1.Config().Logger.ResetNamed("c2"), + }) + defer c2.Shutdown() - wconf, err := config.DevWorker() + wg := new(sync.WaitGroup) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2) + }() + wg.Wait() + + wconf, err := config.DevWorker(config.WithIPv6Enabled(true)) require.NoError(err) w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ Config: wconf, WorkerAuthKms: c1.Config().WorkerAuthKms, - InitialUpstreams: c1.ClusterAddrs(), + InitialUpstreams: append(c1.ClusterAddrs(), c2.ClusterAddrs()...), Logger: logger.Named("w1"), }) defer w1.Shutdown() - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1) - - c2 := c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ - Logger: c1.Config().Logger.ResetNamed("c2"), - }) - defer c2.Shutdown() - - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c2, w1) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w1) + }() + wg.Wait() require.NoError(w1.Worker().Shutdown()) - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1) - helper.ExpectWorkers(t, c2) + + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2) + }() + wg.Wait() client, err := api.NewClient(nil) require.NoError(err) diff --git a/internal/tests/cluster/multi_controller_worker_test.go b/internal/tests/cluster/multi_controller_worker_test.go index 80b3c6613f..9380fda0b9 100644 --- a/internal/tests/cluster/multi_controller_worker_test.go +++ b/internal/tests/cluster/multi_controller_worker_test.go @@ -5,6 +5,7 @@ package cluster import ( "context" + "sync" "testing" "time" @@ -38,33 +39,64 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { }) defer c2.Shutdown() - helper.ExpectWorkers(t, c1) - helper.ExpectWorkers(t, c2) + wg := new(sync.WaitGroup) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2) + }() + wg.Wait() w1 := worker.NewTestWorker(t, &worker.TestWorkerOpts{ WorkerAuthKms: c1.Config().WorkerAuthKms, - InitialUpstreams: c1.ClusterAddrs(), + InitialUpstreams: append(c1.ClusterAddrs(), c2.ClusterAddrs()...), Logger: logger.Named("w1"), }) defer w1.Shutdown() - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1) - helper.ExpectWorkers(t, c2, w1) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w1) + }() + wg.Wait() w2 := w1.AddClusterWorkerMember(t, &worker.TestWorkerOpts{ Logger: logger.Named("w2"), }) defer w2.Shutdown() - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1, w2) - helper.ExpectWorkers(t, c2, w1, w2) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1, w2) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w1, w2) + }() + wg.Wait() require.NoError(w1.Worker().Shutdown()) - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w2) - helper.ExpectWorkers(t, c2, w2) + + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w2) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w2) + }() + wg.Wait() w1 = worker.NewTestWorker(t, &worker.TestWorkerOpts{ WorkerAuthKms: c1.Config().WorkerAuthKms, @@ -73,22 +105,41 @@ func TestMultiControllerMultiWorkerConnections(t *testing.T) { }) defer w1.Shutdown() - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1, w2) - helper.ExpectWorkers(t, c2, w1, w2) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1, w2) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w1, w2) + }() + wg.Wait() require.NoError(c2.Controller().Shutdown()) - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1, w2) + + wg.Add(1) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1, w2) + }() + wg.Wait() c2 = c1.AddClusterControllerMember(t, &controller.TestControllerOpts{ Logger: c1.Config().Logger.ResetNamed("c2"), }) defer c2.Shutdown() - time.Sleep(10 * time.Second) - helper.ExpectWorkers(t, c1, w1, w2) - helper.ExpectWorkers(t, c2, w1, w2) + wg.Add(2) + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c1, w1, w2) + }() + go func() { + defer wg.Done() + helper.ExpectWorkers(t, c2, w1, w2) + }() + wg.Wait() } func TestWorkerAppendInitialUpstreams(t *testing.T) { diff --git a/internal/tests/cluster/worker_bytesupdown_test.go b/internal/tests/cluster/worker_bytesupdown_test.go index e9867074cb..77e734587f 100644 --- a/internal/tests/cluster/worker_bytesupdown_test.go +++ b/internal/tests/cluster/worker_bytesupdown_test.go @@ -31,16 +31,23 @@ func TestWorkerBytesUpDown(t *testing.T) { Level: hclog.Trace, }) - conf, err := config.DevController() + conf, err := config.DevController(config.WithIPv6Enabled(true)) require.NoError(err) - pl, err := net.Listen("tcp", "localhost:0") + pl, err := net.Listen("tcp", "[::1]:") require.NoError(err) + + // update cluster listener to utilize proxy listener address + for _, l := range conf.Listeners { + if l.Purpose[0] == "cluster" { + l.Address = pl.Addr().String() + } + } + c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, InitialResourcesSuffix: "1234567890", Logger: logger.Named("c1"), - PublicClusterAddr: pl.Addr().String(), WorkerStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, }) @@ -62,10 +69,9 @@ func TestWorkerBytesUpDown(t *testing.T) { InitialUpstreams: []string{proxy.ListenerAddr()}, Logger: logger.Named("w1"), SuccessfulStatusGracePeriodDuration: helper.DefaultSuccessfulStatusGracePeriod, + EnableIPv6: true, }) - require.NoError(w1.Worker().WaitForNextSuccessfulStatusUpdate()) - require.NoError(c1.WaitForNextWorkerStatusUpdate(w1.Name())) helper.ExpectWorkers(t, c1, w1) // Use an independent context for test things that take a context so @@ -90,7 +96,12 @@ func TestWorkerBytesUpDown(t *testing.T) { require.NotNil(tgt) // Authorize a session, connect and send/recv some traffic - sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890") + workerInfo := []*targets.WorkerInfo{ + { + Address: w1.ProxyAddrs()[0], + }, + } + sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890", helper.WithWorkerInfo(workerInfo)) conn := sess.Connect(ctx, t) conn.TestSendRecvAll(t) diff --git a/internal/tests/cluster/worker_proxy_test.go b/internal/tests/cluster/worker_proxy_test.go index 585d6452f0..7948aebf2c 100644 --- a/internal/tests/cluster/worker_proxy_test.go +++ b/internal/tests/cluster/worker_proxy_test.go @@ -32,16 +32,23 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { Level: hclog.Trace, }) - conf, err := config.DevController() + pl, err := net.Listen("tcp", "[::1]:") require.NoError(err) - pl, err := net.Listen("tcp", "localhost:0") + conf, err := config.DevController(config.WithIPv6Enabled(true)) require.NoError(err) + + // update cluster listener to utilize proxy listener address + for _, l := range conf.Listeners { + if l.Purpose[0] == "cluster" { + l.Address = pl.Addr().String() + } + } + c1 := controller.NewTestController(t, &controller.TestControllerOpts{ Config: conf, InitialResourcesSuffix: "1234567890", Logger: logger.Named("c1"), - PublicClusterAddr: pl.Addr().String(), WorkerStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, }) t.Cleanup(c1.Shutdown) @@ -66,13 +73,10 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { InitialUpstreams: []string{proxy.ListenerAddr()}, Logger: logger.Named("w1"), SuccessfulStatusGracePeriodDuration: helper.DefaultWorkerStatusGracePeriod, + EnableIPv6: true, }) t.Cleanup(w1.Shutdown) - err = w1.Worker().WaitForNextSuccessfulStatusUpdate() - require.NoError(err) - err = c1.WaitForNextWorkerStatusUpdate(w1.Name()) - require.NoError(err) helper.ExpectWorkers(t, c1, w1) // Use an independent context for test things that take a context so @@ -99,7 +103,12 @@ func TestWorkerSessionProxyMultipleConnections(t *testing.T) { require.NotNil(tgt) // Authorize and connect - sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890") + workerInfo := []*targets.WorkerInfo{ + { + Address: w1.ProxyAddrs()[0], + }, + } + sess := helper.NewTestSession(ctx, t, tcl, "ttcp_1234567890", helper.WithWorkerInfo(workerInfo)) sConn := sess.Connect(ctx, t) // Run initial send/receive test, make sure things are working diff --git a/internal/tests/helper/option.go b/internal/tests/helper/option.go index 28e9b8be5f..4ce8e321b2 100644 --- a/internal/tests/helper/option.go +++ b/internal/tests/helper/option.go @@ -3,6 +3,8 @@ package helper +import "github.com/hashicorp/boundary/api/targets" + // getOpts iterates the inbound Options and returns a struct and any errors func getOpts(opt ...Option) (*Options, error) { opts := getDefaultOptions() @@ -22,6 +24,7 @@ func getOpts(opt ...Option) (*Options, error) { // are parsed in various other packages. type Options struct { WithSkipSessionTeardown bool + WithWorkerInfo []*targets.WorkerInfo } // Option is a function that takes in an options struct and sets values or @@ -43,3 +46,13 @@ func WithSkipSessionTeardown(with bool) Option { return nil } } + +// WithWorkerInfo can be used to override the default worker address localhost:9202 +// for SessionAuthroizationData. This is useful when testing session connection with +// dev workers that are not utilizing default addresses. +func WithWorkerInfo(workerInfo []*targets.WorkerInfo) Option { + return func(o *Options) error { + o.WithWorkerInfo = workerInfo + return nil + } +} diff --git a/internal/tests/helper/testing_helper.go b/internal/tests/helper/testing_helper.go index 0392eb3f62..ed916a4421 100644 --- a/internal/tests/helper/testing_helper.go +++ b/internal/tests/helper/testing_helper.go @@ -11,6 +11,7 @@ import ( "net" "reflect" "strconv" + "sync" "testing" "time" @@ -76,11 +77,18 @@ func NewTestSession( sessAuth, err := sar.GetSessionAuthorization() require.NoError(err) + sessAuthData, err := sessAuth.GetSessionAuthorizationData() + if len(opts.WithWorkerInfo) != 0 { + sessAuthData.WorkerInfo = opts.WithWorkerInfo + } + require.NoError(err) + proxy, err := apiproxy.New( ctx, sessAuth.AuthorizationToken, apiproxy.WithWorkerHost(sessAuth.SessionId), apiproxy.WithSkipSessionTeardown(opts.WithSkipSessionTeardown), + apiproxy.WithSessionAuthorizationData(sessAuthData), ) require.NoError(err) @@ -431,23 +439,36 @@ func NewTestTcpServer(t *testing.T) *TestTcpServer { return ts } +// ExpectWorkers is a blocking call, where the method validates that the expected workers +// can be found in the controllers status update. If the provided list of workers is empty, +// this method will sleep for 10 seconds and then validate that the controller worker status +// is empty. func ExpectWorkers(t *testing.T, c *controller.TestController, workers ...*worker.TestWorker) { - updateTimes := c.Controller().WorkerStatusUpdateTimes() - workerMap := map[string]*worker.TestWorker{} + // validate the controller has no reported workers + if len(workers) == 0 { + c.Controller().WorkerStatusUpdateTimes().Clear() + time.Sleep(10 * time.Second) + assert.Eventually(t, func() bool { + empty := true + c.Controller().WorkerStatusUpdateTimes().Range(func(k, v any) bool { + empty = false + return false + }) + return empty + }, 30*time.Second, 2*time.Second) + return + } + + // validate the controller has expected workers + wg := new(sync.WaitGroup) for _, w := range workers { - workerMap[w.Name()] = w + wg.Add(1) + go func() { + defer wg.Done() + require.NoError(t, c.WaitForNextWorkerStatusUpdate(w.Name())) + _, ok := c.Controller().WorkerStatusUpdateTimes().Load(w.Name()) + assert.True(t, ok) + }() } - updateTimes.Range(func(k, v any) bool { - require.NotNil(t, k) - require.NotNil(t, v) - if workerMap[k.(string)] == nil { - // We don't remove from updateTimes currently so if we're not - // expecting it we'll see an out-of-date entry - return true - } - assert.WithinDuration(t, time.Now(), v.(time.Time), 30*time.Second) - delete(workerMap, k.(string)) - return true - }) - assert.Empty(t, workerMap) + wg.Wait() } diff --git a/internal/util/net.go b/internal/util/net.go new file mode 100644 index 0000000000..874929906a --- /dev/null +++ b/internal/util/net.go @@ -0,0 +1,72 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package util + +import ( + "context" + "errors" + "net" + "regexp" + "strings" + + "github.com/hashicorp/boundary/globals" +) + +const ( + // MinAddressLength + MinAddressLength = 3 + // MaxAddressLength + MaxAddressLength = 255 +) + +// This regular expression is used to find all instances of square brackets within a string. +// This regular expression is used to remove the square brackets from an IPv6 address. +var squareBrackets = regexp.MustCompile("\\[|\\]") + +// JoinHostPort combines host and port into a network address of the form "host:port". +// If host contains a colon, as found in literal IPv6 addresses, then JoinHostPort returns "[host]:port". +func JoinHostPort(host, port string) string { + host = squareBrackets.ReplaceAllString(host, "") + return net.JoinHostPort(host, port) +} + +// SplitHostPort splits a network address of the form "host:port", "host%zone:port", "[host]:port" or "[host%zone]:port" into host or host%zone and port. +// +// A literal IPv6 address in hostport must be enclosed in square brackets, as in "[::1]:80", "[::1%lo0]:80". +func SplitHostPort(hostport string) (host string, port string, err error) { + host, port, err = net.SplitHostPort(hostport) + // use the hostport value as a backup when we have a missing port error + if err != nil && strings.Contains(err.Error(), globals.MissingPortErrStr) { + // incase the hostport value is an ipv6, we must remove the enclosed square + // brackets to retain the same behavior as the net.SplitHostPort() method + host = squareBrackets.ReplaceAllString(hostport, "") + err = nil + } + return +} + +// ParseAddress trims and validates the input address string. It checks whether +// the address is within the allowed length and attempts to split it into a host and +// port. If the address contains a port, it returns an error. The function supports +// both valid IP addresses (IPv4 or IPv6) and DNS names. If the address is valid +// and does not include a port, it returns the host (either an IP or a DNS name). +func ParseAddress(ctx context.Context, address string) (string, error) { + const op = "util.ParseAddress" + address = strings.TrimSpace(address) + if len(address) < MinAddressLength || len(address) > MaxAddressLength { + return "", errors.New("invalid address length") + } + host, port, err := SplitHostPort(address) + if err != nil { + ip := net.ParseIP(address) + if ip.To4() == nil && ip.To16() == nil { + return "", err + } + host = ip.String() + } + if port != "" { + return "", errors.New("address contains a port") + } + return host, nil +} diff --git a/internal/util/net_test.go b/internal/util/net_test.go new file mode 100644 index 0000000000..1767a9bfe9 --- /dev/null +++ b/internal/util/net_test.go @@ -0,0 +1,385 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package util + +import ( + "context" + "net" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_JoinHostPort(t *testing.T) { + t.Parallel() + + // The wrapper function is used to ensure that the + // host input value is not already enclosed with + // square brackets for ipv6 addresses. This is because + // the underlying JoinHostPort() method will enclose the + // existing square brackets with another pair of square + // brackets. + t.Run("ensure-net.JoinHostPort()-behavior", func(t *testing.T) { + assert := assert.New(t) + hostport := net.JoinHostPort("[2001:4860:4860:0:0:0:0:8888]", "80") + assert.Equal("[[2001:4860:4860:0:0:0:0:8888]]:80", hostport) + }) + + tests := []struct { + name string + host string + port string + expectedAddress string + }{ + { + name: "local-ipv4", + host: "127.0.0.1", + port: "80", + expectedAddress: "127.0.0.1:80", + }, + { + name: "ipv4", + host: "8.8.8.8", + port: "80", + expectedAddress: "8.8.8.8:80", + }, + { + name: "ipv4-empty-port", + host: "8.8.8.8", + expectedAddress: "8.8.8.8:", + }, + { + name: "ipv4-square-brackets", + host: "[8.8.8.8]", + port: "80", + expectedAddress: "8.8.8.8:80", + }, + { + name: "missing-left-square-bracket", + host: "::1]", + port: "80", + expectedAddress: "[::1]:80", + }, + { + name: "missing-right-square-bracket", + host: "[::1", + port: "80", + expectedAddress: "[::1]:80", + }, + { + name: "local-no-square-brackets", + host: "::1", + port: "80", + expectedAddress: "[::1]:80", + }, + { + name: "local-no-square-brackets-missing-port", + host: "::1", + expectedAddress: "[::1]:", + }, + { + name: "ipv6-no-square-brackets", + host: "2001:4860:4860:0:0:0:0:8888", + port: "80", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + { + name: "ipv6-no-square-brackets-missing-port", + host: "2001:4860:4860:0:0:0:0:8888", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", + }, + { + name: "abbreviated-ipv6-no-square-brackets", + host: "2001:4860:4860::8888", + port: "80", + expectedAddress: "[2001:4860:4860::8888]:80", + }, + { + name: "abbreviated-ipv6-no-square-brackets-missing-port", + host: "2001:4860:4860::8888", + expectedAddress: "[2001:4860:4860::8888]:", + }, + { + name: "local-square-brackets", + host: "[::1]", + port: "80", + expectedAddress: "[::1]:80", + }, + { + name: "local-double-square-brackets", + host: "[[::1]]", + port: "80", + expectedAddress: "[::1]:80", + }, + { + name: "local-square-brackets-missing-port", + host: "[::1]", + expectedAddress: "[::1]:", + }, + { + name: "local-double-square-brackets-missing-port", + host: "[[::1]]", + expectedAddress: "[::1]:", + }, + { + name: "ipv6-square-brackets", + host: "[2001:4860:4860:0:0:0:0:8888]", + port: "80", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + { + name: "ipv6-dobule-square-brackets", + host: "[[2001:4860:4860:0:0:0:0:8888]]", + port: "80", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:80", + }, + { + name: "ipv6-square-brackets-missing-port", + host: "[2001:4860:4860:0:0:0:0:8888]", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", + }, + { + name: "ipv6-double-square-brackets-missing-port", + host: "[[2001:4860:4860:0:0:0:0:8888]]", + expectedAddress: "[2001:4860:4860:0:0:0:0:8888]:", + }, + { + name: "abbreviated-ipv6-square-brackets", + host: "[2001:4860:4860::8888]", + port: "80", + expectedAddress: "[2001:4860:4860::8888]:80", + }, + { + name: "abbreviated-ipv6-double-square-brackets", + host: "[[2001:4860:4860::8888]]", + port: "80", + expectedAddress: "[2001:4860:4860::8888]:80", + }, + { + name: "abbreviated-ipv6-square-brackets-missing-port", + host: "[2001:4860:4860::8888]", + expectedAddress: "[2001:4860:4860::8888]:", + }, + { + name: "abbreviated-ipv6-double-square-brackets-missing-port", + host: "[[2001:4860:4860::8888]]", + expectedAddress: "[2001:4860:4860::8888]:", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + assert := assert.New(t) + actualAddress := JoinHostPort(tt.host, tt.port) + assert.Equal(tt.expectedAddress, actualAddress) + }) + } +} + +func Test_SplitHostPort(t *testing.T) { + t.Parallel() + + // The wrapper function is used to ignore missing port error. + // We need to validate the behavior of the underlying + // SplitHostPort() method hasn't changed. + t.Run("ensure-net.SplitHostPort()-behavior", func(t *testing.T) { + require, assert := require.New(t), assert.New(t) + host, port, err := net.SplitHostPort("[2001:4860:4860:0:0:0:0:8888]") + require.Error(err) + assert.ErrorContains(err, "missing port in address") + assert.Empty(host) + assert.Empty(port) + }) + + tests := []struct { + name string + hostport string + expectedHost string + expectedPort string + expectedErrMsg string + }{ + { + name: "local-ipv4", + hostport: "127.0.0.1:80", + expectedHost: "127.0.0.1", + expectedPort: "80", + }, + { + name: "ipv4", + hostport: "8.8.8.8:80", + expectedHost: "8.8.8.8", + expectedPort: "80", + }, + { + name: "ipv4-ignore-missing-port", + hostport: "8.8.8.8", + expectedHost: "8.8.8.8", + }, + { + name: "ipv4-empty-port", + hostport: "8.8.8.8:", + expectedHost: "8.8.8.8", + }, + { + name: "ipv4-square-bracket", + hostport: "[8.8.8.8]:80", + expectedHost: "8.8.8.8", + expectedPort: "80", + }, + { + name: "ipv6-missing-square-brackets", + hostport: "::1:80", + expectedErrMsg: "address ::1:80: too many colons in address", + }, + { + name: "ipv6-ignore-missing-port", + hostport: "[::1]", + expectedHost: "::1", + }, + { + name: "ipv6-empty-port", + hostport: "[::1]:", + expectedHost: "::1", + }, + { + name: "local-ipv6", + hostport: "[::1]:80", + expectedHost: "::1", + expectedPort: "80", + }, + { + name: "ipv6", + hostport: "[2001:4860:4860:0:0:0:0:8888]:80", + expectedHost: "2001:4860:4860:0:0:0:0:8888", + expectedPort: "80", + }, + { + name: "abbreviated-ipv6", + hostport: "[2001:4860:4860::8888]:80", + expectedHost: "2001:4860:4860::8888", + expectedPort: "80", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + require, assert := require.New(t), assert.New(t) + actualHost, actualPort, err := SplitHostPort(tt.hostport) + if tt.expectedErrMsg != "" { + require.Error(err) + assert.ErrorContains(err, tt.expectedErrMsg) + return + } + require.NoError(err) + assert.Equal(tt.expectedHost, actualHost) + assert.Equal(tt.expectedPort, actualPort) + }) + } +} + +func Test_ParseAddress(t *testing.T) { + t.Parallel() + tests := []struct { + name string + address string + expectedAddress string + expectedErrMsg string + }{ + { + name: "empty-address", + expectedErrMsg: "invalid address length", + }, + { + name: "empty-spaces", + address: " ", + expectedErrMsg: "invalid address length", + }, + { + name: "invalid-short-address", + address: "ab", + expectedErrMsg: "invalid address length", + }, + { + name: "invalid-long-address", + address: strings.Repeat("a", 256), + expectedErrMsg: "invalid address length", + }, + { + name: "valid-dns-name", + address: "www.google.com", + expectedAddress: "www.google.com", + }, + { + name: "valid-dns-name-trim-empty-spaces", + address: " www.google.com ", + expectedAddress: "www.google.com", + }, + { + name: "valid-ipv4", + address: "127.0.0.1", + expectedAddress: "127.0.0.1", + }, + { + name: "invalid-ipv4-with-port", + address: "127.0.0.1:80", + expectedErrMsg: "address contains a port", + }, + { + name: "valid-ipv6", + address: "2001:4860:4860:0:0:0:0:8888", + expectedAddress: "2001:4860:4860::8888", + }, + { + name: "valid-[ipv6]", + address: "[2001:4860:4860:0:0:0:0:8888]", + expectedAddress: "2001:4860:4860:0:0:0:0:8888", + }, + { + name: "valid-[ipv6]:", + address: "[2001:4860:4860:0:0:0:0:8888]:", + expectedAddress: "2001:4860:4860:0:0:0:0:8888", + }, + { + name: "invalid-ipv6-with-port", + address: "[2001:4860:4860:0:0:0:0:8888]:80", + expectedErrMsg: "address contains a port", + }, + { + name: "valid-abbreviated-ipv6", + address: "2001:4860:4860::8888", + expectedAddress: "2001:4860:4860::8888", + }, + { + name: "valid-abbreviated-[ipv6]", + address: "[2001:4860:4860::8888]", + expectedAddress: "2001:4860:4860::8888", + }, + { + name: "valid-abbreviated-[ipv6]:", + address: "[2001:4860:4860::8888]:", + expectedAddress: "2001:4860:4860::8888", + }, + { + name: "invalid-abbreviated-[ipv6]-with-port", + address: "[2001:4860:4860::8888]:80", + expectedErrMsg: "address contains a port", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + require, assert := require.New(t), assert.New(t) + actualAddress, err := ParseAddress(context.Background(), tt.address) + if tt.expectedErrMsg != "" { + require.Error(err) + assert.ErrorContains(err, tt.expectedErrMsg) + return + } + require.NoError(err) + assert.Equal(tt.expectedAddress, actualAddress) + }) + } +} diff --git a/plugins/boundary/mains/aws/go.mod b/plugins/boundary/mains/aws/go.mod index 8d228bdc36..88ec6c5950 100644 --- a/plugins/boundary/mains/aws/go.mod +++ b/plugins/boundary/mains/aws/go.mod @@ -3,67 +3,65 @@ module github.com/hashicorp/boundary/plugins/boundary/mains/aws go 1.23.1 require ( - github.com/hashicorp/boundary-plugin-aws v0.4.0 - github.com/hashicorp/boundary/sdk v0.0.43-0.20240717182311-a20aae98794a + github.com/hashicorp/boundary-plugin-aws v0.4.1-0.20241028185018-899c62ce0694 + github.com/hashicorp/boundary/sdk v0.0.49 ) require ( - github.com/aws/aws-sdk-go-v2 v1.20.1 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.33 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.32 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0 // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.22.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 // indirect - github.com/aws/smithy-go v1.14.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect + github.com/aws/aws-sdk-go-v2/config v1.28.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.186.0 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.37.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect + github.com/aws/smithy-go v1.22.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 // indirect + github.com/hashicorp/eventlogger v0.2.10 // indirect github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v1.5.0 // indirect - github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect + github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.5.2 // indirect + github.com/hashicorp/go-plugin v1.6.2 // indirect github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect - github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 // indirect + github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/grpc v1.61.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/plugins/boundary/mains/aws/go.sum b/plugins/boundary/mains/aws/go.sum index edfabe9d5b..96a3497489 100644 --- a/plugins/boundary/mains/aws/go.sum +++ b/plugins/boundary/mains/aws/go.sum @@ -6,51 +6,46 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2 v1.20.1 h1:rZBf5DWr7YGrnlTK4kgDQGn1ltqOg5orCYb/UhOFZkg= -github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12 h1:lN6L3LrYHeZ6xCxaIYtoWCx4GMLk4nRknsh29OMSqHY= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.12/go.mod h1:TDCkEAkMTXxTs0oLBGBKpBZbk3NLh8EvAfF0Q3x8/0c= -github.com/aws/aws-sdk-go-v2/config v1.18.33 h1:JKcw5SFxFW/rpM4mOPjv0VQ11E2kxW13F3exWOy7VZU= -github.com/aws/aws-sdk-go-v2/config v1.18.33/go.mod h1:hXO/l9pgY3K5oZJldamP0pbZHdPqqk+4/maa7DSD3cA= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32 h1:lIH1eKPcCY1ylR4B6PkBGRWMHO3aVenOKJHWiS4/G2w= -github.com/aws/aws-sdk-go-v2/credentials v1.13.32/go.mod h1:lL8U3v/Y79YRG69WlAho0OHIKUXCyFvSXaIvfo81sls= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8 h1:DK/9C+UN/X+1+Wm8pqaDksQr2tSLzq+8X1/rI/ZxKEQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.8/go.mod h1:ce7BgLQfYr5hQFdy67oX2svto3ufGtm6oBvmsHScI1Q= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33/go.mod h1:7i0PF1ME/2eUPFcjkVIwq+DOygHEoK92t5cDqNgYbIw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38 h1:c8ed/T9T2K5I+h/JzmF5tpI46+OODQ74dzmdo+QnaMg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.38/go.mod h1:qggunOChCMu9ZF/UkAfhTz25+U2rLVb3ya0Ua6TTfCA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27/go.mod h1:UrHnn3QV/d0pBZ6QBAEQcqFLf8FAzLmoUfPVIueOvoM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32 h1:hNeAAymUY5gu11WrrmFb3CVIp9Dar9hbo44yzzcQpzA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.32/go.mod h1:0ZXSqrty4FtQ7p8TEuRde/SZm9X05KT18LAUlR40Ln0= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39 h1:fc0ukRAiP1syoSGZYu+DaE+FulSYhTiJ8WpVu5jElU4= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.39/go.mod h1:WLAW8PT7+JhjZfLSWe7WEJaJu0GNo0cKc2Zyo003RBs= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1 h1:vUh7dBFNS3oFCtVv6CiYKh5hP9ls8+kIpKLeFruIBLk= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.1/go.mod h1:sFMeinkhj/SZKQM8BxtvNtSPjJEo0Xrz+w3g2e4FSKI= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0 h1:NXi4pNJWjAaiI56P1Rl8DC9A4jMNRE00WNBsDua5WRg= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0/go.mod h1:L3ZT0N/vBsw77mOAawXmRnREpEjcHd2v5Hzf7AkIH8M= -github.com/aws/aws-sdk-go-v2/service/iam v1.22.2 h1:DPFxx/6Zwes/MiadlDteVqDKov7yQ5v9vuwfhZuJm1s= -github.com/aws/aws-sdk-go-v2/service/iam v1.22.2/go.mod h1:cQTMNdo/Z5t1DDRsUnx0a2j6cPnytMBidUYZw2zks28= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13 h1:iV/W5OMBys+66OeXJi/7xIRrKZNsu0ylsLGu+6nbmQE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.13/go.mod h1:ReJb6xYmtGyu9KoFtRreWegbN9dZqvZIIv4vWnhcsyI= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33 h1:QviNkc+vGSuEHx8P+pVNKOdWLXBPIwMFv7p0fphgE4U= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.33/go.mod h1:fABTUmOrAgAalG2i9WJpjBvlnk7UK8YmnYaxN+Q2CwE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27/go.mod h1:EOwBD4J4S5qYszS5/3DpkejfuK+Z5/1uzICfPaZLtqw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32 h1:dGAseBFEYxth10V23b5e2mAS+tX7oVbfYHD6dnDdAsg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.32/go.mod h1:4jwAWKEkCR0anWk5+1RbfSg1R5Gzld7NLiuaq5bTR/Y= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1 h1:PT6PBCycRwhpEW5hJnRiceCeoWJ+r3bdgXtV+VKG7Pk= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.1/go.mod h1:TqoxCLwT2nrxrBGA+z7t6OWM7LBkgRckK3gOjYE+7JA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2 h1:v346f1h8sUBKXnEbrv43L37MTBlFHyKXQPIZHNAaghA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.38.2/go.mod h1:cwCATiyNrXK9P2FsWdZ89g9mpsYv2rhk0UA/KByl5fY= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2 h1:A2RlEMo4SJSwbNoUUgkxTAEMduAy/8wG3eB2b2lP4gY= -github.com/aws/aws-sdk-go-v2/service/sso v1.13.2/go.mod h1:ju+nNXUunfIFamXUIZQiICjnO/TPlOmWcYhZcSy7xaE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2 h1:OJELEgyaT2kmaBGZ+myyZbTTLobfe3ox3FSh5eYK9Qs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.2/go.mod h1:ubDBBaDFs1GHijSOTi8ljppML15GLG0HxhILtbjNNYQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2 h1:ympg1+Lnq33XLhcK/xTG4yZHPs1Oyxu+6DEWbl7qOzA= -github.com/aws/aws-sdk-go-v2/service/sts v1.21.2/go.mod h1:FQ/DQcOfESELfJi5ED+IPPAjI5xC6nxtSolVVB773jM= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.14.1 h1:EFKMUmH/iHMqLiwoEDx2rRjRQpI1YCn5jTysoaDujFs= -github.com/aws/smithy-go v1.14.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= +github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= +github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= +github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= +github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= +github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.186.0 h1:n2l2WeV+lEABrGwG/4MsE0WFEbd3j7yKsmZzbnEm5CY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.186.0/go.mod h1:kYXaB4FzyhEJjvrJ84oPnMElLiEAjGxxUunVW2tBSng= +github.com/aws/aws-sdk-go-v2/service/iam v1.37.2 h1:E7vCDUFeDN8uOk8Nb2d4E1howWS1TR4HrKABXsvttIs= +github.com/aws/aws-sdk-go-v2/service/iam v1.37.2/go.mod h1:QzMecFrIFYJ1cyxjlUoIFRzYSDX19gdqYUd0Tyws2J8= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1 h1:MkQ4unegQEStiQYmfFj+Aq5uTp265ncSmm0XTQwDwi0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.1/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= @@ -60,46 +55,43 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= -github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/boundary-plugin-aws v0.4.0 h1:n0CNeswkTvrREXxzOIoaMjCs7FVWwMHceHKiQNwz3KA= -github.com/hashicorp/boundary-plugin-aws v0.4.0/go.mod h1:p6cicTmRGFw9qKvCbABIxsbRkqJq+jjwy0Ih+Ns3RHg= -github.com/hashicorp/boundary/sdk v0.0.43-0.20240717182311-a20aae98794a h1:SwVze6sYE5o+J9qdcgj29auY1k6O8oSo9DC2+2Gb9rw= -github.com/hashicorp/boundary/sdk v0.0.43-0.20240717182311-a20aae98794a/go.mod h1:9iOT7kDM6mYcSkKxNuZlv8rP7U5BG1kXoevjLLL8lNQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/boundary-plugin-aws v0.4.1-0.20241028041804-97aae6ebc3e0 h1:GANG5VxXVClV5FIh7OQEQ7BIWpf8uZgs48+dkPL/cmE= +github.com/hashicorp/boundary-plugin-aws v0.4.1-0.20241028041804-97aae6ebc3e0/go.mod h1:v5i02mEC5W5n/mHpdGbU3VNYUJggv0NMsOvnZQUAeak= +github.com/hashicorp/boundary-plugin-aws v0.4.1-0.20241028185018-899c62ce0694 h1:2CNa55lFiTbT+J7yY0AeRGHKYz7oCIV9zGn1g/A8Ooo= +github.com/hashicorp/boundary-plugin-aws v0.4.1-0.20241028185018-899c62ce0694/go.mod h1:v5i02mEC5W5n/mHpdGbU3VNYUJggv0NMsOvnZQUAeak= +github.com/hashicorp/boundary/sdk v0.0.49 h1:XOb6mSKyrU/wI20+5xTYBHQUP7eIeKcLxKSCpCs4yzM= +github.com/hashicorp/boundary/sdk v0.0.49/go.mod h1:IHP79to8aIi22FiY58pgBqJL96/U9D8ZAUhS2DdC+Us= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0 h1:f9oX8/3zxiQrfrWnBeyjDm4S02GAU02OBtCRoZOUwlo= -github.com/hashicorp/eventlogger v0.2.6-0.20231025104552-802587e608f0/go.mod h1://CHt6/j+Q2lc0NlUB5af4aS2M0c0aVBg9/JfcpAyhM= +github.com/hashicorp/eventlogger v0.2.10 h1:Dddth3KVSribGE1rInGToM30tRNblvL0G1OG6N+i2pk= +github.com/hashicorp/eventlogger v0.2.10/go.mod h1:imHMTfJH4qfb8Knh9nZw4iLfL9J1bX6TJKEurSB4t+U= github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0 h1:iAb287bq0TaWTnhDYuN/zVqdD2EwanQg9ncVelC60Xc= github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20231025104552-802587e608f0/go.mod h1:tMywUTIvdB/FXhwm6HMTt61C8/eODY6gitCHhXtyojg= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5 h1:jrnDfQm2hCQ0/hEselgqzV4fK16gpZoY0OWGZpVPNHM= github.com/hashicorp/go-kms-wrapping/plugin/v2 v2.0.5/go.mod h1:psh1qKep5ukvuNobFY/hCybuudlkkACpmazOsCgX5Rg= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14 h1:1ZuhfnZgRnLK8S0KovJkoTCRIQId5pv3sDR7pG5VQBw= -github.com/hashicorp/go-kms-wrapping/v2 v2.0.14/go.mod h1:0dWtzl2ilqKpavgM3id/kFK9L3tjo6fS4OhbVPSYpnQ= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.16 h1:WZeXfD26QMWYC35at25KgE021SF9L3u9UMHK8fJAdV0= +github.com/hashicorp/go-kms-wrapping/v2 v2.0.16/go.mod h1:ZiKZctjRTLEppuRwrttWkp71VYMbTTCkazK4xT7U/NQ= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.5.2 h1:aWv8eimFqWlsEiMrYZdPYl+FdHaBJSN4AWwGWfT1G2Y= -github.com/hashicorp/go-plugin v1.5.2/go.mod h1:w1sAEES3g3PuV/RzUrgow20W2uErMly84hhD3um1WL4= +github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= +github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0 h1:ca5TSI4AgaOncPpyzLDtCGjVEtKukONpeM95vFxXCOQ= github.com/hashicorp/go-secure-stdlib/awsutil/v2 v2.0.0/go.mod h1:7CUvZtfTp2U0CYQCLzMtS2ngckjAZePSfwrE2aeDP1M= -github.com/hashicorp/go-secure-stdlib/base62 v0.1.1/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 h1:ET4pqyjiGmY09R5y+rSd70J2w45CtbWDNvGqWp/R3Ng= github.com/hashicorp/go-secure-stdlib/base62 v0.1.2/go.mod h1:EdWO6czbmthiwZ3/PUsDV+UD1D5IRU4ActiaWGwt0Yw= github.com/hashicorp/go-secure-stdlib/configutil/v2 v2.0.11 h1:uPW2Wn0YlmI9RGSkZpcIplnVRwJ7BCiGpk1vnF2TMw4= @@ -108,11 +100,10 @@ github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9 h1:0S0ctJ7Ra8O7ap+/3fZ github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.9/go.mod h1:TNNdgtjLgVDbrgFcyCKrlAicIl3dZF94swJltyGUX2M= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6 h1:ZYv2XA+tEfFXIToR2jmBgVqQU9gERt0APbWqmUoNGnY= -github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.6/go.mod h1:ggFN8dlaLWS2R1gymBbCrvXM/bkZP7hEAa4seqDwhyg= +github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7 h1:oYEPhztZRmZCETTxxIo5MNa+I+DDqSDZ+biJt2o4Ncw= +github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.7/go.mod h1:ggFN8dlaLWS2R1gymBbCrvXM/bkZP7hEAa4seqDwhyg= github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1 h1:SMGUnbpAcat8rIKHkBPjfv81yC46a8eCNZ2hsR2l1EI= github.com/hashicorp/go-secure-stdlib/reloadutil v0.1.1/go.mod h1:Ch/bf00Qnx77MZd49JRgHYqHQjtEmTgGU2faufpVZb0= -github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-secure-stdlib/tlsutil v0.1.3 h1:xbrxd0U9XQW8qL1BAz2XrAjAF/P2vcqUTAues9c24B8= @@ -124,8 +115,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= @@ -134,16 +125,8 @@ github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f h1:E87tDTVS5W github.com/jefferai/isbadcipher v0.0.0-20190226160619-51d2077c035f/go.mod h1:3J2qVK16Lq8V+wfiL2lPeDZ7UWMxk5LemerHa1p6N00= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -153,14 +136,12 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -174,7 +155,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= @@ -184,80 +164,36 @@ github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -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= -mvdan.cc/gofumpt v0.1.1/go.mod h1:yXG1r1WqZVKWbVRtBWKWX9+CxGYfA51nSomhM0woR48=