diff --git a/internal/db/schema/migrations/oss/postgres/75/01_storage_bucket.up.sql b/internal/db/schema/migrations/oss/postgres/75/01_storage_bucket.up.sql new file mode 100644 index 000000000..4f9d785b8 --- /dev/null +++ b/internal/db/schema/migrations/oss/postgres/75/01_storage_bucket.up.sql @@ -0,0 +1,36 @@ +-- Copyright (c) HashiCorp, Inc. +-- SPDX-License-Identifier: MPL-2.0 + +begin; + +drop view storage_plugin_storage_bucket_with_secret; + +alter table storage_plugin_storage_bucket + drop constraint if exists secrets_hmac_must_not_be_empty, + alter column secrets_hmac drop not null; + +create view storage_plugin_storage_bucket_with_secret as + select + spsb.public_id, + spsb.scope_id, + spsb.name, + spsb.description, + spsb.create_time, + spsb.update_time, + spsb.version, + spsb.plugin_id, + spsb.bucket_name, + spsb.bucket_prefix, + spsb.worker_filter, + spsb.attributes, + spsb.secrets_hmac, + spsbs.secrets_encrypted, + spsbs.key_id + from storage_plugin_storage_bucket spsb + left join storage_plugin_storage_bucket_secret spsbs + on spsbs.storage_bucket_id = spsb.public_id; + comment on view storage_plugin_storage_bucket_with_secret is + 'storage_plugin_storage_bucket_with_secret is a view where each row contains a storage bucket. ' + 'Encrypted secret and hmac value is not returned if a secret is not associated with the storage bucket.'; + +commit; \ No newline at end of file diff --git a/internal/plugin/loopback/storage.go b/internal/plugin/loopback/storage.go index 298e0034b..9f45a6b4a 100644 --- a/internal/plugin/loopback/storage.go +++ b/internal/plugin/loopback/storage.go @@ -17,6 +17,7 @@ import ( plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -121,8 +122,8 @@ func (l *LoopbackStorage) onCreateStorageBucket(ctx context.Context, req *plgpb. if req.GetBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } - if req.GetBucket().GetSecrets() == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } l.m.Lock() defer l.m.Unlock() @@ -134,9 +135,15 @@ func (l *LoopbackStorage) onCreateStorageBucket(ctx context.Context, req *plgpb. return nil, status.Errorf(err.ErrCode, err.ErrMsg) } } + secrets := req.GetBucket().GetSecrets() + if secrets == nil { + secrets = &structpb.Struct{ + Fields: make(map[string]*structpb.Value), + } + } return &plgpb.OnCreateStorageBucketResponse{ Persisted: &storagebuckets.StorageBucketPersisted{ - Data: req.GetBucket().GetSecrets(), + Data: secrets, }, }, nil } @@ -149,8 +156,8 @@ func (l *LoopbackStorage) onUpdateStorageBucket(ctx context.Context, req *plgpb. if req.GetNewBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } - if req.Persisted == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetNewBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } l.m.Lock() defer l.m.Unlock() @@ -162,16 +169,20 @@ func (l *LoopbackStorage) onUpdateStorageBucket(ctx context.Context, req *plgpb. return nil, status.Errorf(err.ErrCode, "%s: %s", op, err.ErrMsg) } } - var sec *storagebuckets.StorageBucketPersisted - if req.NewBucket.Secrets != nil { - sec = &storagebuckets.StorageBucketPersisted{ - Data: req.GetNewBucket().GetSecrets(), - } + var secrets *structpb.Struct + if req.GetNewBucket().GetSecrets() != nil { + secrets = req.GetNewBucket().GetSecrets() + } else if req.GetPersisted().GetData() != nil { + secrets = req.GetPersisted().GetData() } else { - sec = req.Persisted + secrets = &structpb.Struct{ + Fields: make(map[string]*structpb.Value), + } } return &plgpb.OnUpdateStorageBucketResponse{ - Persisted: sec, + Persisted: &storagebuckets.StorageBucketPersisted{ + Data: secrets, + }, }, nil } @@ -183,8 +194,8 @@ func (l *LoopbackStorage) onDeleteStorageBucket(ctx context.Context, req *plgpb. if req.GetBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } - if req.Persisted == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } return &plgpb.OnDeleteStorageBucketResponse{}, nil } @@ -197,8 +208,8 @@ func (l *LoopbackStorage) validatePermissions(ctx context.Context, req *plgpb.Va if req.GetBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } - if req.GetBucket().GetSecrets() == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } l.m.Lock() defer l.m.Unlock() @@ -221,8 +232,8 @@ func (l *LoopbackStorage) headObject(ctx context.Context, req *plgpb.HeadObjectR if req.GetBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "$%s: missing storage bucket", op) } - if req.GetBucket().GetSecrets() == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } if req.GetKey() == "" { return nil, status.Errorf(codes.InvalidArgument, "%s; missing object key", op) @@ -261,8 +272,8 @@ func (l *LoopbackStorage) getObject(req *plgpb.GetObjectRequest, stream plgpb.St if req.GetBucket() == nil { return status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } - if req.GetBucket().GetSecrets() == nil { - return status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) + if req.GetBucket().GetAttributes() == nil { + return status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) } if req.GetKey() == "" { return status.Errorf(codes.InvalidArgument, "%s; missing object key", op) @@ -317,12 +328,12 @@ func (l *LoopbackStorage) putObject(ctx context.Context, req *plgpb.PutObjectReq if req.GetBucket() == nil { return nil, status.Errorf(codes.InvalidArgument, "%s: missing storage bucket", op) } + if req.GetBucket().GetAttributes() == nil { + return nil, status.Errorf(codes.InvalidArgument, "%s: missing attributes", op) + } if req.GetBucket().GetBucketName() == "" { return nil, status.Errorf(codes.InvalidArgument, "%s: missing bucket name", op) } - if req.GetBucket().GetSecrets() == nil { - return nil, status.Errorf(codes.InvalidArgument, "%s: missing secrets", op) - } if req.GetKey() == "" { return nil, status.Errorf(codes.InvalidArgument, "%s; missing object key", op) } diff --git a/internal/plugin/loopback/storage_test.go b/internal/plugin/loopback/storage_test.go index 9366d1795..73b0573a7 100644 --- a/internal/plugin/loopback/storage_test.go +++ b/internal/plugin/loopback/storage_test.go @@ -63,7 +63,7 @@ func TestLoopbackOnCreateStorageBucket(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.OnCreateStorageBucketRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", @@ -77,6 +77,11 @@ func TestLoopbackOnCreateStorageBucket(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "bucket_dne", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -87,16 +92,39 @@ func TestLoopbackOnCreateStorageBucket(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_err", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.PermissionDenied, }, { - name: "valid credentials", + name: "valid without credentials", + request: &plgpb.OnCreateStorageBucketRequest{ + Bucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + }, + { + name: "valid with credentials", request: &plgpb.OnCreateStorageBucketRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, }, @@ -164,11 +192,10 @@ func TestLoopbackOnUpdateStorageBucket(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.OnUpdateStorageBucketRequest{ NewBucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", - Secrets: secrets, }, }, expectedErr: codes.InvalidArgument, @@ -179,6 +206,11 @@ func TestLoopbackOnUpdateStorageBucket(t *testing.T) { NewBucket: &storagebuckets.StorageBucket{ BucketName: "bucket_dne", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Persisted: persisted, }, @@ -190,17 +222,40 @@ func TestLoopbackOnUpdateStorageBucket(t *testing.T) { NewBucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_err", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Persisted: persisted, }, expectedErr: codes.PermissionDenied, }, { - name: "valid credentials", + name: "valid without credentials", + request: &plgpb.OnUpdateStorageBucketRequest{ + NewBucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + }, + { + name: "valid with credentials", request: &plgpb.OnUpdateStorageBucketRequest{ NewBucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Persisted: persisted, }, @@ -259,21 +314,38 @@ func TestLoopbackOnDeleteStorageBucket(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.OnDeleteStorageBucketRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", - Secrets: secrets, }, }, expectedErr: codes.InvalidArgument, }, { - name: "valid credentials", + name: "valid without credentials", + request: &plgpb.OnDeleteStorageBucketRequest{ + Bucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + }, + { + name: "valid with credentials", request: &plgpb.OnDeleteStorageBucketRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Persisted: persisted, }, @@ -336,7 +408,7 @@ func TestLoopbackValidatePermissions(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.ValidatePermissionsRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", @@ -350,6 +422,11 @@ func TestLoopbackValidatePermissions(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "bucket_dne", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -360,16 +437,39 @@ func TestLoopbackValidatePermissions(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_err", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.PermissionDenied, }, { - name: "valid credentials", + name: "valid without credentials", + request: &plgpb.ValidatePermissionsRequest{ + Bucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + }, + { + name: "valid with credentials", request: &plgpb.ValidatePermissionsRequest{ Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, }, @@ -443,8 +543,9 @@ func TestLoopbackHeadObject(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.HeadObjectRequest{ + Key: "mock_object", Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", }, @@ -457,6 +558,11 @@ func TestLoopbackHeadObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.InvalidArgument, @@ -468,6 +574,11 @@ func TestLoopbackHeadObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "invalid_bucket", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -479,6 +590,11 @@ func TestLoopbackHeadObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -490,10 +606,30 @@ func TestLoopbackHeadObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_err", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.PermissionDenied, }, + { + name: "head retrieved without secrets", + request: &plgpb.HeadObjectRequest{ + Key: "mock_object", + Bucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + expectedObj: mockStorageMapData["aws_s3_mock"]["mock_object"], + }, { name: "head retrieved", request: &plgpb.HeadObjectRequest{ @@ -501,6 +637,11 @@ func TestLoopbackHeadObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedObj: mockStorageMapData["aws_s3_mock"]["mock_object"], @@ -578,8 +719,9 @@ func TestLoopbackGetObject(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing secrets", + name: "missing attributes", request: &plgpb.GetObjectRequest{ + Key: "mock_object", Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", }, @@ -592,6 +734,11 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.InvalidArgument, @@ -603,6 +750,11 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "invalid_bucket", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -614,6 +766,11 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.NotFound, @@ -625,6 +782,11 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_err", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.PermissionDenied, @@ -636,11 +798,31 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, ChunkSize: 3, }, expectedObj: mockStorageMapData["aws_s3_mock"]["mock_object"], }, + { + name: "object retrieved without secrets", + request: &plgpb.GetObjectRequest{ + Key: "mock_object", + Bucket: &storagebuckets.StorageBucket{ + BucketName: "aws_s3_mock", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + }, + expectedObj: mockStorageMapData["aws_s3_mock"]["mock_object"], + }, { name: "object retrieved", request: &plgpb.GetObjectRequest{ @@ -648,6 +830,11 @@ func TestLoopbackGetObject(t *testing.T) { Bucket: &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", Secrets: secrets, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedObj: mockStorageMapData["aws_s3_mock"]["mock_object"], @@ -733,17 +920,19 @@ func TestLoopbackPutObject(t *testing.T) { expectedErr: codes.InvalidArgument, }, { - name: "missing-bucket-name", - request: &plgpb.PutObjectRequest{ - Bucket: &storagebuckets.StorageBucket{}, - }, + name: "missing attributes", + expectedErr: codes.InvalidArgument, }, { - name: "missing-secrets", + name: "missing-bucket-name", request: &plgpb.PutObjectRequest{ Bucket: &storagebuckets.StorageBucket{ - BucketName: "object_store", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.InvalidArgument, @@ -758,6 +947,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, }, expectedErr: codes.InvalidArgument, @@ -772,6 +966,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "test-file", }, @@ -787,6 +986,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "test-file", Path: path.Join(td, "test-file"), @@ -803,6 +1007,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "test-directory", Path: path.Join(td, "test-directory"), @@ -824,6 +1033,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "test-bucket-not-found", Path: path.Join(td, "test-bucket-not-found"), @@ -845,6 +1059,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "mock_object", Path: path.Join(td, "test-bucket-not-found"), @@ -866,6 +1085,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "test-empty-object-data", Path: path.Join(td, "test-empty-object-data"), @@ -888,6 +1112,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "foo/bar/zoo/mocked_object", Path: path.Join(td, "test-valid-object-dir-in-key"), @@ -903,6 +1132,32 @@ func TestLoopbackPutObject(t *testing.T) { }(), expectedContent: "TEST OBJ WITH DIR IN KEY!", }, + { + name: "valid object without credentials", + request: &plgpb.PutObjectRequest{ + Bucket: &storagebuckets.StorageBucket{ + BucketName: "object_store", + BucketPrefix: "/filtered/", + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, + }, + Key: "mocked_object_no_credentials", + Path: path.Join(td, "test-valid-without-credentials"), + }, + file: func() *os.File { + file, err := os.Create(path.Join(td, "test-valid-without-credentials")) + require.NoError(err) + n, err := file.WriteString("TEST OBJ WITH NO CREDENTIALS!") + require.NoError(err) + require.Equal(len("TEST OBJ WITH NO CREDENTIALS!"), n) + require.NoError(file.Close()) + return file + }(), + expectedContent: "TEST OBJ WITH NO CREDENTIALS!", + }, { name: "valid object w/ prefix", request: &plgpb.PutObjectRequest{ @@ -914,6 +1169,11 @@ func TestLoopbackPutObject(t *testing.T) { "SECRET_KEY_ID": structpb.NewStringValue("secret_key_id"), }, }, + Attributes: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + }, }, Key: "mocked_object", Path: path.Join(td, "test-valid-object-prefix"), @@ -984,12 +1244,18 @@ func TestLoopbackStoragePlugin(t *testing.T) { "SECRET_ACCESS_KEY": structpb.NewStringValue("secret_access_key"), }, } + attributes := &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "endpoint": structpb.NewStringValue("0.0.0.0"), + }, + } objectData := "THIS IS A MOCKED OBJECT" bucket := &storagebuckets.StorageBucket{ BucketName: "aws_s3_mock", BucketPrefix: "/filtered/path/", Secrets: secrets, + Attributes: attributes, } file, err := os.Create(path.Join(td, "test-put-object")) diff --git a/internal/proto/controller/storage/storage/plugin/store/v1/storage.proto b/internal/proto/controller/storage/storage/plugin/store/v1/storage.proto index 8868cf73b..ad0075209 100644 --- a/internal/proto/controller/storage/storage/plugin/store/v1/storage.proto +++ b/internal/proto/controller/storage/storage/plugin/store/v1/storage.proto @@ -69,7 +69,7 @@ message StorageBucket { bytes attributes = 12; // secrets_hmac is a sha256-hmac of the unencrypted secrets stored in the db. - // @inject_tag: `gorm:"not_null"` + // @inject_tag: `gorm:"default:null"` bytes secrets_hmac = 13; } diff --git a/internal/storage/plugin/store/storage.pb.go b/internal/storage/plugin/store/storage.pb.go index 710c6383b..c80666366 100644 --- a/internal/storage/plugin/store/storage.pb.go +++ b/internal/storage/plugin/store/storage.pb.go @@ -68,8 +68,8 @@ type StorageBucket struct { // @inject_tag: `gorm:"not_null"` Attributes []byte `protobuf:"bytes,12,opt,name=attributes,proto3" json:"attributes,omitempty" gorm:"not_null"` // secrets_hmac is a sha256-hmac of the unencrypted secrets stored in the db. - // @inject_tag: `gorm:"not_null"` - SecretsHmac []byte `protobuf:"bytes,13,opt,name=secrets_hmac,json=secretsHmac,proto3" json:"secrets_hmac,omitempty" gorm:"not_null"` + // @inject_tag: `gorm:"default:null"` + SecretsHmac []byte `protobuf:"bytes,13,opt,name=secrets_hmac,json=secretsHmac,proto3" json:"secrets_hmac,omitempty" gorm:"default:null"` } func (x *StorageBucket) Reset() { diff --git a/plugins/boundary/mains/aws/go.mod b/plugins/boundary/mains/aws/go.mod index 9984dcbdd..1b650d6ad 100644 --- a/plugins/boundary/mains/aws/go.mod +++ b/plugins/boundary/mains/aws/go.mod @@ -3,24 +3,25 @@ module github.com/hashicorp/boundary/plugins/boundary/mains/aws go 1.20 require ( - github.com/hashicorp/boundary-plugin-aws v0.1.6 + github.com/hashicorp/boundary-plugin-aws v0.1.8 github.com/hashicorp/boundary/sdk v0.0.33 ) require ( github.com/aws/aws-sdk-go v1.44.214 // indirect - github.com/aws/aws-sdk-go-v2 v1.17.7 // indirect + github.com/aws/aws-sdk-go-v2 v1.18.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/config v1.18.19 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.99.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.31.1 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 // indirect @@ -39,7 +40,7 @@ require ( github.com/hashicorp/go-kms-wrapping/v2 v2.0.9 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.4.9 // indirect - github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 // indirect + github.com/hashicorp/go-secure-stdlib/awsutil v0.2.2 // indirect github.com/hashicorp/go-secure-stdlib/base62 v0.1.2 // indirect github.com/hashicorp/go-secure-stdlib/pluginutil/v2 v2.0.4 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect diff --git a/plugins/boundary/mains/aws/go.sum b/plugins/boundary/mains/aws/go.sum index 820682e9f..f8ceedd22 100644 --- a/plugins/boundary/mains/aws/go.sum +++ b/plugins/boundary/mains/aws/go.sum @@ -2,11 +2,12 @@ github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJ github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.44.214 h1:YzDuC+9UtrAOUkItlK7l3BvKI9o6qAog9X8i289HORc= github.com/aws/aws-sdk-go v1.44.214/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2 v1.18.0 h1:882kkTpSFhdgYRKVZ/VCgf7sd0ru57p2JCxz4/oN5RY= +github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= github.com/aws/aws-sdk-go-v2/config v1.18.19 h1:AqFK6zFNtq4i1EYu+eC7lcKHYnZagMn6SW171la0bGw= @@ -15,20 +16,25 @@ github.com/aws/aws-sdk-go-v2/credentials v1.13.18 h1:EQMdtHwz0ILTW1hoP+EwuWhwCG1 github.com/aws/aws-sdk-go-v2/credentials v1.13.18/go.mod h1:vnwlwjIe+3XJPBYKu1et30ZPABG3VaXJYr8ryohpIyM= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 h1:gt57MN3liKiyGopcqgNzJb2+d9MJaKT/q1OksHNXVE4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1/go.mod h1:lfUx8puBRdM5lVVMQlwt2v+ofiG/X6Ms+dy0UkG/kXw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 h1:kG5eQilShqmJbv11XL1VpyDbaEJzWxd4zRiCG30GSn4= +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/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 h1:vFQlirhuM8lLlpI7imKOMsjdQLuN9CPi+k44F/OFVsk= +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/ini v1.3.32 h1:p5luUImdIqywn6JpQsW3tq5GNOxKmOnEpybzPx+d1lk= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32/go.mod h1:XGhIBZDEgfqmFIugclZ6FU7v75nHhBDtzuB4xB/tEi4= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 h1:DWYZIsyqagnWL00f8M/SOr9fN063OEQWn9LLTbdYXsk= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23/go.mod h1:uIiFgURZbACBEQJfqTZPb/jxO7R+9LeoHUFudtIdeQI= +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/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 h1:CeuSeq/8FnYpPtnuIeLQEEvDv9zUjneuYi8EghMBdwQ= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 h1:5LHn8JQ0qvjD9L9JhMtylnkcw7j05GDZqM9Oin6hpr0= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 h1:0iKliEXAcCa2qVtRs7Ot5hItA2MsufrphbRFlz1Owxo= +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/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8= github.com/aws/aws-sdk-go-v2/service/s3 v1.31.1 h1:PJH4I+qYjPXclKRbVCW47iYUvtXEh1u6YmDhn5J8VQE= @@ -46,7 +52,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= @@ -62,8 +67,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/boundary-plugin-aws v0.1.6 h1:JfEWdmz44iJmXvOZYl3UCBbyzP5m73eIlOpSu3jjos4= -github.com/hashicorp/boundary-plugin-aws v0.1.6/go.mod h1:nZFpoJ5OHE21s3tH9zxjOsA4vm8gMbykmeL728a+K4I= +github.com/hashicorp/boundary-plugin-aws v0.1.8 h1:A/GvBUvo85+wvRXt4f3qSPzEEvXeQDdjFSBFMBCNAoc= +github.com/hashicorp/boundary-plugin-aws v0.1.8/go.mod h1:2cScmnFh5SCQWYtUKkA+6FcGXui1sU/lu2bPcEZ9RQk= github.com/hashicorp/boundary/sdk v0.0.33 h1:kHaVZ3b9j1QvYlG+vhAgrbXh8/+Rq2qlUIs8fKMQH7k= github.com/hashicorp/boundary/sdk v0.0.33/go.mod h1:jn9j5mM8v2pOk8aLeJNIszdm7WBf4gRSP68iy8Iu5Q0= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -75,7 +80,6 @@ github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20230428153751-cca4458 github.com/hashicorp/eventlogger/filters/encrypt v0.1.8-0.20230428153751-cca445805f24/go.mod h1:EQPLoX6CONA9BSYUovTQBHfPGE91g7wOxv03sO29FzY= 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 v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 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-kms-wrapping/plugin/v2 v2.0.4 h1:8z+Zi0uLYXONkxwWb/D7O5t1IUucB6Ft3uvSOa950bM= @@ -85,8 +89,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-plugin v1.4.9 h1:ESiK220/qE0aGxWdzKIvRH69iLiuN/PjoLTm69RoWtU= github.com/hashicorp/go-plugin v1.4.9/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= -github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6 h1:W9WN8p6moV1fjKLkeqEgkAMu5rauy9QeYDAmIaPuuiA= -github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg= +github.com/hashicorp/go-secure-stdlib/awsutil v0.2.2 h1:kWg2vyKl7BRXrNxYziqDJ55n+vtOQ1QsGORjzoeB+uM= +github.com/hashicorp/go-secure-stdlib/awsutil v0.2.2/go.mod h1:oKHSQs4ivIfZ3fbXGQOop1XuDfdSb8RIsWTGaAanSfg= 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= @@ -123,14 +127,10 @@ 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.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 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= @@ -167,7 +167,6 @@ github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -207,12 +206,9 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=