[fix] allow IPv6 controllers, workers, and targets (#5221)

Co-authored-by: Damian Debkowski <damian.debkowski@hashicorp.com>
This commit is contained in:
daniandDamian Debkowski authored and GitHub committed 2024-11-01 13:27:40 -04:00
1 parent 680bb02af9
commit 62c41191ff
42 files changed
+1996 -546

No files matched your search

+2 -1
View File
@@ -4,7 +4,8 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
source = "hashicorp/aws"
version = "5.72.1"
}
}
+2 -1
View File
@@ -14,7 +14,8 @@ terraform "default" {
}
aws = {
source = "hashicorp/aws"
source = "hashicorp/aws"
version = "5.72.1"
}
}
}
+3 -3
View File
@@ -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)
}
+18 -14
View File
@@ -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 == "" {
+16 -17
View File
@@ -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")
}
}
+6 -18
View File
@@ -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
}
+8 -16
View File
@@ -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
+4 -7
View File
@@ -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`)
+7 -14
View File
@@ -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 {
+111 -32
View File
@@ -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()
hclStr := fmt.Sprintf(devConfig+devWorkerExtraConfig, 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)
}
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)
}
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 {
+97
View File
@@ -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()
+15
View File
@@ -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 {
@@ -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
@@ -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 = repo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"})
_, _, err = hostRepo.UpdateHost(ctx, hc.GetProjectId(), h, h.GetVersion(), []string{"address"})
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
}
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)
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) {
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)
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) 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()
+4 -1
View File
@@ -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)
}
@@ -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")
}
}
@@ -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))
}
}
+5 -1
View File
@@ -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,
+24
View File
@@ -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)
+59 -1
View File
@@ -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{
+2 -1
View File
@@ -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...)
+20 -20
View File
@@ -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)
tt.want.PublicId = id
got.PublicId = id
w := db.New(conn)
err2 := w.Create(ctx, got)
if tt.wantWriteErr {
assert.Error(err2)
}
}
return
}
require.NoError(err)
require.NotNil(got)
assert.Emptyf(got.PublicId, "PublicId set")
assert.Equal(tt.want, got)
id, err := newHostId(ctx)
require.NoError(err)
tt.want.PublicId = id
got.PublicId = id
w := db.New(conn)
dbWriteErr := w.Create(ctx, got)
if tt.wantWriteErr {
require.Error(dbWriteErr)
return
}
require.NoError(dbWriteErr)
})
}
}
+9 -6
View File
@@ -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))
@@ -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{
+24
View File
@@ -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.
+10
View File
@@ -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
}
+138 -10
View File
@@ -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)
+2 -6
View File
@@ -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.
+13 -4
View File
@@ -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)
}
@@ -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",
+100 -23
View File
@@ -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)
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())
require.NoError(err)
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",
},
}
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())
foundTarget, err := repo.LookupTarget(context.Background(), tar.GetPublicId())
foundSources := foundTarget.GetHostSources()
require.NoError(err)
foundIds := make([]string, 0, len(foundSources))
for _, s := range foundSources {
foundIds = append(foundIds, s.Id())
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) {
+19 -14
View File
@@ -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)
+43 -28
View File
@@ -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)
@@ -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) {
@@ -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)
+17 -8
View File
@@ -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
+13
View File
@@ -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
}
}
+38 -17
View File
@@ -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{}
for _, w := range workers {
workerMap[w.Name()] = w
// 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
}
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)
// validate the controller has expected workers
wg := new(sync.WaitGroup)
for _, w := range workers {
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)
}()
}
wg.Wait()
}
+72
View File
@@ -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
}
+385
View File
@@ -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)
})
}
}
+42 -44
View File
@@ -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
)
+88 -152
View File
@@ -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=