From 51e0aa992c54367fbd4ffb51976855f739834a2c Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 02:06:51 -0800 Subject: [PATCH 01/22] Azure Blobstorage Binding: Migrate to Track2 Azure SDK Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 282 ++++++++++-------- .../azure/blobstorage/blobstorage_test.go | 10 +- go.mod | 3 +- go.sum | 6 +- .../azure/blobstorage/blobstorage_test.go | 46 +-- .../bindings/azure/blobstorage/go.mod | 4 +- .../bindings/azure/blobstorage/go.sum | 8 +- .../bindings/azure/cosmosdb/go.mod | 2 +- .../bindings/azure/cosmosdb/go.sum | 4 +- .../bindings/azure/eventhubs/go.mod | 2 +- .../bindings/azure/eventhubs/go.sum | 4 +- .../bindings/azure/servicebusqueues/go.mod | 2 +- .../bindings/azure/servicebusqueues/go.sum | 4 +- .../bindings/azure/storagequeues/go.mod | 2 +- .../bindings/azure/storagequeues/go.sum | 4 +- .../pubsub/azure/eventhubs/go.mod | 2 +- .../pubsub/azure/eventhubs/go.sum | 4 +- .../pubsub/azure/servicebus/topics/go.mod | 2 +- .../pubsub/azure/servicebus/topics/go.sum | 4 +- .../secretstores/azure/keyvault/go.mod | 2 +- .../secretstores/azure/keyvault/go.sum | 4 +- .../state/azure/blobstorage/go.mod | 2 +- .../state/azure/blobstorage/go.sum | 4 +- .../certification/state/azure/cosmosdb/go.mod | 2 +- .../certification/state/azure/cosmosdb/go.sum | 4 +- .../state/azure/tablestorage/go.mod | 2 +- .../state/azure/tablestorage/go.sum | 4 +- 27 files changed, 235 insertions(+), 184 deletions(-) diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index ddcd2f8e0..34d10f2ae 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -14,24 +14,29 @@ limitations under the License. package blobstorage import ( + "bytes" "context" b64 "encoding/base64" "encoding/json" "errors" "fmt" - "io" "net/url" "strconv" - "strings" "time" - "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" "github.com/google/uuid" "github.com/dapr/components-contrib/bindings" azauth "github.com/dapr/components-contrib/internal/authentication/azure" mdutils "github.com/dapr/components-contrib/metadata" "github.com/dapr/kit/logger" + "github.com/dapr/kit/ptr" ) const ( @@ -63,25 +68,28 @@ const ( // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // specify maxresults the server will return up to 5,000 items. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters - maxResults = 5000 + maxResults = 5000 + endpointKey = "endpoint" ) var ErrMissingBlobName = errors.New("blobName is a required attribute") // AzureBlobStorage allows saving blobs to an Azure Blob Storage account. type AzureBlobStorage struct { - metadata *blobStorageMetadata - containerURL azblob.ContainerURL + metadata *blobStorageMetadata + // containerURL azblob.ContainerURL + containerClient *container.Client logger logger.Logger } type blobStorageMetadata struct { - AccountName string - Container string - GetBlobRetryCount int - DecodeBase64 bool - PublicAccessLevel azblob.PublicAccessType + StorageAccount string `json:"storageAccount"` + StorageAccessKey string `json:"storageAccessKey"` + Container string `json:"container"` + GetBlobRetryCount int `json:"getBlobRetryCount,string"` + DecodeBase64 bool `json:"decodeBase64,string"` + PublicAccessLevel azblob.PublicAccessType `json:"publicAccessLevel"` } type createResponse struct { @@ -117,79 +125,100 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { } a.metadata = m - credential, env, err := azauth.GetAzureStorageBlobCredentials(a.logger, m.AccountName, metadata.Properties) - if err != nil { - return fmt.Errorf("invalid credentials with error: %s", err.Error()) - } - userAgent := "dapr-" + logger.DaprVersion - options := azblob.PipelineOptions{ - Telemetry: azblob.TelemetryOptions{Value: userAgent}, + options := container.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Retry: policy.RetryOptions{ + MaxRetries: int32(a.metadata.GetBlobRetryCount), + }, + Telemetry: policy.TelemetryOptions{ + ApplicationID: userAgent, + }, + }, } - p := azblob.NewPipeline(credential, options) - var containerURL azblob.ContainerURL - customEndpoint, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageEndpointKeys...) + settings, err := azauth.NewEnvironmentSettings("storage", metadata.Properties) + if err != nil { + return err + } + customEndpoint, ok := metadata.Properties[endpointKey] + var URL *url.URL if ok && customEndpoint != "" { - URL, parseErr := url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.Container)) + var parseErr error + URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.StorageAccount, m.Container)) if parseErr != nil { return parseErr } - containerURL = azblob.NewContainerURL(*URL, p) } else { - URL, _ := url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.Container)) - containerURL = azblob.NewContainerURL(*URL, p) + env := settings.AzureEnvironment + URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.StorageAccount, env.StorageEndpointSuffix, m.Container)) } - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - _, err = containerURL.Create(ctx, azblob.Metadata{}, m.PublicAccessLevel) + var clientErr error + var client *container.Client + // Try using shared key credentials first + if m.StorageAccessKey != "" { + credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.StorageAccount, m.StorageAccessKey) + if err != nil { + return fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) + } + client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) + if clientErr != nil { + return fmt.Errorf("cannot init Blobstorage container client: %w", err) + } + container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) + a.containerClient = client + } else { + // fallback to AAD + credential, tokenErr := settings.GetTokenCredential() + if err != nil { + return fmt.Errorf("invalid credentials with error: %w", tokenErr) + } + client, clientErr = container.NewClient(URL.String(), credential, &options) + } + if clientErr != nil { + return fmt.Errorf("cannot init Blobstorage client: %w", clientErr) + } + + createContainerOptions := container.CreateOptions{ + Access: &m.PublicAccessLevel, + Metadata: map[string]string{}, + } + timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + _, err = client.Create(timeoutCtx, &createContainerOptions) cancel() // Don't return error, container might already exist a.logger.Debugf("error creating container: %w", err) - a.containerURL = containerURL + a.containerClient = client return nil } -func (a *AzureBlobStorage) parseMetadata(metadata bindings.Metadata) (*blobStorageMetadata, error) { - var m blobStorageMetadata - if val, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageAccountNameKeys...); ok && val != "" { - m.AccountName = val +func (a *AzureBlobStorage) parseMetadata(meta bindings.Metadata) (*blobStorageMetadata, error) { + m := blobStorageMetadata{ + GetBlobRetryCount: defaultGetBlobRetryCount, + } + mdutils.DecodeMetadata(meta.Properties, &m) + + if val, ok := mdutils.GetMetadataProperty(meta.Properties, azauth.StorageAccountNameKeys...); ok && val != "" { + m.StorageAccount = val } else { return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0]) } - if val, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageContainerNameKeys...); ok && val != "" { + if val, ok := mdutils.GetMetadataProperty(meta.Properties, azauth.StorageContainerNameKeys...); ok && val != "" { m.Container = val } else { return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0]) } - m.GetBlobRetryCount = defaultGetBlobRetryCount - if val, ok := metadata.Properties["getBlobRetryCount"]; ok { - n, err := strconv.Atoi(val) - if err != nil || n == 0 { - return nil, fmt.Errorf("invalid getBlobRetryCount field from metadata") - } - m.GetBlobRetryCount = n - } - - m.DecodeBase64 = false - if val, ok := metadata.Properties["decodeBase64"]; ok { - n, err := strconv.ParseBool(val) - if err != nil { - return nil, fmt.Errorf("invalid decodeBase64 field from metadata") - } - m.DecodeBase64 = n - } - - m.PublicAccessLevel = azblob.PublicAccessType(strings.ToLower(metadata.Properties["publicAccessLevel"])) // per the Dapr documentation "none" is a valid value if m.PublicAccessLevel == "none" { m.PublicAccessLevel = "" } - if !a.isValidPublicAccessType(m.PublicAccessLevel) { - return nil, fmt.Errorf("invalid public access level: %s; allowed: %s", m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues()) + if m.PublicAccessLevel != "" && !a.isValidPublicAccessType(m.PublicAccessLevel) { + return nil, fmt.Errorf("invalid public access level: %s; allowed: %s", + m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues()) } return &m, nil @@ -205,8 +234,6 @@ func (a *AzureBlobStorage) Operations() []bindings.OperationKind { } func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { - var blobHTTPHeaders azblob.BlobHTTPHeaders - var blobURL azblob.BlockBlobURL var blobName string if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { blobName = val @@ -214,34 +241,38 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque } else { blobName = uuid.New().String() } - blobURL = a.getBlobURL(blobName) + + blobHTTPHeaders := blob.HTTPHeaders{} if val, ok := req.Metadata[metadataKeyContentType]; ok && val != "" { - blobHTTPHeaders.ContentType = val + blobHTTPHeaders.BlobContentType = ptr.Of(val) delete(req.Metadata, metadataKeyContentType) } + var contentMD5 *[]byte + if val, ok := req.Metadata[metadataKeyContentMD5]; ok && val != "" { sDec, err := b64.StdEncoding.DecodeString(val) if err != nil || len(sDec) != 16 { return nil, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") } - blobHTTPHeaders.ContentMD5 = sDec + blobHTTPHeaders.BlobContentMD5 = sDec + contentMD5 = &sDec delete(req.Metadata, metadataKeyContentMD5) } if val, ok := req.Metadata[metadataKeyContentEncoding]; ok && val != "" { - blobHTTPHeaders.ContentEncoding = val + blobHTTPHeaders.BlobContentEncoding = ptr.Of(val) delete(req.Metadata, metadataKeyContentEncoding) } if val, ok := req.Metadata[metadataKeyContentLanguage]; ok && val != "" { - blobHTTPHeaders.ContentLanguage = val + blobHTTPHeaders.BlobContentLanguage = ptr.Of(val) delete(req.Metadata, metadataKeyContentLanguage) } if val, ok := req.Metadata[metadataKeyContentDisposition]; ok && val != "" { - blobHTTPHeaders.ContentDisposition = val + blobHTTPHeaders.BlobContentDisposition = ptr.Of(val) delete(req.Metadata, metadataKeyContentDisposition) } if val, ok := req.Metadata[metadataKeyCacheControl]; ok && val != "" { - blobHTTPHeaders.CacheControl = val + blobHTTPHeaders.BlobCacheControl = ptr.Of(val) delete(req.Metadata, metadataKeyCacheControl) } @@ -258,17 +289,22 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque req.Data = decoded } - _, err = azblob.UploadBufferToBlockBlob(ctx, req.Data, blobURL, azblob.UploadToBlockBlobOptions{ - Parallelism: 16, - Metadata: a.sanitizeMetadata(req.Metadata), - BlobHTTPHeaders: blobHTTPHeaders, - }) + uploadOptions := azblob.UploadBufferOptions{ + Metadata: a.sanitizeMetadata(req.Metadata), + HTTPHeaders: &blobHTTPHeaders, + Concurrency: 16, + TransactionalContentMD5: contentMD5, + } + + blockBlobClient := a.containerClient.NewBlockBlobClient(blobName) + _, err = blockBlobClient.UploadBuffer(ctx, req.Data, &uploadOptions) + if err != nil { return nil, fmt.Errorf("error uploading az blob: %w", err) } resp := createResponse{ - BlobURL: blobURL.String(), + BlobURL: blockBlobClient.URL(), } b, err := json.Marshal(resp) if err != nil { @@ -286,23 +322,30 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque } func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { - var blobURL azblob.BlockBlobURL + var blockBlobClient *blockblob.Client if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { - blobURL = a.getBlobURL(val) + blockBlobClient = a.containerClient.NewBlockBlobClient(val) } else { return nil, ErrMissingBlobName } - resp, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false) + downloadOptions := azblob.DownloadStreamOptions{ + AccessConditions: &blob.AccessConditions{}, + } + + blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, &downloadOptions) if err != nil { return nil, fmt.Errorf("error downloading az blob: %w", err) } - - bodyStream := resp.Body(azblob.RetryReaderOptions{MaxRetryRequests: a.metadata.GetBlobRetryCount}) - - data, err := io.ReadAll(bodyStream) + blobData := &bytes.Buffer{} + reader := blobDownloadResponse.Body + _, err = blobData.ReadFrom(reader) if err != nil { - return nil, fmt.Errorf("error reading az blob body: %w", err) + return nil, fmt.Errorf("error reading az blob: %w", err) + } + err = reader.Close() + if err != nil { + return nil, fmt.Errorf("error closing az blob reader: %w", err) } var metadata map[string]string @@ -311,45 +354,54 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) return nil, fmt.Errorf("error parsing metadata: %w", err) } + getPropertiesOptions := blob.GetPropertiesOptions{ + AccessConditions: &blob.AccessConditions{}, + } + if fetchMetadata { - props, err := blobURL.GetProperties(ctx, azblob.BlobAccessConditions{}) + props, err := blockBlobClient.GetProperties(ctx, &getPropertiesOptions) if err != nil { return nil, fmt.Errorf("error reading blob metadata: %w", err) } - metadata = props.NewMetadata() + metadata = props.Metadata } return &bindings.InvokeResponse{ - Data: data, + Data: blobData.Bytes(), Metadata: metadata, }, nil } func (a *AzureBlobStorage) delete(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { - var blobURL azblob.BlockBlobURL - if val, ok := req.Metadata[metadataKeyBlobName]; ok && val != "" { - blobURL = a.getBlobURL(val) - } else { + var blockBlobClient *blockblob.Client + val, ok := req.Metadata[metadataKeyBlobName] + if !ok || val == "" { return nil, ErrMissingBlobName } - deleteSnapshotsOptions := azblob.DeleteSnapshotsOptionNone - if val, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" { - deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(val) + var deleteSnapshotsOptions blob.DeleteSnapshotsOptionType + if deleteSnapShotOption, ok := req.Metadata[metadataKeyDeleteSnapshots]; ok && val != "" { + deleteSnapshotsOptions = azblob.DeleteSnapshotsOptionType(deleteSnapShotOption) if !a.isValidDeleteSnapshotsOptionType(deleteSnapshotsOptions) { return nil, fmt.Errorf("invalid delete snapshot option type: %s; allowed: %s", deleteSnapshotsOptions, azblob.PossibleDeleteSnapshotsOptionTypeValues()) } } - _, err := blobURL.Delete(ctx, deleteSnapshotsOptions, azblob.BlobAccessConditions{}) + deleteOptions := blob.DeleteOptions{ + DeleteSnapshots: &deleteSnapshotsOptions, + AccessConditions: &blob.AccessConditions{}, + } + + blockBlobClient = a.containerClient.NewBlockBlobClient(val) + _, err := blockBlobClient.Delete(context.Background(), &deleteOptions) return nil, err } func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { - options := azblob.ListBlobsSegmentOptions{} + options := container.ListBlobsFlatOptions{} hasPayload := false var payload listPayload @@ -360,50 +412,52 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest } hasPayload = true } - if hasPayload { - options.Details.Copy = payload.Include.Copy - options.Details.Metadata = payload.Include.Metadata - options.Details.Snapshots = payload.Include.Snapshots - options.Details.UncommittedBlobs = payload.Include.UncommittedBlobs - options.Details.Deleted = payload.Include.Deleted + options.Include.Copy = payload.Include.Copy + options.Include.Metadata = payload.Include.Metadata + options.Include.Snapshots = payload.Include.Snapshots + options.Include.UncommittedBlobs = payload.Include.UncommittedBlobs + options.Include.Deleted = payload.Include.Deleted } if hasPayload && payload.MaxResults != int32(0) { - options.MaxResults = payload.MaxResults + options.MaxResults = ptr.Of(payload.MaxResults) } else { - options.MaxResults = maxResults + options.MaxResults = ptr.Of(int32(maxResults)) } if hasPayload && payload.Prefix != "" { - options.Prefix = payload.Prefix + options.Prefix = ptr.Of(payload.Prefix) } - var initialMarker azblob.Marker + var initialMarker string if hasPayload && payload.Marker != "" { - initialMarker = azblob.Marker{Val: &payload.Marker} + initialMarker = payload.Marker } else { - initialMarker = azblob.Marker{} + initialMarker = "" } + options.Marker = ptr.Of(initialMarker) - var blobs []azblob.BlobItem metadata := map[string]string{} - for currentMaker := initialMarker; currentMaker.NotDone(); { - var listBlob *azblob.ListBlobsFlatSegmentResponse - listBlob, err := a.containerURL.ListBlobsFlatSegment(ctx, currentMaker, options) + blobs := []*container.BlobItem{} + pager := a.containerClient.NewListBlobsFlatPager(&options) + + for pager.More() { + resp, err := pager.NextPage(ctx) if err != nil { return nil, fmt.Errorf("error listing blobs: %w", err) } - blobs = append(blobs, listBlob.Segment.BlobItems...) - + blobs = append(blobs, resp.Segment.BlobItems...) numBlobs := len(blobs) - currentMaker = listBlob.NextMarker - metadata[metadataKeyMarker] = *currentMaker.Val metadata[metadataKeyNumber] = strconv.FormatInt(int64(numBlobs), 10) + metadata[metadataKeyMarker] = "" + if resp.Marker != nil { + metadata[metadataKeyMarker] = *resp.Marker + } - if options.MaxResults-maxResults > 0 { - options.MaxResults -= maxResults + if *options.MaxResults-maxResults > 0 { + *options.MaxResults -= maxResults } else { break } @@ -435,12 +489,6 @@ func (a *AzureBlobStorage) Invoke(ctx context.Context, req *bindings.InvokeReque } } -func (a *AzureBlobStorage) getBlobURL(name string) azblob.BlockBlobURL { - blobURL := a.containerURL.NewBlockBlobURL(name) - - return blobURL -} - func (a *AzureBlobStorage) isValidPublicAccessType(accessType azblob.PublicAccessType) bool { validTypes := azblob.PossiblePublicAccessTypeValues() for _, item := range validTypes { diff --git a/bindings/azure/blobstorage/blobstorage_test.go b/bindings/azure/blobstorage/blobstorage_test.go index d0a459141..52810feab 100644 --- a/bindings/azure/blobstorage/blobstorage_test.go +++ b/bindings/azure/blobstorage/blobstorage_test.go @@ -17,7 +17,7 @@ import ( "context" "testing" - "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/stretchr/testify/assert" "github.com/dapr/components-contrib/bindings" @@ -39,11 +39,11 @@ func TestParseMetadata(t *testing.T) { meta, err := blobStorage.parseMetadata(m) assert.Nil(t, err) assert.Equal(t, "test", meta.Container) - assert.Equal(t, "account", meta.AccountName) + assert.Equal(t, "account", meta.StorageAccount) // storageAccessKey is parsed in the azauth package assert.Equal(t, true, meta.DecodeBase64) assert.Equal(t, 5, meta.GetBlobRetryCount) - assert.Equal(t, azblob.PublicAccessNone, meta.PublicAccessLevel) + assert.Equal(t, "", string(meta.PublicAccessLevel)) }) t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) { @@ -55,7 +55,7 @@ func TestParseMetadata(t *testing.T) { } meta, err := blobStorage.parseMetadata(m) assert.Nil(t, err) - assert.Equal(t, azblob.PublicAccessBlob, meta.PublicAccessLevel) + assert.Equal(t, azblob.PublicAccessTypeBlob, meta.PublicAccessLevel) }) t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) { @@ -67,7 +67,7 @@ func TestParseMetadata(t *testing.T) { } meta, err := blobStorage.parseMetadata(m) assert.Nil(t, err) - assert.Equal(t, azblob.PublicAccessContainer, meta.PublicAccessLevel) + assert.Equal(t, azblob.PublicAccessTypeContainer, meta.PublicAccessLevel) }) t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) { diff --git a/go.mod b/go.mod index 5b94f3034..84ce825b3 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 github.com/Azure/azure-storage-blob-go v0.10.0 github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd github.com/Azure/go-amqp v0.17.5 @@ -133,7 +134,7 @@ require ( github.com/99designs/keyring v1.2.1 // indirect github.com/AthenZ/athenz v1.10.39 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect diff --git a/go.sum b/go.sum index 13862b899..72cb6d3dc 100644 --- a/go.sum +++ b/go.sum @@ -110,14 +110,16 @@ github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4c github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 h1:bFa9IcjvrCber6gGgDAUZ+I2bO8J7s8JxXmu9fhi2ss= github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1/go.mod h1:l3wvZkG9oW07GLBW5Cd0WwG5asOfJ8aqE8raUvNzLpk= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= diff --git a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go index 964b2910d..ad715e91b 100644 --- a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go +++ b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go @@ -39,6 +39,8 @@ import ( "github.com/dapr/components-contrib/tests/certification/flow/sidecar" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" ) const ( @@ -192,12 +194,12 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") // deleting the key again should fail. _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, "") assert.Error(t, invokeDeleteErr2) - assert.Contains(t, invokeDeleteErr2.Error(), "ServiceCode=BlobNotFound") + assert.Contains(t, invokeDeleteErr2.Error(), "ERROR CODE: BlobNotFound") return nil } @@ -230,7 +232,7 @@ func TestBlobStorage(t *testing.T) { _, invokeCreateErr := client.InvokeBinding(ctx, invokeCreateRequest) assert.Error(t, invokeCreateErr) - assert.Contains(t, invokeCreateErr.Error(), "ServiceCode=Md5Mismatch") + assert.Contains(t, invokeCreateErr.Error(), "ERROR CODE: Md5Mismatch") return nil } @@ -279,7 +281,7 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") return nil } @@ -384,9 +386,9 @@ func TestBlobStorage(t *testing.T) { out, invokeGetErr := client.InvokeBinding(ctx, invokeGetRequest) assert.NoError(t, invokeGetErr) - assert.Equal(t, string(out.Data), input) - assert.Contains(t, out.Metadata, "custom") - assert.Equal(t, out.Metadata["custom"], "hello-world") + assert.Equal(t, input, string(out.Data)) + assert.Contains(t, out.Metadata, "Custom") + assert.Equal(t, "hello-world", out.Metadata["Custom"]) out, invokeErr := listBlobRequest(ctx, client, "", "", -1, true, false, false, false, false) assert.NoError(t, invokeErr) @@ -419,7 +421,7 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, "filename.txt", false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ServiceCode=BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") return nil } @@ -505,8 +507,8 @@ func TestBlobStorage(t *testing.T) { unmarshalErr := json.Unmarshal(out.Data, &output) assert.NoError(t, unmarshalErr) - assert.Equal(t, len(output), 1) - assert.Equal(t, output[0]["Name"], "prefixA/filename.txt") + assert.Equal(t, 1, len(output)) + assert.Contains(t, output[0]["Name"], "prefixA") nextMarker := out.Metadata["marker"] @@ -518,8 +520,8 @@ func TestBlobStorage(t *testing.T) { err2 := json.Unmarshal(out2.Data, &output2) assert.NoError(t, err2) - assert.Equal(t, len(output2), 1) - assert.Equal(t, output2[0]["Name"], "prefixAfilename.txt") + assert.Equal(t, 1, len(output2)) + assert.Contains(t, output2[0]["Name"], "prefixA") // cleanup. _, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", "") @@ -530,15 +532,15 @@ func TestBlobStorage(t *testing.T) { assert.NoError(t, invokeDeleteErr3) // list deleted items with prefix. - out3, listErr3 := listBlobRequest(ctx, client, "prefixA", "", -1, false, false, false, false, true) + out3, listErr3 := listBlobRequest(ctx, client, "prefixA/", "", -1, false, false, false, false, true) assert.NoError(t, listErr3) // this will only return the deleted items if soft delete policy is enabled for the blob service. - assert.Equal(t, out3.Metadata["number"], "2") + assert.Equal(t, "1", out3.Metadata["number"]) var output3 []map[string]interface{} err3 := json.Unmarshal(out3.Data, &output3) assert.NoError(t, err3) - assert.Equal(t, len(output3), 2) + assert.Equal(t, len(output3), 1) return nil } @@ -553,17 +555,15 @@ func TestBlobStorage(t *testing.T) { defer client.Close() cred, _ := azblob.NewSharedKeyCredential(os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageAccessKey")) - service, _ := azblob.NewServiceClientWithSharedKey(fmt.Sprintf("https://%s.blob.core.windows.net/", os.Getenv("AzureBlobStorageAccount")), cred, nil) - containerClient, _ := service.NewContainerClient(os.Getenv("AzureBlobStorageContainer")) + containerClient, _ := container.NewClientWithSharedKeyCredential(fmt.Sprintf("https://%s.blob.core.windows.net/%s", os.Getenv("AzureBlobStorageAccount"), os.Getenv("AzureBlobStorageContainer")), cred, nil) - blobClient, _ := containerClient.NewBlockBlobClient("snapshotthis.txt") - uploadResp, uploadErr := blobClient.UploadBuffer( + blobClient := containerClient.NewBlockBlobClient("snapshotthis.txt") + _, uploadErr := blobClient.UploadBuffer( ctx, []byte("some example content"), - azblob.UploadOption{}) //nolint:exhaustivestruct + &azblob.UploadBufferOptions{}) //nolint:exhaustivestruct assert.NoError(t, uploadErr) - uploadResp.Body.Close() _, createSnapshotErr := blobClient.CreateSnapshot( - ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct + ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct assert.NoError(t, createSnapshotErr) // list the contents of the container including snapshots for the specific blob only. @@ -582,7 +582,7 @@ func TestBlobStorage(t *testing.T) { // create another snapshot. _, createSnapshotErr2 := blobClient.CreateSnapshot( - ctx, &azblob.BlobCreateSnapshotOptions{}) //nolint:exhaustivestruct + ctx, &blob.CreateSnapshotOptions{}) //nolint:exhaustivestruct assert.NoError(t, createSnapshotErr2) // delete base blob and snapshots all at once. diff --git a/tests/certification/bindings/azure/blobstorage/go.mod b/tests/certification/bindings/azure/blobstorage/go.mod index df4503ea5..39df468c9 100644 --- a/tests/certification/bindings/azure/blobstorage/go.mod +++ b/tests/certification/bindings/azure/blobstorage/go.mod @@ -3,7 +3,7 @@ module github.com/dapr/components-contrib/tests/certification/bindings/azure/blo go 1.19 require ( - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e @@ -19,7 +19,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/bindings/azure/blobstorage/go.sum b/tests/certification/bindings/azure/blobstorage/go.sum index 3a90fb97c..0200c2d33 100644 --- a/tests/certification/bindings/azure/blobstorage/go.sum +++ b/tests/certification/bindings/azure/blobstorage/go.sum @@ -45,10 +45,10 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= diff --git a/tests/certification/bindings/azure/cosmosdb/go.mod b/tests/certification/bindings/azure/cosmosdb/go.mod index fd5bfac03..886fc97c8 100644 --- a/tests/certification/bindings/azure/cosmosdb/go.mod +++ b/tests/certification/bindings/azure/cosmosdb/go.mod @@ -22,7 +22,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/bindings/azure/cosmosdb/go.sum b/tests/certification/bindings/azure/cosmosdb/go.sum index b63e24fa2..82ff71cf6 100644 --- a/tests/certification/bindings/azure/cosmosdb/go.sum +++ b/tests/certification/bindings/azure/cosmosdb/go.sum @@ -49,8 +49,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4Sath github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 h1:yJegJqjhrMJ3Oe5s43jOTGL2AsE7pJyx+7Yqls/65tw= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4cZn6oIxYYqKB2FG3rBDxk3NZDLDJCHl+Q= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= diff --git a/tests/certification/bindings/azure/eventhubs/go.mod b/tests/certification/bindings/azure/eventhubs/go.mod index 231983040..e700c189c 100644 --- a/tests/certification/bindings/azure/eventhubs/go.mod +++ b/tests/certification/bindings/azure/eventhubs/go.mod @@ -22,7 +22,7 @@ require ( github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-amqp v0.17.5 // indirect diff --git a/tests/certification/bindings/azure/eventhubs/go.sum b/tests/certification/bindings/azure/eventhubs/go.sum index 6e62d9e58..2ffcf1e77 100644 --- a/tests/certification/bindings/azure/eventhubs/go.sum +++ b/tests/certification/bindings/azure/eventhubs/go.sum @@ -51,8 +51,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= diff --git a/tests/certification/bindings/azure/servicebusqueues/go.mod b/tests/certification/bindings/azure/servicebusqueues/go.mod index b03a1078a..3f276e42d 100644 --- a/tests/certification/bindings/azure/servicebusqueues/go.mod +++ b/tests/certification/bindings/azure/servicebusqueues/go.mod @@ -19,7 +19,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect diff --git a/tests/certification/bindings/azure/servicebusqueues/go.sum b/tests/certification/bindings/azure/servicebusqueues/go.sum index d6685e8d6..aab8e8327 100644 --- a/tests/certification/bindings/azure/servicebusqueues/go.sum +++ b/tests/certification/bindings/azure/servicebusqueues/go.sum @@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= diff --git a/tests/certification/bindings/azure/storagequeues/go.mod b/tests/certification/bindings/azure/storagequeues/go.mod index 64645190d..6698ef29e 100644 --- a/tests/certification/bindings/azure/storagequeues/go.mod +++ b/tests/certification/bindings/azure/storagequeues/go.mod @@ -19,7 +19,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/bindings/azure/storagequeues/go.sum b/tests/certification/bindings/azure/storagequeues/go.sum index b9d06c9b6..9776a9019 100644 --- a/tests/certification/bindings/azure/storagequeues/go.sum +++ b/tests/certification/bindings/azure/storagequeues/go.sum @@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= diff --git a/tests/certification/pubsub/azure/eventhubs/go.mod b/tests/certification/pubsub/azure/eventhubs/go.mod index 7055be7b1..a49ec755b 100644 --- a/tests/certification/pubsub/azure/eventhubs/go.mod +++ b/tests/certification/pubsub/azure/eventhubs/go.mod @@ -22,7 +22,7 @@ require ( github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-amqp v0.17.5 // indirect diff --git a/tests/certification/pubsub/azure/eventhubs/go.sum b/tests/certification/pubsub/azure/eventhubs/go.sum index 7848bdb15..bba9d03a7 100644 --- a/tests/certification/pubsub/azure/eventhubs/go.sum +++ b/tests/certification/pubsub/azure/eventhubs/go.sum @@ -51,8 +51,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.6.0/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= diff --git a/tests/certification/pubsub/azure/servicebus/topics/go.mod b/tests/certification/pubsub/azure/servicebus/topics/go.mod index 62e0f47b8..eaf00930e 100644 --- a/tests/certification/pubsub/azure/servicebus/topics/go.mod +++ b/tests/certification/pubsub/azure/servicebus/topics/go.mod @@ -20,7 +20,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect diff --git a/tests/certification/pubsub/azure/servicebus/topics/go.sum b/tests/certification/pubsub/azure/servicebus/topics/go.sum index d6685e8d6..aab8e8327 100644 --- a/tests/certification/pubsub/azure/servicebus/topics/go.sum +++ b/tests/certification/pubsub/azure/servicebus/topics/go.sum @@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1 h1:Zm7A6yKHT3evC/0lquPWJ9hrkRGVIeZOmIvHPv6xV9Q= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.1.1/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= diff --git a/tests/certification/secretstores/azure/keyvault/go.mod b/tests/certification/secretstores/azure/keyvault/go.mod index 77c7dd5d7..50595d243 100644 --- a/tests/certification/secretstores/azure/keyvault/go.mod +++ b/tests/certification/secretstores/azure/keyvault/go.mod @@ -18,7 +18,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect diff --git a/tests/certification/secretstores/azure/keyvault/go.sum b/tests/certification/secretstores/azure/keyvault/go.sum index b6d23539f..4fa12be75 100644 --- a/tests/certification/secretstores/azure/keyvault/go.sum +++ b/tests/certification/secretstores/azure/keyvault/go.sum @@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1 h1:AhZnZn4kUKz36bHJ8AK/FH2tH/q3CAkG+Gme+2ibuak= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.10.1/go.mod h1:S78i9yTr4o/nXlH76bKjGUye9Z2wSxO5Tz7GoDr4vfI= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.0 h1:Lg6BW0VPmCwcMlvOviL3ruHFO+H9tZNqscK0AeuFjGM= diff --git a/tests/certification/state/azure/blobstorage/go.mod b/tests/certification/state/azure/blobstorage/go.mod index 5022f1279..b7c33bfbe 100644 --- a/tests/certification/state/azure/blobstorage/go.mod +++ b/tests/certification/state/azure/blobstorage/go.mod @@ -18,7 +18,7 @@ require ( github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/state/azure/blobstorage/go.sum b/tests/certification/state/azure/blobstorage/go.sum index e1c955cbc..3b5acc6ec 100644 --- a/tests/certification/state/azure/blobstorage/go.sum +++ b/tests/certification/state/azure/blobstorage/go.sum @@ -45,8 +45,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= diff --git a/tests/certification/state/azure/cosmosdb/go.mod b/tests/certification/state/azure/cosmosdb/go.mod index 8dbfc9a34..44f1f6f01 100644 --- a/tests/certification/state/azure/cosmosdb/go.mod +++ b/tests/certification/state/azure/cosmosdb/go.mod @@ -20,7 +20,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/state/azure/cosmosdb/go.sum b/tests/certification/state/azure/cosmosdb/go.sum index 5f83b83bc..e1969c129 100644 --- a/tests/certification/state/azure/cosmosdb/go.sum +++ b/tests/certification/state/azure/cosmosdb/go.sum @@ -49,8 +49,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4Sath github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2 h1:yJegJqjhrMJ3Oe5s43jOTGL2AsE7pJyx+7Yqls/65tw= github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.2/go.mod h1:Fy3bbChFm4cZn6oIxYYqKB2FG3rBDxk3NZDLDJCHl+Q= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= diff --git a/tests/certification/state/azure/tablestorage/go.mod b/tests/certification/state/azure/tablestorage/go.mod index c7ad889bc..b6a64984a 100644 --- a/tests/certification/state/azure/tablestorage/go.mod +++ b/tests/certification/state/azure/tablestorage/go.mod @@ -19,7 +19,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/state/azure/tablestorage/go.sum b/tests/certification/state/azure/tablestorage/go.sum index a592f8d13..658835afc 100644 --- a/tests/certification/state/azure/tablestorage/go.sum +++ b/tests/certification/state/azure/tablestorage/go.sum @@ -47,8 +47,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4Sath github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1 h1:bFa9IcjvrCber6gGgDAUZ+I2bO8J7s8JxXmu9fhi2ss= github.com/Azure/azure-sdk-for-go/sdk/data/aztables v1.0.1/go.mod h1:l3wvZkG9oW07GLBW5Cd0WwG5asOfJ8aqE8raUvNzLpk= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= From c3027b8fb1ae884366b56c083884e44e119e8f31 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 11:52:37 -0800 Subject: [PATCH 02/22] some small improvements Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 32 +++++++++---------- .../azure/blobstorage/blobstorage_test.go | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index 34d10f2ae..e97101b85 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -62,14 +62,14 @@ const ( metadataKeyContentLanguage = "contentLanguage" metadataKeyContentDisposition = "contentDisposition" metadataKeyCacheControl = "cacheControl" - // Specifies the maximum number of HTTP GET requests that will be made while reading from a RetryReader. A value - // of zero means that no additional HTTP GET requests will be made. + // Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value + // of zero means that no additional HTTP requests will be made. defaultGetBlobRetryCount = 10 // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // specify maxresults the server will return up to 5,000 items. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters - maxResults = 5000 - endpointKey = "endpoint" + maxResults int32 = 5000 + endpointKey = "endpoint" ) var ErrMissingBlobName = errors.New("blobName is a required attribute") @@ -87,7 +87,7 @@ type blobStorageMetadata struct { StorageAccount string `json:"storageAccount"` StorageAccessKey string `json:"storageAccessKey"` Container string `json:"container"` - GetBlobRetryCount int `json:"getBlobRetryCount,string"` + GetBlobRetryCount int32 `json:"getBlobRetryCount,string"` DecodeBase64 bool `json:"decodeBase64,string"` PublicAccessLevel azblob.PublicAccessType `json:"publicAccessLevel"` } @@ -129,7 +129,7 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { options := container.ClientOptions{ ClientOptions: azcore.ClientOptions{ Retry: policy.RetryOptions{ - MaxRetries: int32(a.metadata.GetBlobRetryCount), + MaxRetries: a.metadata.GetBlobRetryCount, }, Telemetry: policy.TelemetryOptions{ ApplicationID: userAgent, @@ -245,7 +245,7 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque blobHTTPHeaders := blob.HTTPHeaders{} if val, ok := req.Metadata[metadataKeyContentType]; ok && val != "" { - blobHTTPHeaders.BlobContentType = ptr.Of(val) + blobHTTPHeaders.BlobContentType = &val delete(req.Metadata, metadataKeyContentType) } var contentMD5 *[]byte @@ -253,26 +253,26 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque if val, ok := req.Metadata[metadataKeyContentMD5]; ok && val != "" { sDec, err := b64.StdEncoding.DecodeString(val) if err != nil || len(sDec) != 16 { - return nil, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") + return nil, errors.New("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") } blobHTTPHeaders.BlobContentMD5 = sDec contentMD5 = &sDec delete(req.Metadata, metadataKeyContentMD5) } if val, ok := req.Metadata[metadataKeyContentEncoding]; ok && val != "" { - blobHTTPHeaders.BlobContentEncoding = ptr.Of(val) + blobHTTPHeaders.BlobContentEncoding = &val delete(req.Metadata, metadataKeyContentEncoding) } if val, ok := req.Metadata[metadataKeyContentLanguage]; ok && val != "" { - blobHTTPHeaders.BlobContentLanguage = ptr.Of(val) + blobHTTPHeaders.BlobContentLanguage = &val delete(req.Metadata, metadataKeyContentLanguage) } if val, ok := req.Metadata[metadataKeyContentDisposition]; ok && val != "" { - blobHTTPHeaders.BlobContentDisposition = ptr.Of(val) + blobHTTPHeaders.BlobContentDisposition = &val delete(req.Metadata, metadataKeyContentDisposition) } if val, ok := req.Metadata[metadataKeyCacheControl]; ok && val != "" { - blobHTTPHeaders.BlobCacheControl = ptr.Of(val) + blobHTTPHeaders.BlobCacheControl = &val delete(req.Metadata, metadataKeyCacheControl) } @@ -421,13 +421,13 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest } if hasPayload && payload.MaxResults != int32(0) { - options.MaxResults = ptr.Of(payload.MaxResults) + options.MaxResults = &payload.MaxResults } else { - options.MaxResults = ptr.Of(int32(maxResults)) + options.MaxResults = ptr.Of(maxResults) // cannot get address of constant directly } if hasPayload && payload.Prefix != "" { - options.Prefix = ptr.Of(payload.Prefix) + options.Prefix = &payload.Prefix } var initialMarker string @@ -436,7 +436,7 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest } else { initialMarker = "" } - options.Marker = ptr.Of(initialMarker) + options.Marker = &initialMarker metadata := map[string]string{} blobs := []*container.BlobItem{} diff --git a/bindings/azure/blobstorage/blobstorage_test.go b/bindings/azure/blobstorage/blobstorage_test.go index 52810feab..8462e497d 100644 --- a/bindings/azure/blobstorage/blobstorage_test.go +++ b/bindings/azure/blobstorage/blobstorage_test.go @@ -42,7 +42,7 @@ func TestParseMetadata(t *testing.T) { assert.Equal(t, "account", meta.StorageAccount) // storageAccessKey is parsed in the azauth package assert.Equal(t, true, meta.DecodeBase64) - assert.Equal(t, 5, meta.GetBlobRetryCount) + assert.Equal(t, int32(5), meta.GetBlobRetryCount) assert.Equal(t, "", string(meta.PublicAccessLevel)) }) From 17d38d7f655edc1ef05f23bcbf63bf5ef3612b0d Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 12:02:22 -0800 Subject: [PATCH 03/22] fix blob storage cert test Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- .../azure/blobstorage/blobstorage_test.go | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go index ad715e91b..79c4855e1 100644 --- a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go +++ b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go @@ -33,6 +33,7 @@ import ( dapr_testing "github.com/dapr/dapr/pkg/testing" daprsdk "github.com/dapr/go-sdk/client" "github.com/dapr/kit/logger" + "github.com/dapr/kit/ptr" "github.com/dapr/components-contrib/tests/certification/embedded" "github.com/dapr/components-contrib/tests/certification/flow" @@ -106,10 +107,12 @@ func listBlobRequest(ctx flow.Context, client daprsdk.Client, prefix string, mar } // deleteBlobRequest is used to make a common binding request for the delete operation. -func deleteBlobRequest(ctx flow.Context, client daprsdk.Client, name string, deleteSnapshotsOption string) (out *daprsdk.BindingEvent, err error) { +func deleteBlobRequest(ctx flow.Context, client daprsdk.Client, name string, deleteSnapshotsOption *string) (out *daprsdk.BindingEvent, err error) { invokeDeleteMetadata := map[string]string{ - "blobName": name, - "deleteSnapshots": deleteSnapshotsOption, + "blobName": name, + } + if deleteSnapshotsOption != nil { + invokeDeleteMetadata["deleteSnapshots"] = *deleteSnapshotsOption } invokeGetRequest := &daprsdk.InvokeBindingRequest{ @@ -187,7 +190,7 @@ func TestBlobStorage(t *testing.T) { assert.Equal(t, newString, input2) // cleanup. - out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") + out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil) assert.NoError(t, invokeDeleteErr) assert.Empty(t, out.Data) @@ -197,7 +200,7 @@ func TestBlobStorage(t *testing.T) { assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") // deleting the key again should fail. - _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, "") + _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, nil) assert.Error(t, invokeDeleteErr2) assert.Contains(t, invokeDeleteErr2.Error(), "ERROR CODE: BlobNotFound") @@ -274,7 +277,7 @@ func TestBlobStorage(t *testing.T) { assert.Equal(t, responseData, dataBytes) assert.Empty(t, out.Metadata) - out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") + out, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil) assert.NoError(t, invokeDeleteErr) assert.Empty(t, out.Data) @@ -329,7 +332,7 @@ func TestBlobStorage(t *testing.T) { } // cleanup. - _, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, "") + _, invokeDeleteErr := deleteBlobRequest(ctx, client, blobName, nil) assert.NoError(t, invokeDeleteErr) return nil @@ -414,7 +417,7 @@ func TestBlobStorage(t *testing.T) { } assert.True(t, found) - out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", "") + out, invokeDeleteErr := deleteBlobRequest(ctx, client, "filename.txt", nil) assert.NoError(t, invokeDeleteErr) assert.Empty(t, out.Data) @@ -524,11 +527,11 @@ func TestBlobStorage(t *testing.T) { assert.Contains(t, output2[0]["Name"], "prefixA") // cleanup. - _, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", "") + _, invokeDeleteErr1 := deleteBlobRequest(ctx, client, "prefixA/filename.txt", nil) assert.NoError(t, invokeDeleteErr1) - _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", "") + _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "prefixAfilename.txt", nil) assert.NoError(t, invokeDeleteErr2) - _, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", "") + _, invokeDeleteErr3 := deleteBlobRequest(ctx, client, "prefixB/filename.txt", nil) assert.NoError(t, invokeDeleteErr3) // list deleted items with prefix. @@ -572,13 +575,13 @@ func TestBlobStorage(t *testing.T) { assert.Equal(t, out.Metadata["number"], "2") // delete snapshots. - _, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", "only") + _, invokeDeleteErr := deleteBlobRequest(ctx, client, "snapshotthis.txt", ptr.Of(string(blob.DeleteSnapshotsOptionTypeOnly))) assert.NoError(t, invokeDeleteErr) // verify snapshot is deleted. out2, listErr2 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false) assert.NoError(t, listErr2) - assert.Equal(t, out2.Metadata["number"], "1") + assert.Equal(t, "1", out2.Metadata["number"]) // create another snapshot. _, createSnapshotErr2 := blobClient.CreateSnapshot( @@ -586,13 +589,13 @@ func TestBlobStorage(t *testing.T) { assert.NoError(t, createSnapshotErr2) // delete base blob and snapshots all at once. - _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "snapshotthis.txt", "include") + _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, "snapshotthis.txt", ptr.Of(string(blob.DeleteSnapshotsOptionTypeInclude))) assert.NoError(t, invokeDeleteErr2) // verify base blob and snapshots are deleted. out3, listErr3 := listBlobRequest(ctx, client, "snapshotthis.txt", "", -1, false, true, false, false, false) assert.NoError(t, listErr3) - assert.Equal(t, out3.Metadata["number"], "0") + assert.Equal(t, "0", out3.Metadata["number"]) return nil } From 7ccca4def8a90b4055935a0008db87127b03adff Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 19:55:02 -0800 Subject: [PATCH 04/22] AzBlob State: Migrate to Track2 SDK Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- state/azure/blobstorage/blobstorage.go | 210 +++++++++++------- state/azure/blobstorage/blobstorage_test.go | 12 +- .../state/azure/blobstorage/go.mod | 1 + .../state/azure/blobstorage/go.sum | 2 + 4 files changed, 140 insertions(+), 85 deletions(-) diff --git a/state/azure/blobstorage/blobstorage.go b/state/azure/blobstorage/blobstorage.go index b493ae162..a03e7c663 100644 --- a/state/azure/blobstorage/blobstorage.go +++ b/state/azure/blobstorage/blobstorage.go @@ -36,16 +36,21 @@ Concurrency is supported with ETags according to https://docs.microsoft.com/en-u package blobstorage import ( + "bytes" "context" b64 "encoding/base64" "fmt" - "io" - "net" "net/url" "reflect" "strings" + "time" - "github.com/Azure/azure-storage-blob-go/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" jsoniter "github.com/json-iterator/go" azauth "github.com/dapr/components-contrib/internal/authentication/azure" @@ -63,13 +68,14 @@ const ( contentLanguage = "ContentLanguage" contentDisposition = "ContentDisposition" cacheControl = "CacheControl" + endpointKey = "endpoint" ) // StateStore Type. type StateStore struct { state.DefaultBulkStore - containerURL azblob.ContainerURL - json jsoniter.API + containerClient *container.Client + json jsoniter.API features []state.Feature logger logger.Logger @@ -78,49 +84,77 @@ type StateStore struct { type blobStorageMetadata struct { AccountName string ContainerName string + AccountKey string } // Init the connection to blob storage, optionally creates a blob container if it doesn't exist. func (r *StateStore) Init(metadata state.Metadata) error { - meta, err := getBlobStorageMetadata(metadata.Properties) + m, err := getBlobStorageMetadata(metadata.Properties) if err != nil { return err } - credential, env, err := azauth.GetAzureStorageBlobCredentials(r.logger, meta.AccountName, metadata.Properties) - if err != nil { - return fmt.Errorf("invalid credentials with error: %s", err.Error()) - } - userAgent := "dapr-" + logger.DaprVersion - options := azblob.PipelineOptions{ - Telemetry: azblob.TelemetryOptions{Value: userAgent}, + options := container.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Telemetry: policy.TelemetryOptions{ + ApplicationID: userAgent, + }, + }, } - p := azblob.NewPipeline(credential, options) + settings, err := azauth.NewEnvironmentSettings("storage", metadata.Properties) + if err != nil { + return err + } + customEndpoint, ok := metadata.Properties[endpointKey] var URL *url.URL - customEndpoint, ok := mdutils.GetMetadataProperty(metadata.Properties, azauth.StorageEndpointKeys...) if ok && customEndpoint != "" { - URL, err = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, meta.AccountName, meta.ContainerName)) + var parseErr error + URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.ContainerName)) + if parseErr != nil { + return parseErr + } } else { - URL, err = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", meta.AccountName, env.StorageEndpointSuffix, meta.ContainerName)) - } - if err != nil { - return err - } - containerURL := azblob.NewContainerURL(*URL, p) - - _, err = net.LookupHost(URL.Hostname()) - if err != nil { - return err + env := settings.AzureEnvironment + URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.ContainerName)) } - ctx := context.Background() - _, err = containerURL.Create(ctx, azblob.Metadata{}, azblob.PublicAccessNone) - r.logger.Debugf("error creating container: %s", err) + var clientErr error + var client *container.Client + // Try using shared key credentials first + if m.AccountKey != "" { + credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.AccountName, m.AccountKey) + if err != nil { + return fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) + } + client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) + if clientErr != nil { + return fmt.Errorf("cannot init Blobstorage container client: %w", err) + } + container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) + r.containerClient = client + } else { + // fallback to AAD + credential, tokenErr := settings.GetTokenCredential() + if err != nil { + return fmt.Errorf("invalid credentials with error: %w", tokenErr) + } + client, clientErr = container.NewClient(URL.String(), credential, &options) + } + if clientErr != nil { + return fmt.Errorf("cannot init Blobstorage client: %w", clientErr) + } - r.containerURL = containerURL - r.logger.Debugf("using container '%s'", meta.ContainerName) + createContainerOptions := container.CreateOptions{ + Access: nil, + } + timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + _, err = client.Create(timeoutCtx, &createContainerOptions) + cancel() + // Don't return error, container might already exist + r.logger.Debugf("error creating container: %w", err) + r.containerClient = client return nil } @@ -149,10 +183,11 @@ func (r *StateStore) Set(req *state.SetRequest) error { } func (r *StateStore) Ping() error { - accessConditions := azblob.BlobAccessConditions{} - - if _, err := r.containerURL.GetProperties(context.Background(), accessConditions.LeaseAccessConditions); err != nil { - return fmt.Errorf("blob storage: error connecting to Blob storage at %s: %s", r.containerURL.URL().Host, err) + getPropertiesOptions := container.GetPropertiesOptions{ + LeaseAccessConditions: &container.LeaseAccessConditions{}, + } + if _, err := r.containerClient.GetProperties(context.Background(), &getPropertiesOptions); err != nil { + return fmt.Errorf("blob storage: error connecting to Blob storage at %s: %s", r.containerClient.URL(), err) } return nil @@ -197,9 +232,13 @@ func getBlobStorageMetadata(meta map[string]string) (*blobStorageMetadata, error } func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*state.GetResponse, error) { - blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) + blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) - resp, err := blobURL.Download(ctx, 0, azblob.CountToEnd, azblob.BlobAccessConditions{}, false) + downloadOptions := azblob.DownloadStreamOptions{ + AccessConditions: &blob.AccessConditions{}, + } + + blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, &downloadOptions) if err != nil { r.logger.Debugf("download file %s, err %s", req.Key, err) @@ -210,107 +249,124 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat return &state.GetResponse{}, err } - bodyStream := resp.Body(azblob.RetryReaderOptions{}) - data, err := io.ReadAll(bodyStream) + blobData := &bytes.Buffer{} + reader := blobDownloadResponse.Body + _, err = blobData.ReadFrom(reader) if err != nil { - r.logger.Debugf("read file %s, err %s", req.Key, err) - return &state.GetResponse{}, err + return &state.GetResponse{}, fmt.Errorf("error reading az blob: %w", err) + } + err = reader.Close() + if err != nil { + return &state.GetResponse{}, fmt.Errorf("error closing az blob reader: %w", err) } - contentType := resp.ContentType() + contentType := blobDownloadResponse.ContentType return &state.GetResponse{ - Data: data, - ETag: ptr.Of(string(resp.ETag())), - ContentType: &contentType, + Data: blobData.Bytes(), + ETag: ptr.Of(string(*blobDownloadResponse.ETag)), + ContentType: contentType, }, nil } func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error { - accessConditions := azblob.BlobAccessConditions{} + modifiedAccessConditions := blob.ModifiedAccessConditions{} if req.ETag != nil && *req.ETag != "" { - accessConditions.IfMatch = azblob.ETag(*req.ETag) + modifiedAccessConditions.IfMatch = ptr.Of(azcore.ETag(*req.ETag)) } if req.Options.Concurrency == state.FirstWrite && (req.ETag == nil || *req.ETag == "") { - accessConditions.IfNoneMatch = azblob.ETag("*") + modifiedAccessConditions.IfNoneMatch = ptr.Of(azcore.ETagAny) } - blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) + accessConditions := blob.AccessConditions{ + ModifiedAccessConditions: &modifiedAccessConditions, + } blobHTTPHeaders, err := r.createBlobHTTPHeadersFromRequest(req) if err != nil { return err } - _, err = azblob.UploadBufferToBlockBlob(ctx, r.marshal(req), blobURL, azblob.UploadToBlockBlobOptions{ - Metadata: req.Metadata, - AccessConditions: accessConditions, - BlobHTTPHeaders: blobHTTPHeaders, - }) - if err != nil { - r.logger.Debugf("write file %s, err %s", req.Key, err) + uploadOptions := azblob.UploadBufferOptions{ + AccessConditions: &accessConditions, + Metadata: req.Metadata, + HTTPHeaders: &blobHTTPHeaders, + Concurrency: 16, + } + + blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) + _, err = blockBlobClient.UploadBuffer(ctx, r.marshal(req), &uploadOptions) + + if err != nil { // Check if the error is due to ETag conflict if req.ETag != nil && isETagConflictError(err) { return state.NewETagError(state.ETagMismatch, err) } - return err + return fmt.Errorf("error uploading az blob: %w", err) } return nil } -func (r *StateStore) createBlobHTTPHeadersFromRequest(req *state.SetRequest) (azblob.BlobHTTPHeaders, error) { - var blobHTTPHeaders azblob.BlobHTTPHeaders +func (r *StateStore) createBlobHTTPHeadersFromRequest(req *state.SetRequest) (blob.HTTPHeaders, error) { + blobHTTPHeaders := blob.HTTPHeaders{} if val, ok := req.Metadata[contentType]; ok && val != "" { - blobHTTPHeaders.ContentType = val + blobHTTPHeaders.BlobContentType = &val delete(req.Metadata, contentType) } if req.ContentType != nil { - if blobHTTPHeaders.ContentType != "" { - r.logger.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.ContentType, *req.ContentType) + if blobHTTPHeaders.BlobContentType != nil { + r.logger.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.BlobContentType, req.ContentType) } - blobHTTPHeaders.ContentType = *req.ContentType + blobHTTPHeaders.BlobContentType = req.ContentType } if val, ok := req.Metadata[contentMD5]; ok && val != "" { sDec, err := b64.StdEncoding.DecodeString(val) if err != nil || len(sDec) != 16 { - return azblob.BlobHTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") + return blob.HTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") } - blobHTTPHeaders.ContentMD5 = sDec + blobHTTPHeaders.BlobContentMD5 = sDec delete(req.Metadata, contentMD5) } if val, ok := req.Metadata[contentEncoding]; ok && val != "" { - blobHTTPHeaders.ContentEncoding = val + blobHTTPHeaders.BlobContentEncoding = &val delete(req.Metadata, contentEncoding) } if val, ok := req.Metadata[contentLanguage]; ok && val != "" { - blobHTTPHeaders.ContentLanguage = val + blobHTTPHeaders.BlobContentLanguage = &val delete(req.Metadata, contentLanguage) } if val, ok := req.Metadata[contentDisposition]; ok && val != "" { - blobHTTPHeaders.ContentDisposition = val + blobHTTPHeaders.BlobContentDisposition = &val delete(req.Metadata, contentDisposition) } if val, ok := req.Metadata[cacheControl]; ok && val != "" { - blobHTTPHeaders.CacheControl = val + blobHTTPHeaders.BlobCacheControl = &val delete(req.Metadata, cacheControl) } return blobHTTPHeaders, nil } func (r *StateStore) deleteFile(ctx context.Context, req *state.DeleteRequest) error { - blobURL := r.containerURL.NewBlockBlobURL(getFileName(req.Key)) - accessConditions := azblob.BlobAccessConditions{} + blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) + modifiedAccessConditions := blob.ModifiedAccessConditions{} if req.ETag != nil && *req.ETag != "" { - accessConditions.IfMatch = azblob.ETag(*req.ETag) + modifiedAccessConditions.IfMatch = ptr.Of(azcore.ETag(*req.ETag)) } - _, err := blobURL.Delete(ctx, azblob.DeleteSnapshotsOptionNone, accessConditions) + deleteOptions := blob.DeleteOptions{ + DeleteSnapshots: nil, + AccessConditions: &blob.AccessConditions{ + ModifiedAccessConditions: &modifiedAccessConditions, + }, + } + + _, err := blockBlobClient.Delete(ctx, &deleteOptions) if err != nil { r.logger.Debugf("delete file %s, err %s", req.Key, err) @@ -349,13 +405,9 @@ func (r *StateStore) marshal(req *state.SetRequest) []byte { } func isNotFoundError(err error) bool { - azureError, ok := err.(azblob.StorageError) - - return ok && azureError.ServiceCode() == azblob.ServiceCodeBlobNotFound + return bloberror.HasCode(err, bloberror.BlobNotFound) } func isETagConflictError(err error) bool { - azureError, ok := err.(azblob.StorageError) - - return ok && azureError.ServiceCode() == azblob.ServiceCodeConditionNotMet + return bloberror.HasCode(err, bloberror.ConditionNotMet) } diff --git a/state/azure/blobstorage/blobstorage_test.go b/state/azure/blobstorage/blobstorage_test.go index f511239b1..e86505d51 100644 --- a/state/azure/blobstorage/blobstorage_test.go +++ b/state/azure/blobstorage/blobstorage_test.go @@ -34,8 +34,7 @@ func TestInit(t *testing.T) { } err := s.Init(m) assert.Nil(t, err) - assert.Equal(t, "acc.blob.core.windows.net", s.containerURL.URL().Host) - assert.Equal(t, "/dapr", s.containerURL.URL().Path) + assert.Equal(t, "https://acc.blob.core.windows.net/dapr", s.containerClient.URL()) }) t.Run("Init with missing metadata", func(t *testing.T) { @@ -53,7 +52,8 @@ func TestInit(t *testing.T) { "accountKey": "e+Dnvl8EOxYxV94nurVaRQ==", "containerName": "dapr", } - err := s.Init(m) + s.Init(m) + err := s.Ping() assert.NotNil(t, err) }) } @@ -100,7 +100,7 @@ func TestBlobHTTPHeaderGeneration(t *testing.T) { blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) assert.Nil(t, err) - assert.Equal(t, "application/json", blobHeaders.ContentType) + assert.Equal(t, "application/json", *blobHeaders.BlobContentType) }) t.Run("Content type and metadata provided (conflict), content type chosen", func(t *testing.T) { contentType := "application/json" @@ -113,7 +113,7 @@ func TestBlobHTTPHeaderGeneration(t *testing.T) { blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) assert.Nil(t, err) - assert.Equal(t, "application/json", blobHeaders.ContentType) + assert.Equal(t, "application/json", *blobHeaders.BlobContentType) }) t.Run("ContentType not provided, metadata provided set backward compatibility", func(t *testing.T) { req := &state.SetRequest{ @@ -124,6 +124,6 @@ func TestBlobHTTPHeaderGeneration(t *testing.T) { blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) assert.Nil(t, err) - assert.Equal(t, "text/plain", blobHeaders.ContentType) + assert.Equal(t, "text/plain", *blobHeaders.BlobContentType) }) } diff --git a/tests/certification/state/azure/blobstorage/go.mod b/tests/certification/state/azure/blobstorage/go.mod index b7c33bfbe..1caa631ff 100644 --- a/tests/certification/state/azure/blobstorage/go.mod +++ b/tests/certification/state/azure/blobstorage/go.mod @@ -19,6 +19,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 // indirect github.com/Azure/azure-storage-blob-go v0.10.0 // indirect github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect diff --git a/tests/certification/state/azure/blobstorage/go.sum b/tests/certification/state/azure/blobstorage/go.sum index 3b5acc6ec..0200c2d33 100644 --- a/tests/certification/state/azure/blobstorage/go.sum +++ b/tests/certification/state/azure/blobstorage/go.sum @@ -47,6 +47,8 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4Sath github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 h1:BMTdr+ib5ljLa9MxTJK8x/Ds0MbBb4MfuW5BL0zMJnI= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1/go.mod h1:c6WvOhtmjNUWbLfOG1qxM/q0SPvQNSVJvolm+C52dIU= github.com/Azure/azure-storage-blob-go v0.10.0 h1:evCwGreYo3XLeBV4vSxLbLiYb6e0SzsJiXQVRGsRXxs= github.com/Azure/azure-storage-blob-go v0.10.0/go.mod h1:ep1edmW+kNQx4UfWM9heESNmQdijykocJ0YOxmMX8SE= github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd h1:b3wyxBl3vvr15tUAziPBPK354y+LSdfPCpex5oBttHo= From 70eb9f3a9c43c7829e36a8ceb2f77a50efc6e276 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 20:35:05 -0800 Subject: [PATCH 05/22] Address code review comments Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 23 ++++++++----------- state/azure/blobstorage/blobstorage.go | 9 ++++---- .../azure/blobstorage/blobstorage_test.go | 11 +++++---- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index e97101b85..5a8dbbc06 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -14,12 +14,12 @@ limitations under the License. package blobstorage import ( - "bytes" "context" b64 "encoding/base64" "encoding/json" "errors" "fmt" + "io" "net/url" "strconv" "time" @@ -64,7 +64,7 @@ const ( metadataKeyCacheControl = "cacheControl" // Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value // of zero means that no additional HTTP requests will be made. - defaultGetBlobRetryCount = 10 + defaultBlobRetryCount = 3 // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // specify maxresults the server will return up to 5,000 items. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters @@ -76,8 +76,7 @@ var ErrMissingBlobName = errors.New("blobName is a required attribute") // AzureBlobStorage allows saving blobs to an Azure Blob Storage account. type AzureBlobStorage struct { - metadata *blobStorageMetadata - // containerURL azblob.ContainerURL + metadata *blobStorageMetadata containerClient *container.Client logger logger.Logger @@ -166,7 +165,6 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { if clientErr != nil { return fmt.Errorf("cannot init Blobstorage container client: %w", err) } - container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) a.containerClient = client } else { // fallback to AAD @@ -196,7 +194,7 @@ func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { func (a *AzureBlobStorage) parseMetadata(meta bindings.Metadata) (*blobStorageMetadata, error) { m := blobStorageMetadata{ - GetBlobRetryCount: defaultGetBlobRetryCount, + GetBlobRetryCount: defaultBlobRetryCount, } mdutils.DecodeMetadata(meta.Properties, &m) @@ -248,8 +246,8 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque blobHTTPHeaders.BlobContentType = &val delete(req.Metadata, metadataKeyContentType) } - var contentMD5 *[]byte + var contentMD5 *[]byte if val, ok := req.Metadata[metadataKeyContentMD5]; ok && val != "" { sDec, err := b64.StdEncoding.DecodeString(val) if err != nil || len(sDec) != 16 { @@ -292,7 +290,6 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque uploadOptions := azblob.UploadBufferOptions{ Metadata: a.sanitizeMetadata(req.Metadata), HTTPHeaders: &blobHTTPHeaders, - Concurrency: 16, TransactionalContentMD5: contentMD5, } @@ -337,9 +334,9 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) if err != nil { return nil, fmt.Errorf("error downloading az blob: %w", err) } - blobData := &bytes.Buffer{} reader := blobDownloadResponse.Body - _, err = blobData.ReadFrom(reader) + defer reader.Close() + blobData, err := io.ReadAll(reader) if err != nil { return nil, fmt.Errorf("error reading az blob: %w", err) } @@ -368,7 +365,7 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) } return &bindings.InvokeResponse{ - Data: blobData.Bytes(), + Data: blobData, Metadata: metadata, }, nil } @@ -395,7 +392,7 @@ func (a *AzureBlobStorage) delete(ctx context.Context, req *bindings.InvokeReque } blockBlobClient = a.containerClient.NewBlockBlobClient(val) - _, err := blockBlobClient.Delete(context.Background(), &deleteOptions) + _, err := blockBlobClient.Delete(ctx, &deleteOptions) return nil, err } @@ -420,7 +417,7 @@ func (a *AzureBlobStorage) list(ctx context.Context, req *bindings.InvokeRequest options.Include.Deleted = payload.Include.Deleted } - if hasPayload && payload.MaxResults != int32(0) { + if hasPayload && payload.MaxResults > 0 { options.MaxResults = &payload.MaxResults } else { options.MaxResults = ptr.Of(maxResults) // cannot get address of constant directly diff --git a/state/azure/blobstorage/blobstorage.go b/state/azure/blobstorage/blobstorage.go index a03e7c663..5c6f6cd38 100644 --- a/state/azure/blobstorage/blobstorage.go +++ b/state/azure/blobstorage/blobstorage.go @@ -36,10 +36,10 @@ Concurrency is supported with ETags according to https://docs.microsoft.com/en-u package blobstorage import ( - "bytes" "context" b64 "encoding/base64" "fmt" + "io" "net/url" "reflect" "strings" @@ -132,7 +132,6 @@ func (r *StateStore) Init(metadata state.Metadata) error { if clientErr != nil { return fmt.Errorf("cannot init Blobstorage container client: %w", err) } - container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) r.containerClient = client } else { // fallback to AAD @@ -249,9 +248,9 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat return &state.GetResponse{}, err } - blobData := &bytes.Buffer{} reader := blobDownloadResponse.Body - _, err = blobData.ReadFrom(reader) + defer reader.Close() + blobData, err := io.ReadAll(reader) if err != nil { return &state.GetResponse{}, fmt.Errorf("error reading az blob: %w", err) } @@ -263,7 +262,7 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat contentType := blobDownloadResponse.ContentType return &state.GetResponse{ - Data: blobData.Bytes(), + Data: blobData, ETag: ptr.Of(string(*blobDownloadResponse.ETag)), ContentType: contentType, }, nil diff --git a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go index 79c4855e1..a775cc53c 100644 --- a/tests/certification/bindings/azure/blobstorage/blobstorage_test.go +++ b/tests/certification/bindings/azure/blobstorage/blobstorage_test.go @@ -41,6 +41,7 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" ) @@ -197,12 +198,12 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound) // deleting the key again should fail. _, invokeDeleteErr2 := deleteBlobRequest(ctx, client, blobName, nil) assert.Error(t, invokeDeleteErr2) - assert.Contains(t, invokeDeleteErr2.Error(), "ERROR CODE: BlobNotFound") + assert.Contains(t, invokeDeleteErr2.Error(), bloberror.BlobNotFound) return nil } @@ -235,7 +236,7 @@ func TestBlobStorage(t *testing.T) { _, invokeCreateErr := client.InvokeBinding(ctx, invokeCreateRequest) assert.Error(t, invokeCreateErr) - assert.Contains(t, invokeCreateErr.Error(), "ERROR CODE: Md5Mismatch") + assert.Contains(t, invokeCreateErr.Error(), bloberror.MD5Mismatch) return nil } @@ -284,7 +285,7 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, blobName, false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound) return nil } @@ -424,7 +425,7 @@ func TestBlobStorage(t *testing.T) { // confirm the deletion. _, invokeSecondGetErr := getBlobRequest(ctx, client, "filename.txt", false) assert.Error(t, invokeSecondGetErr) - assert.Contains(t, invokeSecondGetErr.Error(), "ERROR CODE: BlobNotFound") + assert.Contains(t, invokeSecondGetErr.Error(), bloberror.BlobNotFound) return nil } From 8811d5e64fa0feb4cc3b1c10ebdda3610aa0a236 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 21:37:17 -0800 Subject: [PATCH 06/22] AzBlob components: Extract shared code Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 172 +----------------- .../azure/blobstorage/blobstorage_test.go | 71 -------- .../component/azure/blobstorage/client.go | 108 +++++++++++ .../component/azure/blobstorage/metadata.go | 123 +++++++++++++ .../azure/blobstorage/metadata_test.go | 93 ++++++++++ state/azure/blobstorage/blobstorage.go | 99 +--------- state/azure/blobstorage/blobstorage_test.go | 20 -- 7 files changed, 334 insertions(+), 352 deletions(-) create mode 100644 internal/component/azure/blobstorage/client.go create mode 100644 internal/component/azure/blobstorage/metadata.go create mode 100644 internal/component/azure/blobstorage/metadata_test.go diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index 5a8dbbc06..5150a9b0e 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -20,12 +20,8 @@ import ( "errors" "fmt" "io" - "net/url" "strconv" - "time" - "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob" @@ -33,8 +29,7 @@ import ( "github.com/google/uuid" "github.com/dapr/components-contrib/bindings" - azauth "github.com/dapr/components-contrib/internal/authentication/azure" - mdutils "github.com/dapr/components-contrib/metadata" + storageinternal "github.com/dapr/components-contrib/internal/component/azure/blobstorage" "github.com/dapr/kit/logger" "github.com/dapr/kit/ptr" ) @@ -62,9 +57,6 @@ const ( metadataKeyContentLanguage = "contentLanguage" metadataKeyContentDisposition = "contentDisposition" metadataKeyCacheControl = "cacheControl" - // Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value - // of zero means that no additional HTTP requests will be made. - defaultBlobRetryCount = 3 // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // specify maxresults the server will return up to 5,000 items. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters @@ -76,21 +68,12 @@ var ErrMissingBlobName = errors.New("blobName is a required attribute") // AzureBlobStorage allows saving blobs to an Azure Blob Storage account. type AzureBlobStorage struct { - metadata *blobStorageMetadata + metadata *storageinternal.BlobStorageMetadata containerClient *container.Client logger logger.Logger } -type blobStorageMetadata struct { - StorageAccount string `json:"storageAccount"` - StorageAccessKey string `json:"storageAccessKey"` - Container string `json:"container"` - GetBlobRetryCount int32 `json:"getBlobRetryCount,string"` - DecodeBase64 bool `json:"decodeBase64,string"` - PublicAccessLevel azblob.PublicAccessType `json:"publicAccessLevel"` -} - type createResponse struct { BlobURL string `json:"blobURL"` BlobName string `json:"blobName"` @@ -118,110 +101,14 @@ func NewAzureBlobStorage(logger logger.Logger) bindings.OutputBinding { // Init performs metadata parsing. func (a *AzureBlobStorage) Init(metadata bindings.Metadata) error { - m, err := a.parseMetadata(metadata) + var err error + a.containerClient, a.metadata, err = storageinternal.CreateContainerStorageClient(a.logger, metadata.Properties) if err != nil { return err } - a.metadata = m - - userAgent := "dapr-" + logger.DaprVersion - options := container.ClientOptions{ - ClientOptions: azcore.ClientOptions{ - Retry: policy.RetryOptions{ - MaxRetries: a.metadata.GetBlobRetryCount, - }, - Telemetry: policy.TelemetryOptions{ - ApplicationID: userAgent, - }, - }, - } - - settings, err := azauth.NewEnvironmentSettings("storage", metadata.Properties) - if err != nil { - return err - } - customEndpoint, ok := metadata.Properties[endpointKey] - var URL *url.URL - if ok && customEndpoint != "" { - var parseErr error - URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.StorageAccount, m.Container)) - if parseErr != nil { - return parseErr - } - } else { - env := settings.AzureEnvironment - URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.StorageAccount, env.StorageEndpointSuffix, m.Container)) - } - - var clientErr error - var client *container.Client - // Try using shared key credentials first - if m.StorageAccessKey != "" { - credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.StorageAccount, m.StorageAccessKey) - if err != nil { - return fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) - } - client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) - if clientErr != nil { - return fmt.Errorf("cannot init Blobstorage container client: %w", err) - } - a.containerClient = client - } else { - // fallback to AAD - credential, tokenErr := settings.GetTokenCredential() - if err != nil { - return fmt.Errorf("invalid credentials with error: %w", tokenErr) - } - client, clientErr = container.NewClient(URL.String(), credential, &options) - } - if clientErr != nil { - return fmt.Errorf("cannot init Blobstorage client: %w", clientErr) - } - - createContainerOptions := container.CreateOptions{ - Access: &m.PublicAccessLevel, - Metadata: map[string]string{}, - } - timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - _, err = client.Create(timeoutCtx, &createContainerOptions) - cancel() - // Don't return error, container might already exist - a.logger.Debugf("error creating container: %w", err) - a.containerClient = client - return nil } -func (a *AzureBlobStorage) parseMetadata(meta bindings.Metadata) (*blobStorageMetadata, error) { - m := blobStorageMetadata{ - GetBlobRetryCount: defaultBlobRetryCount, - } - mdutils.DecodeMetadata(meta.Properties, &m) - - if val, ok := mdutils.GetMetadataProperty(meta.Properties, azauth.StorageAccountNameKeys...); ok && val != "" { - m.StorageAccount = val - } else { - return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0]) - } - - if val, ok := mdutils.GetMetadataProperty(meta.Properties, azauth.StorageContainerNameKeys...); ok && val != "" { - m.Container = val - } else { - return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0]) - } - - // per the Dapr documentation "none" is a valid value - if m.PublicAccessLevel == "none" { - m.PublicAccessLevel = "" - } - if m.PublicAccessLevel != "" && !a.isValidPublicAccessType(m.PublicAccessLevel) { - return nil, fmt.Errorf("invalid public access level: %s; allowed: %s", - m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues()) - } - - return &m, nil -} - func (a *AzureBlobStorage) Operations() []bindings.OperationKind { return []bindings.OperationKind{ bindings.CreateOperation, @@ -288,7 +175,7 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque } uploadOptions := azblob.UploadBufferOptions{ - Metadata: a.sanitizeMetadata(req.Metadata), + Metadata: storageinternal.SanitizeMetadata(a.logger, req.Metadata), HTTPHeaders: &blobHTTPHeaders, TransactionalContentMD5: contentMD5, } @@ -486,17 +373,6 @@ func (a *AzureBlobStorage) Invoke(ctx context.Context, req *bindings.InvokeReque } } -func (a *AzureBlobStorage) isValidPublicAccessType(accessType azblob.PublicAccessType) bool { - validTypes := azblob.PossiblePublicAccessTypeValues() - for _, item := range validTypes { - if item == accessType { - return true - } - } - - return false -} - func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.DeleteSnapshotsOptionType) bool { validTypes := azblob.PossibleDeleteSnapshotsOptionTypeValues() for _, item := range validTypes { @@ -507,41 +383,3 @@ func (a *AzureBlobStorage) isValidDeleteSnapshotsOptionType(accessType azblob.De return false } - -func (a *AzureBlobStorage) sanitizeMetadata(metadata map[string]string) map[string]string { - for key, val := range metadata { - // Keep only letters and digits - n := 0 - newKey := make([]byte, len(key)) - for i := 0; i < len(key); i++ { - if (key[i] >= 'A' && key[i] <= 'Z') || - (key[i] >= 'a' && key[i] <= 'z') || - (key[i] >= '0' && key[i] <= '9') { - newKey[n] = key[i] - n++ - } - } - - if n != len(key) { - nks := string(newKey[:n]) - a.logger.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks) - delete(metadata, key) - metadata[nks] = val - key = nks - } - - // Remove all non-ascii characters - n = 0 - newVal := make([]byte, len(val)) - for i := 0; i < len(val); i++ { - if val[i] > 127 { - continue - } - newVal[n] = val[i] - n++ - } - metadata[key] = string(newVal[:n]) - } - - return metadata -} diff --git a/bindings/azure/blobstorage/blobstorage_test.go b/bindings/azure/blobstorage/blobstorage_test.go index 8462e497d..fbcb6e54e 100644 --- a/bindings/azure/blobstorage/blobstorage_test.go +++ b/bindings/azure/blobstorage/blobstorage_test.go @@ -17,83 +17,12 @@ import ( "context" "testing" - "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/stretchr/testify/assert" "github.com/dapr/components-contrib/bindings" "github.com/dapr/kit/logger" ) -func TestParseMetadata(t *testing.T) { - m := bindings.Metadata{} - blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage) - - t.Run("parse all metadata", func(t *testing.T) { - m.Properties = map[string]string{ - "storageAccount": "account", - "storageAccessKey": "key", - "container": "test", - "getBlobRetryCount": "5", - "decodeBase64": "true", - } - meta, err := blobStorage.parseMetadata(m) - assert.Nil(t, err) - assert.Equal(t, "test", meta.Container) - assert.Equal(t, "account", meta.StorageAccount) - // storageAccessKey is parsed in the azauth package - assert.Equal(t, true, meta.DecodeBase64) - assert.Equal(t, int32(5), meta.GetBlobRetryCount) - assert.Equal(t, "", string(meta.PublicAccessLevel)) - }) - - t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) { - m.Properties = map[string]string{ - "storageAccount": "account", - "storageAccessKey": "key", - "container": "test", - "publicAccessLevel": "blob", - } - meta, err := blobStorage.parseMetadata(m) - assert.Nil(t, err) - assert.Equal(t, azblob.PublicAccessTypeBlob, meta.PublicAccessLevel) - }) - - t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) { - m.Properties = map[string]string{ - "storageAccount": "account", - "storageAccessKey": "key", - "container": "test", - "publicAccessLevel": "container", - } - meta, err := blobStorage.parseMetadata(m) - assert.Nil(t, err) - assert.Equal(t, azblob.PublicAccessTypeContainer, meta.PublicAccessLevel) - }) - - t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) { - m.Properties = map[string]string{ - "storageAccount": "account", - "storageAccessKey": "key", - "container": "test", - "publicAccessLevel": "invalid", - } - _, err := blobStorage.parseMetadata(m) - assert.Error(t, err) - }) - - t.Run("sanitize metadata if necessary", func(t *testing.T) { - m.Properties = map[string]string{ - "somecustomfield": "some-custom-value", - "specialfield": "special:valueÜ", - "not-allowed:": "not-allowed", - } - meta := blobStorage.sanitizeMetadata(m.Properties) - assert.Equal(t, meta["somecustomfield"], "some-custom-value") - assert.Equal(t, meta["specialfield"], "special:value") - assert.Equal(t, meta["notallowed"], "not-allowed") - }) -} - func TestGetOption(t *testing.T) { blobStorage := NewAzureBlobStorage(logger.NewLogger("test")).(*AzureBlobStorage) diff --git a/internal/component/azure/blobstorage/client.go b/internal/component/azure/blobstorage/client.go new file mode 100644 index 000000000..64eb5a6d2 --- /dev/null +++ b/internal/component/azure/blobstorage/client.go @@ -0,0 +1,108 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package blobstorage + +import ( + "context" + "fmt" + "net/url" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" + + azauth "github.com/dapr/components-contrib/internal/authentication/azure" + "github.com/dapr/kit/logger" +) + +const ( + endpointKey = "endpoint" + // Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value + // of zero means that no additional HTTP requests will be made. + defaultBlobRetryCount = 3 +) + +func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*container.Client, *BlobStorageMetadata, error) { + m, err := parseMetadata(meta) + if err != nil { + return nil, nil, err + } + + userAgent := "dapr-" + logger.DaprVersion + options := container.ClientOptions{ + ClientOptions: azcore.ClientOptions{ + Retry: policy.RetryOptions{ + MaxRetries: m.RetryCount, + }, + Telemetry: policy.TelemetryOptions{ + ApplicationID: userAgent, + }, + }, + } + + settings, err := azauth.NewEnvironmentSettings("storage", meta) + if err != nil { + return nil, nil, err + } + customEndpoint, ok := meta[endpointKey] + var URL *url.URL + if ok && customEndpoint != "" { + var parseErr error + URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.ContainerName)) + if parseErr != nil { + return nil, nil, parseErr + } + } else { + env := settings.AzureEnvironment + URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.ContainerName)) + } + + var clientErr error + var client *container.Client + // Try using shared key credentials first + if m.AccountKey != "" { + credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.AccountName, m.AccountKey) + if err != nil { + return nil, nil, fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) + } + client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) + if clientErr != nil { + return nil, nil, fmt.Errorf("cannot init Blobstorage container client: %w", err) + } + } else { + // fallback to AAD + credential, tokenErr := settings.GetTokenCredential() + if err != nil { + return nil, nil, fmt.Errorf("invalid credentials with error: %w", tokenErr) + } + client, clientErr = container.NewClient(URL.String(), credential, &options) + } + if clientErr != nil { + return nil, nil, fmt.Errorf("cannot init Blobstorage client: %w", clientErr) + } + + createContainerOptions := container.CreateOptions{ + Access: &m.PublicAccessLevel, + Metadata: map[string]string{}, + } + timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + _, err = client.Create(timeoutCtx, &createContainerOptions) + cancel() + // Don't return error, container might already exist + log.Debugf("error creating container: %w", err) + + return client, m, nil +} diff --git a/internal/component/azure/blobstorage/metadata.go b/internal/component/azure/blobstorage/metadata.go new file mode 100644 index 000000000..14223c9ef --- /dev/null +++ b/internal/component/azure/blobstorage/metadata.go @@ -0,0 +1,123 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package blobstorage + +import ( + "fmt" + "strconv" + + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + + azauth "github.com/dapr/components-contrib/internal/authentication/azure" + mdutils "github.com/dapr/components-contrib/metadata" + "github.com/dapr/kit/logger" +) + +type BlobStorageMetadata struct { + AccountName string + AccountKey string + ContainerName string + RetryCount int32 `json:"retryCount,string"` + DecodeBase64 bool `json:"decodeBase64,string"` + PublicAccessLevel azblob.PublicAccessType +} + +func parseMetadata(meta map[string]string) (*BlobStorageMetadata, error) { + m := BlobStorageMetadata{ + RetryCount: defaultBlobRetryCount, + } + mdutils.DecodeMetadata(meta, &m) + + if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountNameKeys...); ok && val != "" { + m.AccountName = val + } else { + return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0]) + } + + if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageContainerNameKeys...); ok && val != "" { + m.ContainerName = val + } else { + return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0]) + } + + // per the Dapr documentation "none" is a valid value + if m.PublicAccessLevel == "none" { + m.PublicAccessLevel = "" + } + if m.PublicAccessLevel != "" && !isValidPublicAccessType(m.PublicAccessLevel) { + return nil, fmt.Errorf("invalid public access level: %s; allowed: %s", + m.PublicAccessLevel, azblob.PossiblePublicAccessTypeValues()) + } + + // we need this key for backwards compatibility + if val, ok := meta["getBlobRetryCount"]; ok && val != "" { + // convert val from string to int32 + parseInt, err := strconv.ParseInt(val, 10, 32) + if err != nil { + return nil, err + } + m.RetryCount = int32(parseInt) + } + + return &m, nil +} + +func isValidPublicAccessType(accessType azblob.PublicAccessType) bool { + validTypes := azblob.PossiblePublicAccessTypeValues() + for _, item := range validTypes { + if item == accessType { + return true + } + } + + return false +} + +func SanitizeMetadata(log logger.Logger, metadata map[string]string) map[string]string { + for key, val := range metadata { + // Keep only letters and digits + n := 0 + newKey := make([]byte, len(key)) + for i := 0; i < len(key); i++ { + if (key[i] >= 'A' && key[i] <= 'Z') || + (key[i] >= 'a' && key[i] <= 'z') || + (key[i] >= '0' && key[i] <= '9') { + newKey[n] = key[i] + n++ + } + } + + if n != len(key) { + nks := string(newKey[:n]) + log.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks) + delete(metadata, key) + metadata[nks] = val + key = nks + } + + // Remove all non-ascii characters + n = 0 + newVal := make([]byte, len(val)) + for i := 0; i < len(val); i++ { + if val[i] > 127 { + continue + } + newVal[n] = val[i] + n++ + } + metadata[key] = string(newVal[:n]) + } + + return metadata +} diff --git a/internal/component/azure/blobstorage/metadata_test.go b/internal/component/azure/blobstorage/metadata_test.go new file mode 100644 index 000000000..e60ef9c14 --- /dev/null +++ b/internal/component/azure/blobstorage/metadata_test.go @@ -0,0 +1,93 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package blobstorage + +import ( + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" + "github.com/dapr/kit/logger" + "github.com/stretchr/testify/assert" +) + +func TestParseMetadata(t *testing.T) { + logger := logger.NewLogger("test") + var m map[string]string + + t.Run("parse all metadata", func(t *testing.T) { + m = map[string]string{ + "storageAccount": "account", + "storageAccessKey": "key", + "container": "test", + "getBlobRetryCount": "5", + "decodeBase64": "true", + } + meta, err := parseMetadata(m) + assert.Nil(t, err) + assert.Equal(t, "test", meta.ContainerName) + assert.Equal(t, "account", meta.AccountName) + // storageAccessKey is parsed in the azauth package + assert.Equal(t, true, meta.DecodeBase64) + assert.Equal(t, int32(5), meta.RetryCount) + assert.Equal(t, "", string(meta.PublicAccessLevel)) + }) + + t.Run("parse metadata with publicAccessLevel = blob", func(t *testing.T) { + m = map[string]string{ + "storageAccount": "account", + "storageAccessKey": "key", + "container": "test", + "publicAccessLevel": "blob", + } + meta, err := parseMetadata(m) + assert.Nil(t, err) + assert.Equal(t, azblob.PublicAccessTypeBlob, meta.PublicAccessLevel) + }) + + t.Run("parse metadata with publicAccessLevel = container", func(t *testing.T) { + m = map[string]string{ + "storageAccount": "account", + "storageAccessKey": "key", + "container": "test", + "publicAccessLevel": "container", + } + meta, err := parseMetadata(m) + assert.Nil(t, err) + assert.Equal(t, azblob.PublicAccessTypeContainer, meta.PublicAccessLevel) + }) + + t.Run("parse metadata with invalid publicAccessLevel", func(t *testing.T) { + m = map[string]string{ + "storageAccount": "account", + "storageAccessKey": "key", + "container": "test", + "publicAccessLevel": "invalid", + } + _, err := parseMetadata(m) + assert.Error(t, err) + }) + + t.Run("sanitize metadata if necessary", func(t *testing.T) { + m = map[string]string{ + "somecustomfield": "some-custom-value", + "specialfield": "special:valueÜ", + "not-allowed:": "not-allowed", + } + meta := SanitizeMetadata(logger, m) + assert.Equal(t, meta["somecustomfield"], "some-custom-value") + assert.Equal(t, meta["specialfield"], "special:value") + assert.Equal(t, meta["notallowed"], "not-allowed") + }) +} diff --git a/state/azure/blobstorage/blobstorage.go b/state/azure/blobstorage/blobstorage.go index 5c6f6cd38..fb92126dd 100644 --- a/state/azure/blobstorage/blobstorage.go +++ b/state/azure/blobstorage/blobstorage.go @@ -40,20 +40,17 @@ import ( b64 "encoding/base64" "fmt" "io" - "net/url" "reflect" "strings" - "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" - "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/bloberror" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" jsoniter "github.com/json-iterator/go" - azauth "github.com/dapr/components-contrib/internal/authentication/azure" + storageinternal "github.com/dapr/components-contrib/internal/component/azure/blobstorage" mdutils "github.com/dapr/components-contrib/metadata" "github.com/dapr/components-contrib/state" "github.com/dapr/kit/logger" @@ -81,80 +78,13 @@ type StateStore struct { logger logger.Logger } -type blobStorageMetadata struct { - AccountName string - ContainerName string - AccountKey string -} - // Init the connection to blob storage, optionally creates a blob container if it doesn't exist. func (r *StateStore) Init(metadata state.Metadata) error { - m, err := getBlobStorageMetadata(metadata.Properties) + var err error + r.containerClient, _, err = storageinternal.CreateContainerStorageClient(r.logger, metadata.Properties) if err != nil { return err } - - userAgent := "dapr-" + logger.DaprVersion - options := container.ClientOptions{ - ClientOptions: azcore.ClientOptions{ - Telemetry: policy.TelemetryOptions{ - ApplicationID: userAgent, - }, - }, - } - - settings, err := azauth.NewEnvironmentSettings("storage", metadata.Properties) - if err != nil { - return err - } - customEndpoint, ok := metadata.Properties[endpointKey] - var URL *url.URL - if ok && customEndpoint != "" { - var parseErr error - URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.ContainerName)) - if parseErr != nil { - return parseErr - } - } else { - env := settings.AzureEnvironment - URL, _ = url.Parse(fmt.Sprintf("https://%s.blob.%s/%s", m.AccountName, env.StorageEndpointSuffix, m.ContainerName)) - } - - var clientErr error - var client *container.Client - // Try using shared key credentials first - if m.AccountKey != "" { - credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.AccountName, m.AccountKey) - if err != nil { - return fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) - } - client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) - if clientErr != nil { - return fmt.Errorf("cannot init Blobstorage container client: %w", err) - } - r.containerClient = client - } else { - // fallback to AAD - credential, tokenErr := settings.GetTokenCredential() - if err != nil { - return fmt.Errorf("invalid credentials with error: %w", tokenErr) - } - client, clientErr = container.NewClient(URL.String(), credential, &options) - } - if clientErr != nil { - return fmt.Errorf("cannot init Blobstorage client: %w", clientErr) - } - - createContainerOptions := container.CreateOptions{ - Access: nil, - } - timeoutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - _, err = client.Create(timeoutCtx, &createContainerOptions) - cancel() - // Don't return error, container might already exist - r.logger.Debugf("error creating container: %w", err) - r.containerClient = client - return nil } @@ -193,7 +123,7 @@ func (r *StateStore) Ping() error { } func (r *StateStore) GetComponentMetadata() map[string]string { - metadataStruct := blobStorageMetadata{} + metadataStruct := storageinternal.BlobStorageMetadata{} metadataInfo := map[string]string{} mdutils.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo) return metadataInfo @@ -211,25 +141,6 @@ func NewAzureBlobStorageStore(logger logger.Logger) state.Store { return s } -func getBlobStorageMetadata(meta map[string]string) (*blobStorageMetadata, error) { - m := blobStorageMetadata{} - err := mdutils.DecodeMetadata(meta, &m) - - if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountNameKeys...); ok && val != "" { - m.AccountName = val - } else { - return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageAccountNameKeys[0]) - } - - if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageContainerNameKeys...); ok && val != "" { - m.ContainerName = val - } else { - return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0]) - } - - return &m, err -} - func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*state.GetResponse, error) { blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) @@ -289,7 +200,7 @@ func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error uploadOptions := azblob.UploadBufferOptions{ AccessConditions: &accessConditions, - Metadata: req.Metadata, + Metadata: storageinternal.SanitizeMetadata(r.logger, req.Metadata), HTTPHeaders: &blobHTTPHeaders, Concurrency: 16, } diff --git a/state/azure/blobstorage/blobstorage_test.go b/state/azure/blobstorage/blobstorage_test.go index e86505d51..2e69af070 100644 --- a/state/azure/blobstorage/blobstorage_test.go +++ b/state/azure/blobstorage/blobstorage_test.go @@ -58,26 +58,6 @@ func TestInit(t *testing.T) { }) } -func TestGetBlobStorageMetaData(t *testing.T) { - t.Run("Nothing at all passed", func(t *testing.T) { - m := make(map[string]string) - _, err := getBlobStorageMetadata(m) - - assert.NotNil(t, err) - }) - - t.Run("All parameters passed and parsed", func(t *testing.T) { - m := make(map[string]string) - m["accountName"] = "acc" - m["containerName"] = "dapr" - meta, err := getBlobStorageMetadata(m) - - assert.Nil(t, err) - assert.Equal(t, "acc", meta.AccountName) - assert.Equal(t, "dapr", meta.ContainerName) - }) -} - func TestFileName(t *testing.T) { t.Run("Valid composite key", func(t *testing.T) { key := getFileName("app_id||key") From f11fc2421ed2ed1aadf2db5f84787580c9b92bf7 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Thu, 17 Nov 2022 21:43:20 -0800 Subject: [PATCH 07/22] fix linter issue Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- internal/component/azure/blobstorage/metadata_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/component/azure/blobstorage/metadata_test.go b/internal/component/azure/blobstorage/metadata_test.go index e60ef9c14..c466fb093 100644 --- a/internal/component/azure/blobstorage/metadata_test.go +++ b/internal/component/azure/blobstorage/metadata_test.go @@ -18,8 +18,9 @@ import ( "testing" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" - "github.com/dapr/kit/logger" "github.com/stretchr/testify/assert" + + "github.com/dapr/kit/logger" ) func TestParseMetadata(t *testing.T) { From 23d36a08d78e47d64b60553def2262bd6e5bd326 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:56:02 -0800 Subject: [PATCH 08/22] more refactoring and address code review Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 51 +++--------- .../component/azure/blobstorage/client.go | 15 ++-- .../azure/blobstorage/client_test.go | 64 +++++++++++++++ .../component/azure/blobstorage/metadata.go | 4 + .../component/azure/blobstorage/request.go | 73 ++++++++++++++++++ .../azure/blobstorage/request_test.go | 53 +++++++++++++ state/azure/blobstorage/blobstorage.go | 77 +------------------ state/azure/blobstorage/blobstorage_test.go | 38 --------- 8 files changed, 216 insertions(+), 159 deletions(-) create mode 100644 internal/component/azure/blobstorage/client_test.go create mode 100644 internal/component/azure/blobstorage/request.go create mode 100644 internal/component/azure/blobstorage/request_test.go diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index 5150a9b0e..582de9878 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -49,14 +49,6 @@ const ( // Defines the delete snapshots option for the delete operation. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob#request-headers metadataKeyDeleteSnapshots = "deleteSnapshots" - // HTTP headers to be associated with the blob. - // See: https://docs.microsoft.com/en-us/rest/api/storageservices/put-blob#request-headers-all-blob-types - metadataKeyContentType = "contentType" - metadataKeyContentMD5 = "contentMD5" - metadataKeyContentEncoding = "contentEncoding" - metadataKeyContentLanguage = "contentLanguage" - metadataKeyContentDisposition = "contentDisposition" - metadataKeyCacheControl = "cacheControl" // Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not // specify maxresults the server will return up to 5,000 items. // See: https://docs.microsoft.com/en-us/rest/api/storageservices/list-blobs#uri-parameters @@ -124,41 +116,16 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque blobName = val delete(req.Metadata, metadataKeyBlobName) } else { - blobName = uuid.New().String() - } - - blobHTTPHeaders := blob.HTTPHeaders{} - - if val, ok := req.Metadata[metadataKeyContentType]; ok && val != "" { - blobHTTPHeaders.BlobContentType = &val - delete(req.Metadata, metadataKeyContentType) - } - - var contentMD5 *[]byte - if val, ok := req.Metadata[metadataKeyContentMD5]; ok && val != "" { - sDec, err := b64.StdEncoding.DecodeString(val) - if err != nil || len(sDec) != 16 { - return nil, errors.New("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") + id, err := uuid.NewRandom() + if err != nil { + return nil, err } - blobHTTPHeaders.BlobContentMD5 = sDec - contentMD5 = &sDec - delete(req.Metadata, metadataKeyContentMD5) + blobName = id.String() } - if val, ok := req.Metadata[metadataKeyContentEncoding]; ok && val != "" { - blobHTTPHeaders.BlobContentEncoding = &val - delete(req.Metadata, metadataKeyContentEncoding) - } - if val, ok := req.Metadata[metadataKeyContentLanguage]; ok && val != "" { - blobHTTPHeaders.BlobContentLanguage = &val - delete(req.Metadata, metadataKeyContentLanguage) - } - if val, ok := req.Metadata[metadataKeyContentDisposition]; ok && val != "" { - blobHTTPHeaders.BlobContentDisposition = &val - delete(req.Metadata, metadataKeyContentDisposition) - } - if val, ok := req.Metadata[metadataKeyCacheControl]; ok && val != "" { - blobHTTPHeaders.BlobCacheControl = &val - delete(req.Metadata, metadataKeyCacheControl) + + blobHTTPHeaders, err := storageinternal.CreateBlobHTTPHeadersFromRequest(req.Metadata, nil, a.logger) + if err != nil { + return nil, err } d, err := strconv.Unquote(string(req.Data)) @@ -177,7 +144,7 @@ func (a *AzureBlobStorage) create(ctx context.Context, req *bindings.InvokeReque uploadOptions := azblob.UploadBufferOptions{ Metadata: storageinternal.SanitizeMetadata(a.logger, req.Metadata), HTTPHeaders: &blobHTTPHeaders, - TransactionalContentMD5: contentMD5, + TransactionalContentMD5: &blobHTTPHeaders.BlobContentMD5, } blockBlobClient := a.containerClient.NewBlockBlobClient(blobName) diff --git a/internal/component/azure/blobstorage/client.go b/internal/component/azure/blobstorage/client.go index 64eb5a6d2..7a9250421 100644 --- a/internal/component/azure/blobstorage/client.go +++ b/internal/component/azure/blobstorage/client.go @@ -25,11 +25,11 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container" azauth "github.com/dapr/components-contrib/internal/authentication/azure" + mdutils "github.com/dapr/components-contrib/metadata" "github.com/dapr/kit/logger" ) const ( - endpointKey = "endpoint" // Specifies the maximum number of HTTP requests that will be made to retry blob operations. A value // of zero means that no additional HTTP requests will be made. defaultBlobRetryCount = 3 @@ -57,9 +57,12 @@ func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*c if err != nil { return nil, nil, err } - customEndpoint, ok := meta[endpointKey] + var customEndpoint string + if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageEndpointKeys...); ok && val != "" { + customEndpoint = val + } var URL *url.URL - if ok && customEndpoint != "" { + if customEndpoint != "" { var parseErr error URL, parseErr = url.Parse(fmt.Sprintf("%s/%s/%s", customEndpoint, m.AccountName, m.ContainerName)) if parseErr != nil { @@ -76,7 +79,7 @@ func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*c if m.AccountKey != "" { credential, newSharedKeyErr := azblob.NewSharedKeyCredential(m.AccountName, m.AccountKey) if err != nil { - return nil, nil, fmt.Errorf("invalid credentials with error: %w", newSharedKeyErr) + return nil, nil, fmt.Errorf("invalid shared key credentials with error: %w", newSharedKeyErr) } client, clientErr = container.NewClientWithSharedKeyCredential(URL.String(), credential, &options) if clientErr != nil { @@ -86,7 +89,7 @@ func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*c // fallback to AAD credential, tokenErr := settings.GetTokenCredential() if err != nil { - return nil, nil, fmt.Errorf("invalid credentials with error: %w", tokenErr) + return nil, nil, fmt.Errorf("invalid token credentials with error: %w", tokenErr) } client, clientErr = container.NewClient(URL.String(), credential, &options) } @@ -102,7 +105,7 @@ func CreateContainerStorageClient(log logger.Logger, meta map[string]string) (*c _, err = client.Create(timeoutCtx, &createContainerOptions) cancel() // Don't return error, container might already exist - log.Debugf("error creating container: %w", err) + log.Debugf("error creating container: %v", err) return client, m, nil } diff --git a/internal/component/azure/blobstorage/client_test.go b/internal/component/azure/blobstorage/client_test.go new file mode 100644 index 000000000..61ebe43ba --- /dev/null +++ b/internal/component/azure/blobstorage/client_test.go @@ -0,0 +1,64 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package blobstorage + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + azauth "github.com/dapr/components-contrib/internal/authentication/azure" + "github.com/dapr/kit/logger" +) + +type scenario struct { + metadata map[string]string + expectedFailureSubString string +} + +func TestClientInitFailures(t *testing.T) { + log := logger.NewLogger("test") + + scenarios := map[string]scenario{ + "missing accountName": { + metadata: createTestMetadata(false, true, true), + expectedFailureSubString: "missing or empty accountName field from metadata", + }, + "missing container": { + metadata: createTestMetadata(true, true, false), + expectedFailureSubString: "missing or empty containerName field from metadata", + }, + } + + for name, s := range scenarios { + t.Run(name, func(t *testing.T) { + _, _, err := CreateContainerStorageClient(log, s.metadata) + assert.Contains(t, err.Error(), s.expectedFailureSubString) + }) + } +} + +func createTestMetadata(accountName bool, accountKey bool, container bool) map[string]string { + m := map[string]string{} + if accountName { + m[azauth.StorageAccountNameKeys[0]] = "account" + } + if accountKey { + m[azauth.StorageAccountKeyKeys[0]] = "key" + } + if container { + m[azauth.StorageContainerNameKeys[0]] = "test" + } + return m +} diff --git a/internal/component/azure/blobstorage/metadata.go b/internal/component/azure/blobstorage/metadata.go index 14223c9ef..04a3499e5 100644 --- a/internal/component/azure/blobstorage/metadata.go +++ b/internal/component/azure/blobstorage/metadata.go @@ -51,6 +51,10 @@ func parseMetadata(meta map[string]string) (*BlobStorageMetadata, error) { return nil, fmt.Errorf("missing or empty %s field from metadata", azauth.StorageContainerNameKeys[0]) } + if val, ok := mdutils.GetMetadataProperty(meta, azauth.StorageAccountKeyKeys...); ok && val != "" { + m.AccountKey = val + } + // per the Dapr documentation "none" is a valid value if m.PublicAccessLevel == "none" { m.PublicAccessLevel = "" diff --git a/internal/component/azure/blobstorage/request.go b/internal/component/azure/blobstorage/request.go new file mode 100644 index 000000000..38bc5e4e2 --- /dev/null +++ b/internal/component/azure/blobstorage/request.go @@ -0,0 +1,73 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package blobstorage + +import ( + b64 "encoding/base64" + "fmt" + + "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" + + "github.com/dapr/kit/logger" +) + +const ( + contentTypeKey = "ContentType" + contentMD5Key = "ContentMD5" + contentEncodingKey = "ContentEncoding" + contentLanguageKey = "ContentLanguage" + contentDispositionKey = "ContentDisposition" + cacheControlKey = "CacheControl" +) + +func CreateBlobHTTPHeadersFromRequest(meta map[string]string, contentType *string, log logger.Logger) (blob.HTTPHeaders, error) { + blobHTTPHeaders := blob.HTTPHeaders{} + if val, ok := meta[contentTypeKey]; ok && val != "" { + blobHTTPHeaders.BlobContentType = &val + delete(meta, contentTypeKey) + } + + if contentType != nil { + if blobHTTPHeaders.BlobContentType != nil { + log.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.BlobContentType, *contentType) + } + blobHTTPHeaders.BlobContentType = contentType + } + + if val, ok := meta[contentMD5Key]; ok && val != "" { + sDec, err := b64.StdEncoding.DecodeString(val) + if err != nil || len(sDec) != 16 { + return blob.HTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") + } + blobHTTPHeaders.BlobContentMD5 = sDec + delete(meta, contentMD5Key) + } + if val, ok := meta[contentEncodingKey]; ok && val != "" { + blobHTTPHeaders.BlobContentEncoding = &val + delete(meta, contentEncodingKey) + } + if val, ok := meta[contentLanguageKey]; ok && val != "" { + blobHTTPHeaders.BlobContentLanguage = &val + delete(meta, contentLanguageKey) + } + if val, ok := meta[contentDispositionKey]; ok && val != "" { + blobHTTPHeaders.BlobContentDisposition = &val + delete(meta, contentDispositionKey) + } + if val, ok := meta[cacheControlKey]; ok && val != "" { + blobHTTPHeaders.BlobCacheControl = &val + delete(meta, cacheControlKey) + } + return blobHTTPHeaders, nil +} diff --git a/internal/component/azure/blobstorage/request_test.go b/internal/component/azure/blobstorage/request_test.go new file mode 100644 index 000000000..051eb6f0f --- /dev/null +++ b/internal/component/azure/blobstorage/request_test.go @@ -0,0 +1,53 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package blobstorage + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/dapr/kit/logger" +) + +func TestBlobHTTPHeaderGeneration(t *testing.T) { + log := logger.NewLogger("test") + + t.Run("Content type is set from request, forward compatibility", func(t *testing.T) { + contentType := "application/json" + requestMetadata := map[string]string{} + + blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, &contentType, log) + assert.Nil(t, err) + assert.Equal(t, "application/json", *blobHeaders.BlobContentType) + }) + t.Run("Content type and metadata provided (conflict), content type chosen", func(t *testing.T) { + contentType := "application/json" + requestMetadata := map[string]string{ + contentTypeKey: "text/plain", + } + + blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, &contentType, log) + assert.Nil(t, err) + assert.Equal(t, "application/json", *blobHeaders.BlobContentType) + }) + t.Run("ContentType not provided, metadata provided set backward compatibility", func(t *testing.T) { + requestMetadata := map[string]string{ + contentTypeKey: "text/plain", + } + blobHeaders, err := CreateBlobHTTPHeadersFromRequest(requestMetadata, nil, log) + assert.Nil(t, err) + assert.Equal(t, "text/plain", *blobHeaders.BlobContentType) + }) +} diff --git a/state/azure/blobstorage/blobstorage.go b/state/azure/blobstorage/blobstorage.go index fb92126dd..c3d238706 100644 --- a/state/azure/blobstorage/blobstorage.go +++ b/state/azure/blobstorage/blobstorage.go @@ -37,7 +37,6 @@ package blobstorage import ( "context" - b64 "encoding/base64" "fmt" "io" "reflect" @@ -58,14 +57,7 @@ import ( ) const ( - keyDelimiter = "||" - contentType = "ContentType" - contentMD5 = "ContentMD5" - contentEncoding = "ContentEncoding" - contentLanguage = "ContentLanguage" - contentDisposition = "ContentDisposition" - cacheControl = "CacheControl" - endpointKey = "endpoint" + keyDelimiter = "||" ) // StateStore Type. @@ -95,27 +87,21 @@ func (r *StateStore) Features() []state.Feature { // Delete the state. func (r *StateStore) Delete(req *state.DeleteRequest) error { - r.logger.Debugf("delete %s", req.Key) return r.deleteFile(context.Background(), req) } // Get the state. func (r *StateStore) Get(req *state.GetRequest) (*state.GetResponse, error) { - r.logger.Debugf("get %s", req.Key) return r.readFile(context.Background(), req) } // Set the state. func (r *StateStore) Set(req *state.SetRequest) error { - r.logger.Debugf("saving %s", req.Key) return r.writeFile(context.Background(), req) } func (r *StateStore) Ping() error { - getPropertiesOptions := container.GetPropertiesOptions{ - LeaseAccessConditions: &container.LeaseAccessConditions{}, - } - if _, err := r.containerClient.GetProperties(context.Background(), &getPropertiesOptions); err != nil { + if _, err := r.containerClient.GetProperties(context.Background(), nil); err != nil { return fmt.Errorf("blob storage: error connecting to Blob storage at %s: %s", r.containerClient.URL(), err) } @@ -143,15 +129,8 @@ func NewAzureBlobStorageStore(logger logger.Logger) state.Store { func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*state.GetResponse, error) { blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) - - downloadOptions := azblob.DownloadStreamOptions{ - AccessConditions: &blob.AccessConditions{}, - } - - blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, &downloadOptions) + blobDownloadResponse, err := blockBlobClient.DownloadStream(ctx, nil) if err != nil { - r.logger.Debugf("download file %s, err %s", req.Key, err) - if isNotFoundError(err) { return &state.GetResponse{}, nil } @@ -165,10 +144,6 @@ func (r *StateStore) readFile(ctx context.Context, req *state.GetRequest) (*stat if err != nil { return &state.GetResponse{}, fmt.Errorf("error reading az blob: %w", err) } - err = reader.Close() - if err != nil { - return &state.GetResponse{}, fmt.Errorf("error closing az blob reader: %w", err) - } contentType := blobDownloadResponse.ContentType @@ -193,7 +168,7 @@ func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error ModifiedAccessConditions: &modifiedAccessConditions, } - blobHTTPHeaders, err := r.createBlobHTTPHeadersFromRequest(req) + blobHTTPHeaders, err := storageinternal.CreateBlobHTTPHeadersFromRequest(req.Metadata, req.ContentType, r.logger) if err != nil { return err } @@ -202,7 +177,6 @@ func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error AccessConditions: &accessConditions, Metadata: storageinternal.SanitizeMetadata(r.logger, req.Metadata), HTTPHeaders: &blobHTTPHeaders, - Concurrency: 16, } blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) @@ -220,47 +194,6 @@ func (r *StateStore) writeFile(ctx context.Context, req *state.SetRequest) error return nil } -func (r *StateStore) createBlobHTTPHeadersFromRequest(req *state.SetRequest) (blob.HTTPHeaders, error) { - blobHTTPHeaders := blob.HTTPHeaders{} - if val, ok := req.Metadata[contentType]; ok && val != "" { - blobHTTPHeaders.BlobContentType = &val - delete(req.Metadata, contentType) - } - - if req.ContentType != nil { - if blobHTTPHeaders.BlobContentType != nil { - r.logger.Warnf("ContentType received from request Metadata %s, as well as ContentType property %s, choosing value from contentType property", blobHTTPHeaders.BlobContentType, req.ContentType) - } - blobHTTPHeaders.BlobContentType = req.ContentType - } - - if val, ok := req.Metadata[contentMD5]; ok && val != "" { - sDec, err := b64.StdEncoding.DecodeString(val) - if err != nil || len(sDec) != 16 { - return blob.HTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") - } - blobHTTPHeaders.BlobContentMD5 = sDec - delete(req.Metadata, contentMD5) - } - if val, ok := req.Metadata[contentEncoding]; ok && val != "" { - blobHTTPHeaders.BlobContentEncoding = &val - delete(req.Metadata, contentEncoding) - } - if val, ok := req.Metadata[contentLanguage]; ok && val != "" { - blobHTTPHeaders.BlobContentLanguage = &val - delete(req.Metadata, contentLanguage) - } - if val, ok := req.Metadata[contentDisposition]; ok && val != "" { - blobHTTPHeaders.BlobContentDisposition = &val - delete(req.Metadata, contentDisposition) - } - if val, ok := req.Metadata[cacheControl]; ok && val != "" { - blobHTTPHeaders.BlobCacheControl = &val - delete(req.Metadata, cacheControl) - } - return blobHTTPHeaders, nil -} - func (r *StateStore) deleteFile(ctx context.Context, req *state.DeleteRequest) error { blockBlobClient := r.containerClient.NewBlockBlobClient(getFileName(req.Key)) @@ -278,8 +211,6 @@ func (r *StateStore) deleteFile(ctx context.Context, req *state.DeleteRequest) e _, err := blockBlobClient.Delete(ctx, &deleteOptions) if err != nil { - r.logger.Debugf("delete file %s, err %s", req.Key, err) - if req.ETag != nil && isETagConflictError(err) { return state.NewETagError(state.ETagMismatch, err) } else if isNotFoundError(err) { diff --git a/state/azure/blobstorage/blobstorage_test.go b/state/azure/blobstorage/blobstorage_test.go index 2e69af070..e8ec8a97b 100644 --- a/state/azure/blobstorage/blobstorage_test.go +++ b/state/azure/blobstorage/blobstorage_test.go @@ -69,41 +69,3 @@ func TestFileName(t *testing.T) { assert.Equal(t, "key", key) }) } - -func TestBlobHTTPHeaderGeneration(t *testing.T) { - s := NewAzureBlobStorageStore(logger.NewLogger("logger")).(*StateStore) - t.Run("Content type is set from request, forward compatibility", func(t *testing.T) { - contentType := "application/json" - req := &state.SetRequest{ - ContentType: &contentType, - } - - blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) - assert.Nil(t, err) - assert.Equal(t, "application/json", *blobHeaders.BlobContentType) - }) - t.Run("Content type and metadata provided (conflict), content type chosen", func(t *testing.T) { - contentType := "application/json" - req := &state.SetRequest{ - ContentType: &contentType, - Metadata: map[string]string{ - contentType: "text/plain", - }, - } - - blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) - assert.Nil(t, err) - assert.Equal(t, "application/json", *blobHeaders.BlobContentType) - }) - t.Run("ContentType not provided, metadata provided set backward compatibility", func(t *testing.T) { - req := &state.SetRequest{ - Metadata: map[string]string{ - contentType: "text/plain", - }, - } - - blobHeaders, err := s.createBlobHTTPHeadersFromRequest(req) - assert.Nil(t, err) - assert.Equal(t, "text/plain", *blobHeaders.BlobContentType) - }) -} From f1b9374f9a72da8c0a1c6e94f75184cdc31dfc10 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Fri, 18 Nov 2022 18:02:09 -0800 Subject: [PATCH 09/22] Move tests around Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- .../component/azure/blobstorage/metadata.go | 39 ------------------- .../azure/blobstorage/metadata_test.go | 15 ------- .../component/azure/blobstorage/request.go | 38 ++++++++++++++++++ .../azure/blobstorage/request_test.go | 15 +++++++ 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/internal/component/azure/blobstorage/metadata.go b/internal/component/azure/blobstorage/metadata.go index 04a3499e5..af3db2061 100644 --- a/internal/component/azure/blobstorage/metadata.go +++ b/internal/component/azure/blobstorage/metadata.go @@ -21,7 +21,6 @@ import ( azauth "github.com/dapr/components-contrib/internal/authentication/azure" mdutils "github.com/dapr/components-contrib/metadata" - "github.com/dapr/kit/logger" ) type BlobStorageMetadata struct { @@ -87,41 +86,3 @@ func isValidPublicAccessType(accessType azblob.PublicAccessType) bool { return false } - -func SanitizeMetadata(log logger.Logger, metadata map[string]string) map[string]string { - for key, val := range metadata { - // Keep only letters and digits - n := 0 - newKey := make([]byte, len(key)) - for i := 0; i < len(key); i++ { - if (key[i] >= 'A' && key[i] <= 'Z') || - (key[i] >= 'a' && key[i] <= 'z') || - (key[i] >= '0' && key[i] <= '9') { - newKey[n] = key[i] - n++ - } - } - - if n != len(key) { - nks := string(newKey[:n]) - log.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks) - delete(metadata, key) - metadata[nks] = val - key = nks - } - - // Remove all non-ascii characters - n = 0 - newVal := make([]byte, len(val)) - for i := 0; i < len(val); i++ { - if val[i] > 127 { - continue - } - newVal[n] = val[i] - n++ - } - metadata[key] = string(newVal[:n]) - } - - return metadata -} diff --git a/internal/component/azure/blobstorage/metadata_test.go b/internal/component/azure/blobstorage/metadata_test.go index c466fb093..e0d648184 100644 --- a/internal/component/azure/blobstorage/metadata_test.go +++ b/internal/component/azure/blobstorage/metadata_test.go @@ -19,12 +19,9 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/stretchr/testify/assert" - - "github.com/dapr/kit/logger" ) func TestParseMetadata(t *testing.T) { - logger := logger.NewLogger("test") var m map[string]string t.Run("parse all metadata", func(t *testing.T) { @@ -79,16 +76,4 @@ func TestParseMetadata(t *testing.T) { _, err := parseMetadata(m) assert.Error(t, err) }) - - t.Run("sanitize metadata if necessary", func(t *testing.T) { - m = map[string]string{ - "somecustomfield": "some-custom-value", - "specialfield": "special:valueÜ", - "not-allowed:": "not-allowed", - } - meta := SanitizeMetadata(logger, m) - assert.Equal(t, meta["somecustomfield"], "some-custom-value") - assert.Equal(t, meta["specialfield"], "special:value") - assert.Equal(t, meta["notallowed"], "not-allowed") - }) } diff --git a/internal/component/azure/blobstorage/request.go b/internal/component/azure/blobstorage/request.go index 38bc5e4e2..38f017bbc 100644 --- a/internal/component/azure/blobstorage/request.go +++ b/internal/component/azure/blobstorage/request.go @@ -71,3 +71,41 @@ func CreateBlobHTTPHeadersFromRequest(meta map[string]string, contentType *strin } return blobHTTPHeaders, nil } + +func SanitizeMetadata(log logger.Logger, metadata map[string]string) map[string]string { + for key, val := range metadata { + // Keep only letters and digits + n := 0 + newKey := make([]byte, len(key)) + for i := 0; i < len(key); i++ { + if (key[i] >= 'A' && key[i] <= 'Z') || + (key[i] >= 'a' && key[i] <= 'z') || + (key[i] >= '0' && key[i] <= '9') { + newKey[n] = key[i] + n++ + } + } + + if n != len(key) { + nks := string(newKey[:n]) + log.Warnf("metadata key %s contains disallowed characters, sanitized to %s", key, nks) + delete(metadata, key) + metadata[nks] = val + key = nks + } + + // Remove all non-ascii characters + n = 0 + newVal := make([]byte, len(val)) + for i := 0; i < len(val); i++ { + if val[i] > 127 { + continue + } + newVal[n] = val[i] + n++ + } + metadata[key] = string(newVal[:n]) + } + + return metadata +} diff --git a/internal/component/azure/blobstorage/request_test.go b/internal/component/azure/blobstorage/request_test.go index 051eb6f0f..74d92e7ed 100644 --- a/internal/component/azure/blobstorage/request_test.go +++ b/internal/component/azure/blobstorage/request_test.go @@ -51,3 +51,18 @@ func TestBlobHTTPHeaderGeneration(t *testing.T) { assert.Equal(t, "text/plain", *blobHeaders.BlobContentType) }) } + +func TestSanitizeRequestMetadata(t *testing.T) { + log := logger.NewLogger("test") + t.Run("sanitize metadata if necessary", func(t *testing.T) { + m := map[string]string{ + "somecustomfield": "some-custom-value", + "specialfield": "special:valueÜ", + "not-allowed:": "not-allowed", + } + meta := SanitizeMetadata(log, m) + assert.Equal(t, meta["somecustomfield"], "some-custom-value") + assert.Equal(t, meta["specialfield"], "special:value") + assert.Equal(t, meta["notallowed"], "not-allowed") + }) +} From 7d5c06bc8df7b69ecc9aea5761357805f3751469 Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Wed, 23 Nov 2022 01:43:24 +0000 Subject: [PATCH 10/22] Make blob metadata case insensitive Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- .../component/azure/blobstorage/request.go | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/internal/component/azure/blobstorage/request.go b/internal/component/azure/blobstorage/request.go index 38f017bbc..2d3dade3d 100644 --- a/internal/component/azure/blobstorage/request.go +++ b/internal/component/azure/blobstorage/request.go @@ -16,6 +16,7 @@ package blobstorage import ( b64 "encoding/base64" "fmt" + "strings" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" @@ -23,19 +24,25 @@ import ( ) const ( - contentTypeKey = "ContentType" - contentMD5Key = "ContentMD5" - contentEncodingKey = "ContentEncoding" - contentLanguageKey = "ContentLanguage" - contentDispositionKey = "ContentDisposition" - cacheControlKey = "CacheControl" + contentTypeKey = "contenttype" + contentMD5Key = "contentmd5" + contentEncodingKey = "contentencoding" + contentLanguageKey = "contentlanguage" + contentDispositionKey = "contentdisposition" + cacheControlKey = "cachecontrol" ) func CreateBlobHTTPHeadersFromRequest(meta map[string]string, contentType *string, log logger.Logger) (blob.HTTPHeaders, error) { + // build map to support arbitrary case + caseMap := make(map[string]string) + for k := range meta { + caseMap[strings.ToLower(k)] = k + } + blobHTTPHeaders := blob.HTTPHeaders{} - if val, ok := meta[contentTypeKey]; ok && val != "" { + if val, ok := meta[caseMap[contentTypeKey]]; ok && val != "" { blobHTTPHeaders.BlobContentType = &val - delete(meta, contentTypeKey) + delete(meta, caseMap[contentTypeKey]) } if contentType != nil { @@ -45,29 +52,29 @@ func CreateBlobHTTPHeadersFromRequest(meta map[string]string, contentType *strin blobHTTPHeaders.BlobContentType = contentType } - if val, ok := meta[contentMD5Key]; ok && val != "" { + if val, ok := meta[caseMap[contentMD5Key]]; ok && val != "" { sDec, err := b64.StdEncoding.DecodeString(val) if err != nil || len(sDec) != 16 { return blob.HTTPHeaders{}, fmt.Errorf("the MD5 value specified in Content MD5 is invalid, MD5 value must be 128 bits and base64 encoded") } blobHTTPHeaders.BlobContentMD5 = sDec - delete(meta, contentMD5Key) + delete(meta, caseMap[contentMD5Key]) } - if val, ok := meta[contentEncodingKey]; ok && val != "" { + if val, ok := meta[caseMap[contentEncodingKey]]; ok && val != "" { blobHTTPHeaders.BlobContentEncoding = &val - delete(meta, contentEncodingKey) + delete(meta, caseMap[contentEncodingKey]) } - if val, ok := meta[contentLanguageKey]; ok && val != "" { + if val, ok := meta[caseMap[contentLanguageKey]]; ok && val != "" { blobHTTPHeaders.BlobContentLanguage = &val - delete(meta, contentLanguageKey) + delete(meta, caseMap[contentLanguageKey]) } - if val, ok := meta[contentDispositionKey]; ok && val != "" { + if val, ok := meta[caseMap[contentDispositionKey]]; ok && val != "" { blobHTTPHeaders.BlobContentDisposition = &val - delete(meta, contentDispositionKey) + delete(meta, caseMap[contentDispositionKey]) } - if val, ok := meta[cacheControlKey]; ok && val != "" { + if val, ok := meta[caseMap[cacheControlKey]]; ok && val != "" { blobHTTPHeaders.BlobCacheControl = &val - delete(meta, cacheControlKey) + delete(meta, caseMap[cacheControlKey]) } return blobHTTPHeaders, nil } From 9d6f1e0ded5de318da47b285dee5035c9620c50a Mon Sep 17 00:00:00 2001 From: Tiago Alves Macambira Date: Fri, 25 Nov 2022 18:58:17 -0800 Subject: [PATCH 11/22] Additional tests for Hashicorp Vaul Secret Store certification. * This PR adds additional tests to complete vault certification. A detailed test plann is added to its README. * Fixes a vault behaviour regarding its multiple key-values per secret behaviour when its `valueType` flag is set to `text`. This is a follow up to dapr/components-contrib#2140. Closes #1926. Signed-off-by: Tiago Alves Macambira --- .../setup-hashicorp-vault-secrets.sh | 2 + .../docker-compose-hashicorp-vault.yml | 3 +- secretstores/README.md | 2 +- secretstores/hashicorp/vault/vault.go | 6 +- secretstores/hashicorp/vault/vault_test.go | 45 +- .../secretstores/hashicorp/vault/README.md | 128 ++- .../vault/components/caFamily/Makefile | 48 ++ .../vault/components/caFamily/README.md | 26 + .../docker-compose-hashicorp-vault.yml | 46 ++ .../caFamily/badCaCert/hashicorp-vault.yml | 20 + .../docker-compose-hashicorp-vault.yml | 46 ++ .../hashicorp-vault.yml | 20 + .../docker-compose-hashicorp-vault.yml | 46 ++ .../badTlsServerName/hashicorp-vault.yml | 20 + .../caCert/docker-compose-hashicorp-vault.yml | 46 ++ .../caFamily/caCert/hashicorp-vault.yml | 20 + .../caPath/docker-compose-hashicorp-vault.yml | 46 ++ .../caFamily/caPath/hashicorp-vault.yml | 20 + .../caPem/docker-compose-hashicorp-vault.yml | 46 ++ .../caFamily/caPem/hashicorp-vault.yml | 59 ++ .../caPem/hashicorp-vault.yml.template | 20 + .../components/caFamily/certificates/cert.pem | 34 + .../certificates/incorrect-ca-cert.pem | 34 + .../certificates/incorrect-ca-key.pem | 52 ++ .../components/caFamily/certificates/key.pem | 52 ++ .../caFamily/vaultConfig/vault_server.hcl | 15 + .../docker-compose-hashicorp-vault.yml | 37 + .../customSecretsPath/hashicorp-vault.yml | 15 + .../setup-hashicorp-vault-secrets.sh | 31 + .../enginePath/secret/hashicorp-vault.yml | 15 + .../docker-compose-hashicorp-vault.yml | 38 + .../vaultAddr/missing/hashicorp-vault.yml | 19 + .../docker-compose-hashicorp-vault.yml | 38 + .../hashicorp-vault.yml | 19 + .../docker-compose-hashicorp-vault.yml | 36 + .../vaultAddr/nonStdPort/hashicorp-vault.yml | 14 + .../wrongAddress/hashicorp-vault.yml | 13 + .../vaultKVPrefix/hashicorp-vault.yml | 15 + .../vaultKVUsePrefixFalse/hashicorp-vault.yml | 15 + .../badVaultToken/hashicorp-vault.yml | 14 + .../both/hashicorp-vault.yml | 16 + .../neither/hashicorp-vault.yml | 13 + .../hashicorp-vault.yml | 15 + .../vault_token_file.txt | 1 + .../hashicorp-vault.yml | 14 + .../vaultValueTypeText/hashicorp-vault.yml | 15 + .../docker-compose-hashicorp-vault.yml | 37 + .../components/versioning/hashicorp-vault.yml | 13 + .../seed-secret-with-multiple-versions.sh | 34 + .../hashicorp/vault/vault_test.go | 750 +++++++++++++++--- 50 files changed, 2014 insertions(+), 115 deletions(-) create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml.template create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem create mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl create mode 100644 tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/hashicorp-vault.yml create mode 100755 tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/setup-hashicorp-vault-secrets.sh create mode 100644 tests/certification/secretstores/hashicorp/vault/components/enginePath/secret/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultAddr/wrongAddress/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultKVPrefix/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultKVUsePrefixFalse/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/badVaultToken/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/both/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/neither/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathPointsToBrokenPath/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/vaultValueTypeText/hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml create mode 100644 tests/certification/secretstores/hashicorp/vault/components/versioning/hashicorp-vault.yml create mode 100755 tests/certification/secretstores/hashicorp/vault/components/versioning/seed-secret-with-multiple-versions.sh diff --git a/.github/infrastructure/conformance/hashicorp/setup-hashicorp-vault-secrets.sh b/.github/infrastructure/conformance/hashicorp/setup-hashicorp-vault-secrets.sh index 35ad267d0..00c004528 100755 --- a/.github/infrastructure/conformance/hashicorp/setup-hashicorp-vault-secrets.sh +++ b/.github/infrastructure/conformance/hashicorp/setup-hashicorp-vault-secrets.sh @@ -16,6 +16,8 @@ for attempt in `seq $MAX_ATTEMPTS`; do if vault status && vault kv put secret/dapr/conftestsecret conftestsecret=abcd && vault kv put secret/dapr/secondsecret secondsecret=efgh && + vault kv put secret/secretWithNoPrefix noPrefixKey=noProblem && + vault kv put secret/alternativePrefix/secretUnderAlternativePrefix altPrefixKey=altPrefixValue && vault kv put secret/dapr/multiplekeyvaluessecret first=1 second=2 third=3; then echo ✅ secrets set; diff --git a/.github/infrastructure/docker-compose-hashicorp-vault.yml b/.github/infrastructure/docker-compose-hashicorp-vault.yml index 7d5cc7de0..eafd2cef8 100644 --- a/.github/infrastructure/docker-compose-hashicorp-vault.yml +++ b/.github/infrastructure/docker-compose-hashicorp-vault.yml @@ -1,8 +1,9 @@ version: '3.9' # Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once -x-common-vaues: +x-common-values: # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt vault_token: &VAULT_TOKEN "vault-dev-root-token-id" # Reuse the same docker image to save on resources and because the base vault image # has everything we need for seeding the initial key values too. diff --git a/secretstores/README.md b/secretstores/README.md index 66725a685..3631ceb65 100644 --- a/secretstores/README.md +++ b/secretstores/README.md @@ -4,4 +4,4 @@ Secret Stores provide a common way to interact with different secret stores, clo ## Implementing a new Secret Store -A compliant secret store needs to implement the `SecretStore` inteface included in the [`secret_store.go`](secret_store.go) file. +A compliant secret store needs to implement the `SecretStore` interface included in the [`secret_store.go`](secret_store.go) file. diff --git a/secretstores/hashicorp/vault/vault.go b/secretstores/hashicorp/vault/vault.go index da029b9fa..0d540c2ee 100644 --- a/secretstores/hashicorp/vault/vault.go +++ b/secretstores/hashicorp/vault/vault.go @@ -508,5 +508,9 @@ func readCertificateFolder(certPool *x509.CertPool, path string) error { // Features returns the features available in this secret store. func (v *vaultSecretStore) Features() []secretstores.Feature { - return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret} + if v.vaultValueType == valueTypeText { + return []secretstores.Feature{} + } else { + return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret} + } } diff --git a/secretstores/hashicorp/vault/vault_test.go b/secretstores/hashicorp/vault/vault_test.go index 0fc662e84..093667d53 100644 --- a/secretstores/hashicorp/vault/vault_test.go +++ b/secretstores/hashicorp/vault/vault_test.go @@ -409,10 +409,49 @@ func getCertificate() []byte { } func TestGetFeatures(t *testing.T) { - s := NewHashiCorpVaultSecretStore(logger.NewLogger("test")) - // Yes, we are skipping initialization as feature retrieval doesn't depend on it. - t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET", func(t *testing.T) { + initVaultWithVaultValueType := func(vaultValueType string) secretstores.SecretStore { + properties := map[string]string{ + "vaultToken": expectedTok, + "skipVerify": "true", + "vaultValueType": vaultValueType, + } + + m := secretstores.Metadata{ + Base: metadata.Base{Properties: properties}, + } + + target := &vaultSecretStore{ + client: nil, + logger: nil, + } + + // This call will throw an error on Windows systems because of the of + // the call x509.SystemCertPool() because system root pool is not + // available on Windows so ignore the error for when the tests are run + // on the Windows platform during CI + _ = target.Init(m) + + return target + } + + t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET by default", func(t *testing.T) { + // Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value + s := NewHashiCorpVaultSecretStore(logger.NewLogger("test")) f := s.Features() assert.True(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f)) }) + + t.Run("Vault supports MULTIPLE_KEY_VALUES_PER_SECRET if configured with vaultValueType=map", func(t *testing.T) { + // Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value + s := initVaultWithVaultValueType("text") + f := s.Features() + assert.False(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f)) + }) + + t.Run("Vault does not support MULTIPLE_KEY_VALUES_PER_SECRET if configured with vaultValueType=text", func(t *testing.T) { + // Yes, we are skipping initialization as feature retrieval doesn't depend on it for the default value + s := initVaultWithVaultValueType("text") + f := s.Features() + assert.False(t, secretstores.FeatureMultipleKeyValuesPerSecret.IsPresent(f)) + }) } diff --git a/tests/certification/secretstores/hashicorp/vault/README.md b/tests/certification/secretstores/hashicorp/vault/README.md index 480417e4b..b4ee693f5 100644 --- a/tests/certification/secretstores/hashicorp/vault/README.md +++ b/tests/certification/secretstores/hashicorp/vault/README.md @@ -16,17 +16,118 @@ This secret store [supports the following features][features]: ## Test network instability 1. Vault component does not expose a time out configuration option. For this test, let's assume a 1 minute timeout. 2. Retrieve a key to show the connection is fine. -3. Interrupt the network (Vault port, 8200) for longer than the established timeout value. +3. Interrupt the network on Vault's port (8200) for longer than the established timeout value. 4. Wait a few seconds (less than the timeout value). 5. Try to read the key from step 2 and assert it is still there. ## Test support for multiple keys under the same secret -1. Test retrieval of secrets with multiple keys under it +1. Test retrieval of secrets with multiple keys under it. + +## Tests for metadata fields + +### Tests for `vaultKVPrefix`, `vaultKVUsePrefix` and `vaultValueTypeText` + +1. Verify `vaultKVPrefix` is used + * set field to to non default value + * run dapr application with component + * component should successfully initialize + * component should advertise `multipleKeyValuesPerSecret` feature + * retrieval of key under registered under new prefix should succeed + * keys under default and empty prefixes should be missing +1. Verify `vaultKVUsePrefix` is used + * set field to `false` (non default value) + * run dapr application with component + * component should successfully initialize + * component should advertise `multipleKeyValuesPerSecret` feature + * retrieval of key registered without (empty) prefix should succeed + * keys under default and non-default prefix from step above should be missing +1. Verify `vaultValueTypeText` is used + * set field to to non default value `text` + * run dapr application with component + * component should successfully initialize + * component should **not** advertise `multipleKeyValuesPerSecret` feature + * retrieval of key under registered under new prefix should succeed + * keys under default and empty prefixes should be missing + + +### Tests for `vaultToken` and `vaultTokenMountPath` + +1. Verify `vaultToken` is used (happy case) + * The baseline fo this test is all the previous test are using a known-to-work value that matches what our docker-compose environment sets up. +1. Verify failure when we use a `vaultToken` value that does not match what our environment sets up +1. Verify `vaultTokenMountPath` is used (happy case) +1. Verify failure when `vaultTokenMountPath` points to a broken path +1. Verify failure when both `vaultToken` and `vaultTokenMountPath` are missing +1. Verify failure when both `vaultToken` and `vaultTokenMountPath` are present + + +### Tests for vaultAddr + +1. Verify `vaultAddr` is used (happy case) + * The baseline fo this test is all the previous test are using this flag with a known-to-work value that matches what our docker-compose environment sets up and is **not the default**. +1. Verify initialization and operation success when `vaultAddr` is missing `skipVerify` is `true` + * Start a vault instance using a self-signed HTTPS certificate. + * Component configuration lacks `vaultAddr` and defaults to address `https://127.0.0.1:8200` + * Due to `skipVerify` the component accepts the self-signed certificate +1. Verify initialization success but operation failure when `vaultAddr` is missing `skipVerify` is `false` + * Start a vault instance using a self-signed HTTPS certificate. + * Component configuration lacks `vaultAddr` and defaults to address `https://127.0.0.1:8200` + * Since `skipVerify` is disable the component requires a valid TLS certificate and refuses to connect to our vault instance, failing requests. +1. Verify `vaultAddr` is used when it points to a non-std port + * Start a vault instance in dev-mode (HTTP) but listening on a non-std port + * Modify component configuration to use this non-std port + * Ensure component initialization success and successful retrieval of secrets +1. Verify successful initialization but secret retrieval failure when `vaultAddr` points to an address not served by a Vault + * Start a vault instance in dev-mode (HTTP) listening on std port + * Modify component configuration to use a distinct (non-std) port + * Ensure component initialization success but secret retrieval failure + + +### Tests for enginePath + +1. Verify that setting `enginePath` to an explicit default value works +1. Verify that setting `enginePath` to a custom value (`TestEnginePathCustomSecretsPath`) works + * Start a vault instance in dev-mode + * In the companion shell script that seeds the vault instance with secrets, + 1. Create a new **path** named `customSecretsPath` that uses the KV engine version 2 (`-version=2 kv` or `kv-v2`) + * We cannot use version 1 as the vault component lacks support for non-versioned engines. + 2. Seeds this path with a secret specific for this test (to avoid the risk of false-positive tests) + * Verify that the custom path has secrets under it using BulkList (this is a sanity check) + * Verify that the custom path-specific secret is found + + +### Tests for CA and other certificate-related parameters + +TODO: Should we add code to enforce that only one of these is provided? + +1. Verify happy-case behavior when `caPem` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false. +1. Verify happy-case behavior when `caPath` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false. +1. Verify happy-case behavior when `caCert` is set to valid CA certificate and `tlsServerName` matches the server name and `skipVerify` is false. +1. Verify successful initialization but secret retrieval failure when `caPem` is set to a valid server certificate (baseline) but `tlsServerName` does not match the server name and `skipVerify` is false. +1. Verify successful initialization but secret retrieval failure when `caPem` is set to an invalid server certificate (flag under test) despite `tlsServerName` matching the server name and `skipVerify` is false. + +1. Same as the one above but `skipVerify` is true and we should observe happy-case behavior. + +1. skipVerify + * We also tested before with the vault-generated self-signed cert while testing for `vaultAddr` + + +#### Versioning + +1. Verify success on retrieval of a past version of a secret + * Start a vault instance in dev-mode (HTTP) + * Seed vault instance with multiple versions of a single secret + * Use standard component configuration + * Ensure component initialization success + * Ensure successful retrieval of latest version of the secret + * Ensure successful retrieval of an specific version of the secret ## Out of scope +1. Verifying how vault component handles engines that do not support versioning, like KV version 1 + * Vault component only handles engines with version support (Bug?) 1. Tests verifying writing and updating a secret since secret stores do not expose this functionality. @@ -34,8 +135,24 @@ This secret store [supports the following features][features]: Under the current directory run: +```shell +GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -v vault_test.go ``` -go test -v vault_test.go + +To run an specific test run (replacing `TestVersioning` with the name of the test method): + +```shell +GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -run TestVersioning -v vault_test.go +``` + +### Docker-compose + +You might need to verify if docker-compose is doing what you think it is doing: seeding the right secrets or even booting up properly. + +Head to the directory hosting the `docker-compose-hashicorp-vault.yml` file and run: + +```shell +docker-compose -f docker-compose-hashicorp-vault.yml up --remove-orphans ``` # References: @@ -44,7 +161,10 @@ go test -v vault_test.go * [List of secret store components and their features][features] * [PR with Conformance tests for Hashicorp Vault][conformance] * [HashiCorp Vault API reference](https://www.vaultproject.io/api-docs) +* [Vault Official Docker image documentation][vault-docker] + [HashiCorp Vault Secret Store]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/hashicorp-vault/ [features]: https://docs.dapr.io/reference/components-reference/supported-secret-stores/ -[conformance]: https://github.com/dapr/components-contrib/pull/2031 \ No newline at end of file +[conformance]: https://github.com/dapr/components-contrib/pull/2031 +[vault-docker]: https://hub.docker.com/_/vault/ \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile b/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile new file mode 100644 index 000000000..548a7edfc --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile @@ -0,0 +1,48 @@ + +TARGETS = certificates/key.pem certificates/cert.pem caPem/hashicorp-vault.yml certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem + +all: $(TARGETS) + +# Create cert and key lasting 10 years, no password, no prompt for +# subject details. Also set subjectAltName so we avoid the +# "x509: certificate relies on legacy Common Name field" errors + +certificates/key.pem certificates/cert.pem: + openssl req -x509 -newkey rsa:4096 \ + -keyout certificates/key.pem \ + -out certificates/cert.pem \ + -sha256 -days 3650 \ + -nodes \ + -addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \ + -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" + chmod -v 644 certificates/key.pem certificates/cert.pem + +# We use this for negative tests that ensure we reject connecting to +# a server using a distinct Certificate Authority -- despite the server certificate +# having all the right identifiers +certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem: + openssl req -x509 -newkey rsa:4096 \ + -keyout certificates/incorrect-ca-key.pem \ + -out certificates/incorrect-ca-cert.pem \ + -sha256 -days 3650 \ + -nodes \ + -addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \ + -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" + chmod -v 644 certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem + + +caPem/hashicorp-vault.yml: caPem/hashicorp-vault.yml.template certificates/cert.pem + set -e; \ + echo "#\n# THIS FILE IS AUTO-GENERATED - DO NOT EDIT\n#\n\n" > $@.tmp; \ + cat caPem/hashicorp-vault.yml.template >> $@.tmp;\ + sed 's/^/ /' certificates/cert.pem >> $@.tmp; \ + mv -f $@.tmp $@ + +# %: .tmp.% +# mv $< $@ + +clean: + rm -f -v $(TARGETS) + +.PHONY: clean +.PHONY: all \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md b/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md new file mode 100644 index 000000000..708bd2bd7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md @@ -0,0 +1,26 @@ +# Certificate-related tests + +These tests are particularly tricky to setup- so a little README in case you decide to change +this in the future and things break. + +# vault, `-dev-tls` and its default port + +To make our testing easier we start vault with `-dev-tls`. We do this: +* to keep the development behavior on, +* to force vault to start with a default TLS listener with its own self-signed TLS cert. We will + use this listener for our negative tests (for `skipValidation` and `tlsServerName`). + +To keep the rest of the test setup consistent and similar to other tests, we move this listener to a non-default port. + + +# Using and generating our very own certificate and key + +Besides `-dev-tls`, we also instruct vault to use a configuration that defines another listener using `-config /vault/config/vault_server.hcl`. This listener, defined in the `config/vault_server.hcl` is configured use a certificate-key pair we generated ourselves. It also binds this listener to the default vault port - to make the keep some sort of consistency in the test setup. + +We use this certificate we generated to assist with the validation of `caPem`, `caCert`, `caPath`, `skipValidate` and `tlsServerName` flags. All of these refer to the same certificate. Testing `caPem` is a bit special in that it needs the certificate inlined in the component YAML file. + +A Makefile is included here in order to document and to ease re-generation of the certificate and keys. It will also re-generate the `caPem`-dependent component YAML, so one does not have to remember updating it whenever the certificate is updated or regenerated. + +# Misc. references + +For how to configure the vault docker image we are using check https://hub.docker.com/_/vault/ \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/hashicorp-vault.yml new file mode 100644 index 000000000..8b734f73f --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCert/hashicorp-vault.yml @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-badCaCert + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caCert + value: components/caFamily/certificates/incorrect-ca-cert.pem # <<<<< We should fail authentication \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/hashicorp-vault.yml new file mode 100644 index 000000000..480d33284 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badCaCertAndSkipVerify/hashicorp-vault.yml @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-badCaCertAndSkipVerify + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: true # <<< flag under test + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caCert + value: components/caFamily/certificates/incorrect-ca-cert.pem # <<<<< We would fail authentication if it wasn't for skipVerify \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/hashicorp-vault.yml new file mode 100644 index 000000000..b366f7047 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/badTlsServerName/hashicorp-vault.yml @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-badTlsServerName + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: badTlsServerName # <<<<< Ooops, this won't match our cert. + - name: caCert + value: components/caFamily/certificates/cert.pem \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/hashicorp-vault.yml new file mode 100644 index 000000000..50c53eec2 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caCert/hashicorp-vault.yml @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-caCert + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caCert + value: components/caFamily/certificates/cert.pem \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/hashicorp-vault.yml new file mode 100644 index 000000000..5d2e51e81 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPath/hashicorp-vault.yml @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-caPath + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caPath + value: components/caFamily/certificates/ \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..50f41bee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/docker-compose-hashicorp-vault.yml @@ -0,0 +1,46 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + # Move vault's dev-mode self-signed TLS listener to another port so we can use the default one for + # our own listener with our own self-signed certificate. + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:7200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + volumes: + - ../vaultConfig:/vault/config/:ro + - ../certificates:/certificates:ro + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls -config /vault/config/vault_server.hcl + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + # Force the server to use our own certificate + VAULT_SKIP_VERIFY: 'false' + VAULT_CACERT: /certificates/cert.pem + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + - ../certificates:/certificates:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml new file mode 100644 index 000000000..9f9884e43 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml @@ -0,0 +1,59 @@ +# +# THIS FILE IS AUTO-GENERATED - DO NOT EDIT +# + + +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-caPem + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caPem + value: |- + -----BEGIN CERTIFICATE----- + MIIF4TCCA8mgAwIBAgIUQz0IMcZaa13YeKVjvz8ESiNCEJgwDQYJKoZIhvcNAQEL + BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 + ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD + DAt3d3cuZGFwci5pbzAeFw0yMjExMjUwNDA4NTBaFw0zMjExMjIwNDA4NTBaMGkx + CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw + EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 + LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQxCUMQAfW + RDvmpCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qG + w4JzbHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7g + cbmXrMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw + 5160nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlks + GijEVyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrd + pPnkweg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21 + XadkKErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+Wyd + zZQQeORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZ + zReChaiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiG + roVdmA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxT + IM2tNdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABo4GAMH4wHQYDVR0OBBYEFH/Z + KI7WpyDBM3UZE4sFYp/Rt6WuMB8GA1UdIwQYMBaAFH/ZKI7WpyDBM3UZE4sFYp/R + t6WuMA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 + gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAKvq+GzTZVePm3Cg + TRgT9tL0IojzBwEVulQYM1zoBPS9d/djwIznfA5IMJDwZF50uhCOwZqmHUn4GJPB + ClkYmxjQlcwfYJjiU4sVPu7zNI/bfm7wZnJLbyUNYnshuBRQ6eianwqEo+ZeZQQd + 4fM9QyfYyvW2YanPSQLOtvE6nXZzkzpVMB1H+wp6klAQ6sThHqGVpGTeNxUBaVeV + dN9vBzIdRSJ0PlTmjCiBykB2HqLEMg9ZXKBHXgciI6APiSd6bd40KNKy8eoayFPQ + rx4tdxd8kbIMRyJG4puSEKAVDaUcFqgNXOFctS3d7JX9EGKGm+aWvd8CTEOtAay9 + VMb1f6mFmMPuGOrK4JQBVOriLVBpHT9QlOIWlj9CuaycHiPfU9p3A1qL72etFdNA + 1pQ44QYjiBVxpyQvLO1DGm/HrnShWPoyBRaT2lQbMUudqeQMkQQQXRDBK4L3CIwP + pBNg/S5rJAdyAZrpCtjK896bGscCplKI6/Io0g2vOcdLrtwAn23ocshL6PWndue8 + k6XUS1LFLKz/cgRzzk93yD5VMYkYwo0hfHdpsF9AELl6DHsILEvkAYmR8zJcz/o8 + hpsTwp3eNexA//gED4f4qWoTbnr1ofFToloQqC/nWhtNaO0BNClyJH8cYcVNQLFX + LFXkjVxkrXK8v2vNPR2KvyXleKFk + -----END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml.template b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml.template new file mode 100644 index 000000000..2e41d366f --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml.template @@ -0,0 +1,20 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestCaFamilyOfFields-caPem + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "https://127.0.0.1:8200" + # Enforce TLS verification because this test is all about this + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: tlsServerName + value: hashicorp_vault + - name: caPem + value: |- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem new file mode 100644 index 000000000..b6d963737 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF4TCCA8mgAwIBAgIUQz0IMcZaa13YeKVjvz8ESiNCEJgwDQYJKoZIhvcNAQEL +BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 +ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD +DAt3d3cuZGFwci5pbzAeFw0yMjExMjUwNDA4NTBaFw0zMjExMjIwNDA4NTBaMGkx +CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw +EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 +LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQxCUMQAfW +RDvmpCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qG +w4JzbHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7g +cbmXrMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw +5160nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlks +GijEVyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrd +pPnkweg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21 +XadkKErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+Wyd +zZQQeORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZ +zReChaiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiG +roVdmA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxT +IM2tNdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABo4GAMH4wHQYDVR0OBBYEFH/Z +KI7WpyDBM3UZE4sFYp/Rt6WuMB8GA1UdIwQYMBaAFH/ZKI7WpyDBM3UZE4sFYp/R +t6WuMA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 +gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAKvq+GzTZVePm3Cg +TRgT9tL0IojzBwEVulQYM1zoBPS9d/djwIznfA5IMJDwZF50uhCOwZqmHUn4GJPB +ClkYmxjQlcwfYJjiU4sVPu7zNI/bfm7wZnJLbyUNYnshuBRQ6eianwqEo+ZeZQQd +4fM9QyfYyvW2YanPSQLOtvE6nXZzkzpVMB1H+wp6klAQ6sThHqGVpGTeNxUBaVeV +dN9vBzIdRSJ0PlTmjCiBykB2HqLEMg9ZXKBHXgciI6APiSd6bd40KNKy8eoayFPQ +rx4tdxd8kbIMRyJG4puSEKAVDaUcFqgNXOFctS3d7JX9EGKGm+aWvd8CTEOtAay9 +VMb1f6mFmMPuGOrK4JQBVOriLVBpHT9QlOIWlj9CuaycHiPfU9p3A1qL72etFdNA +1pQ44QYjiBVxpyQvLO1DGm/HrnShWPoyBRaT2lQbMUudqeQMkQQQXRDBK4L3CIwP +pBNg/S5rJAdyAZrpCtjK896bGscCplKI6/Io0g2vOcdLrtwAn23ocshL6PWndue8 +k6XUS1LFLKz/cgRzzk93yD5VMYkYwo0hfHdpsF9AELl6DHsILEvkAYmR8zJcz/o8 +hpsTwp3eNexA//gED4f4qWoTbnr1ofFToloQqC/nWhtNaO0BNClyJH8cYcVNQLFX +LFXkjVxkrXK8v2vNPR2KvyXleKFk +-----END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem new file mode 100644 index 000000000..1bdae2e7a --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF4TCCA8mgAwIBAgIUSrQ0syOfHO5v4Jl7gqdachXf1o8wDQYJKoZIhvcNAQEL +BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 +ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD +DAt3d3cuZGFwci5pbzAeFw0yMjExMjUxOTQ0MDJaFw0zMjExMjIxOTQ0MDJaMGkx +CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw +EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 +LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDCdxTPbiMc +Gx7l/6cBI8nuvrX0AA+OZNoxNRSa/Y5LNXOdIFbMvBHgK4spQKN2RXVjLB9PZ6Tz +rNxlQNgMlF3dOVGxFVBLhjt1acDPXjeDYeCrq6lj5NnqBUJGE7Weau8KIAh1iDfp +pFT5Sa7spVwdFpVcgS/WUvB7LMIqZJgCvydMw1DMM8iE7KbuHBeGO0dkELDt1b28 +sYAB2LV1pesr4yIVeBcqDmZJhHhKyXeNi0RxYwVR+c5/AIcy4oz3AwGaj00xCSRS +tbUZYT3wtKuFWajLVaFhhWspqnEgDfGaYgRWMBhybLUBJSkTi1y6XfGPbJg5p9cr +rXuLNeqwavJqi3/ow7N6ybCC+gpZFGtotUIVe6G9Gw4puPtpL8dXRt5UGI77lUMA +cjaRTql4RZG9yiWxvkppbJohYzZj39buVVtnfK4h6fVeOsIrotjq6A07PmrC9IZG +tYyShDc0lk0ns08PuaFxUEWDFSNgPXzZh7jVXykBRqWkqsAVUhve8NYBB0GyEIJ3 +fl/Nbb0ODqQXrknvD2af9jRrd0yC3NSg3+3pW9bMLe1qA28GiisGREhIV2I7WIm8 +nDQX/sxE1WOVlL5QQP5mnkZEJJIOQoq5AT+orFquvbCUYhyqf5VVM07+H3A/C6Au +AZ0EBBzBKdF15UvPA68Nqef/OX4jCs584wIDAQABo4GAMH4wHQYDVR0OBBYEFHUA +p2sagqDSpNEfGHXLQTQPCsC6MB8GA1UdIwQYMBaAFHUAp2sagqDSpNEfGHXLQTQP +CsC6MA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 +gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAG/8gN+7C+ROZrDS +fWHYA68jwdQWqe5+5SlZ4sMEbboA7+++csptBi27oQEtCdsTMx/4eC8/Topsz1// +OcHPo+/pQQW5VWo1Ny0Nfq9TJ+CZ9NuEoizSnLvVWhEBclA7bhkGvp3cqXTa6XqH +EDSur0ltQRhs0F+zFRPuPqEIJziLv54BEnt1iM2ydv3yVi0dF9Xz8BE92pB93ONd +PnnvCjFhvZn9X2oogBgf0HaMTQDj02mm25q86NVZ5qSEBuc+NI/8l7s5ruo+HXcY +q2WqAgwnQfmYUrNqHNmB0zj0+NygZytWmPYb1GVSi+3PcgVKW08EsQ7i8MI00CCY +/J2Pb/wHcu1VSRjX3ijhcp4MDfHQmFAnRyaey/ocHdUrBiTtWzNszD5DQhMPOKGx +ksItrRDExgDkVZspqli72oFnZyF3V4NEAo/ZDk2k5o91huyc7d/sQ4mc2ghJfNCT +aMWsHbYF7oUkwvun4K8duePB0M1JZS4qXG0kmQrEfUSocS3U8AWItvVQ9H0DCbpT +pcQFBqCuaj3ehuzsExbKLKI6+VrqTXZi8ZPozyxbkWuXnXSPFdG5wn5eQrFQxGnt +jFjrzTFeo9kzp3a7fYVveR70xYF3hdtHbPRhxt18k8BZB1vLrb08v9df0LAFfcd2 +vljYnSZYxz/14hzgCxFSQq6D92/E +-----END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem new file mode 100644 index 000000000..0d0003c60 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDCdxTPbiMcGx7l +/6cBI8nuvrX0AA+OZNoxNRSa/Y5LNXOdIFbMvBHgK4spQKN2RXVjLB9PZ6TzrNxl +QNgMlF3dOVGxFVBLhjt1acDPXjeDYeCrq6lj5NnqBUJGE7Weau8KIAh1iDfppFT5 +Sa7spVwdFpVcgS/WUvB7LMIqZJgCvydMw1DMM8iE7KbuHBeGO0dkELDt1b28sYAB +2LV1pesr4yIVeBcqDmZJhHhKyXeNi0RxYwVR+c5/AIcy4oz3AwGaj00xCSRStbUZ +YT3wtKuFWajLVaFhhWspqnEgDfGaYgRWMBhybLUBJSkTi1y6XfGPbJg5p9crrXuL +NeqwavJqi3/ow7N6ybCC+gpZFGtotUIVe6G9Gw4puPtpL8dXRt5UGI77lUMAcjaR +Tql4RZG9yiWxvkppbJohYzZj39buVVtnfK4h6fVeOsIrotjq6A07PmrC9IZGtYyS +hDc0lk0ns08PuaFxUEWDFSNgPXzZh7jVXykBRqWkqsAVUhve8NYBB0GyEIJ3fl/N +bb0ODqQXrknvD2af9jRrd0yC3NSg3+3pW9bMLe1qA28GiisGREhIV2I7WIm8nDQX +/sxE1WOVlL5QQP5mnkZEJJIOQoq5AT+orFquvbCUYhyqf5VVM07+H3A/C6AuAZ0E +BBzBKdF15UvPA68Nqef/OX4jCs584wIDAQABAoICAQCm8+dY4ryf36TaX284qkou +f2rlLbwtSuaMgn7LRc6JQT2d82qx4PET3S5fX1A3NRC/8Nx8poXWclzRTSdvPV2M +lS5Ocvb5sCeR+RYAsmnEkR57JCiMS6jOom8wjLFLbZEFx1Sb2zPtkhkl4J2eK6V2 +j7HxtjOktJYjmdyk2rIrAYOzAqh2eCq5/BagrFuB8ZisDyxnNC7uNhGpBC1d8PGD +P0A+4Fg60hv9GA7SXj8WtS8wjYu+wlIHdSOdiyTs2Jbi5A6of6nAnKH7RSIRansr +RDuHPmALwqirH9p5Y58+JNKGUEpcynlnn0ixr98PXaIKuXfDYBZ6ODmt3b88cMTn +NgQ0AF9SLOqtong3roxq/fluHmD7TbX3sryBmjEUtdKJ4SwIYRbqJt6yKTn99VBJ +tSBxokz2s8/ExnnYmiOEMmf6Ri8pmszu5hy8tswvVaHY9Vgu+KhF4spfyy6tWUly +ducfmvnNqpp9f+KID73pIN0OV0Wb/2smvmBeM8AQqh7KOcBvE9Uep7sNZs/6MnuK +ZodQf4PlwiE50Z05qiYqivy74U/57Sw30nBd0m4B7gWwDKRd0dMxanv2JVQ+AEq7 +Fsue7/CqQbejG5ExspOFb5sFrQLD3MD5//TIAQCjUjEGGMEX/Su+if7viw8b2Ztg +v2yaEqLYf/nKxyjMQ3zyKQKCAQEA73YxAFgI8/hqmAwvorIvVhVAzPFRq9lYU5ol +ic8GbQjv403Qlc9mIv5VJulNHIP3jBiDbI0BGyavvZ4emwxd5F+YzUMCfN+M6brL +opL6/SeBd6clGqYVIYRPMEh5i4hXgfDHZtLEkUhoNULyo+1TtLFiLTufeQl1i3u3 +VeCLhadpg3VQMzo2ADzDDWV4gm+Zj6vdhk4ia20JZZs6+jbehi62JVcOW7wA7A1/ +UotYLNzWJ+WMfG5chLqC4FGA7p0mAz7XBXO+4TNGnoeliBohba5OIvDX2HAiOqk7 +IUzmBzq3ycTn0yQzrk51/1s99TNJ6YtFiLISmrxtpy9K5vcS7QKCAQEAz+VT4ZJV +B0JSvAuJs/OOTrdaHRG3U/39ZRZ7B/LstUYk0Mw6gNvCB/I66LFjwnv9sv8vwPDy +32fWyjt4c1mOkAWw8kSi2Z7e+/Tbkuhi2UwrIuF2Zk6nUyP0oDD03xYOryEcgxWd +JtW4eOA96BU42tApyj+9D3JJshinVD+QgTg6GlxPWqwHQAqMPqOpuEbMJBQhDlZu +dFtlYv+866hcoeJd54SZhXQqqMD/XOEL+n5CcSGOO0pt5vCAFDoT7Vws/xQ5frx/ +m1LSVu8nbLVXS37NbRRHeKV7aK3jQ6duG7iC1xccWlUKh16CQKgqWz7WEGS1b5dR +MbYxBd0Zd1TFDwKCAQEArLeNJHhbDM2y5LR1b14iMm7l7Gxqwg7kXHikdr+yHNcD +X+nydvu+6aKUfJpuGhE9bfkIYjVaBOFkhNoVrTPATUZ+ih65HqSHmNY4pqxpCEuE +YG9Ynd4JA8HQ9DxyHqhapcirqoh/a2LUdwYwyPgXFg+Thpior76Y3+B+Hhz1xZM4 +0a6+CBUGeilZbsIvp7UjB7Oo9oRI4z8kNfs/ENaerh3nFwuxuYzjBV++5CTJlqI6 +fVBegil/5eQ5Hd7rpjAHCPQ8VxxjIz++wf2I8aAXWGsOxLj+lohayADkO2Khz7kU +cx3pMCu+cwz4oxSGneM+fosLvkrijGU4mgvMdMblCQKCAQB62xID5p766DXOTJ82 +ycKaP/4v2Y1WRG2fdHaGTweVZHtTLK2SAswaOAqaAmJqxy04v1cwFPPiFBI5doWK +3SzDbamQsgDuy9UIXj34Bf6MXVfMiCKY+PgmyMPCesvqnbVVxyJ7UKWLEpeuTw4m +fYwYuxVHIP2QCEEGz0zrG5lA08J6W3zFn421ScZxKfSdIrF2zLJwL6Gcf3pd07WI +Kfl77TMDIzg6RlkDWvJNp+yVPlHzWxobbbOe2xdFXMDz7xnkL8Z+X9SlLH+Cwlex +BUUuJyQsxuQpptlUFhaMn4ARP6uKgmzN8R2Eu9QLc5V8UJjeHTWfWXOxBfLYfT2U +aHL/AoIBAQCPc8rfH3M0ZWv8edsibvOgUtJ3yG4+IiRjLEnNhK6NVZHfX9RIAmqO +csIYRhV8hjBVLwAc12a3t105JXfbYnQ9ucwsXmSKt0W+CDOCOMKCEvUv/33ePhZN +dwmyb+E9C32mb/xWipmt/t8ucNUDkX81U7tauEWjx2tQv5Db5iGmuoIkPAxbeOLc +JRNTyYzBYiG7j3nKo/6Yg69eUZibh1M0Dg6NIZ9ltmU50yB7JQBCxrJGz7VcPmJb +ute7XRuTHKHjESeTHkC5RsSAOc1cLmcu/W3qWDYZaFAo7pX3e3bWqAbatVaqSs6C +WG6Z5JfRpAOCbhDnmIuc1NxwhVyG8c3q +-----END PRIVATE KEY----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem new file mode 100644 index 000000000..239be4c7c --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDQxCUMQAfWRDvm +pCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qGw4Jz +bHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7gcbmX +rMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw5160 +nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlksGijE +VyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrdpPnk +weg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21Xadk +KErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+WydzZQQ +eORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZzReC +haiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiGroVd +mA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxTIM2t +NdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABAoICAQCThohHp9fh6kYKLmVblidk +ewRHeVcixhD8FlX7aOUcN0O4x2/VNny5Z+MFCLty1smTf7FHuoGEyhQdTMFV8Rts +xfLedYrnlI4arCQ9nehMDzXC3QQeMzl5NCgHZxtMJkTx5rrgT4R7RuJH9KhTSNXG +6kAlBQkAvGd2LimkzWOMW+0MK8LEwEd4YZkDhJvkNhJcEO4he3hdZqLeLv+QwnHH +8uF1crhBoaWXC+mav13SzvtfAsfiK0MuR8mB6PtqcsQEB8ANxH3vVG0KkikhqYJW +glmS/17zW5Ua7GEo03ylHAe4gy8ukAV3ijvzkCHriGF4KzSouBGLn1GX/g8GSsTU +Z8xjkQ7/fvL0BxngglmjQOJtqmhGbX9vBwJB7Lufdo2uv3/1+oHVDRgtGx6IldAz +ZoiZj1owoGs9wxx6EoDnh4L51u/Kg18yjk7VhOU1TLo+bO97pHcEV3T20Vk5ZdPY +xJ4YSBtaX9RhvEPDK+gZur2tLO0i4B1j5JrqHg+w9ROj2jeYtDP9Ji7TiwJa6crw +TzSOZq+5Bbdc3LzAmG/1plLbJquusi0bi+GZoS+Cadpv0pAefGxsa8TW+0fDKfxc +xkRW50Dh3bSv7VCuEyqgGpU2Kqkz0heYa1xCuzYUDtphelBS2Q92gbS2G3nB6zF8 +r/HDS3fE68SSo1hdJvpTAQKCAQEA9Pv8I8ZDHfSiKPUcOQWDjv+t7XkoWqa71Nkl +B+exmL3MkmzPV7AwYv8mJwdgsildQl92/JE8khNtetLfbmr+AkSYuHi8H96NFMfM +feQsv16noC2vjH2wHIsR1YcZlvGHK0tK05s7PZxLVWcoHAqzRw0tV/1VdcHq54t/ +QfrqQFdrQ4G+K/iYyT3MqErWdk566JVQbA2HZxhbau0Dm8V2lx9+5FmWo01GNQ2d +ZyigSUOWnxYWz4tvA9BQvGZ3NKRp6+vgb6zIcFuSL66bwtc3xi6pJm5yKMQR9TKm +fypq54wUvkYS098C/MSBDxy/mPlzFW4YZb0//n3D2HglOgRNsQKCAQEA2idAu3GH ++m6skYX5efTBw3Rz3wv+iopo8K/8ToYETbRdtJV1dLXcR2W4b9ebc+IkIkDOicgO +4P2eai/CSCpoL+/fI0wd2eyfT6oACQMKoz0lgY39gg5/lnNbjrZuwgH2o+epFi5I +YhZgaXT6/DhuM8ROx0TViqGyWEWz7hgw+fY3WpnmPQqO/83kxh4akzVJetdZzkLc +XKJtT0aW8MJ+g4TQUE1j3GzBTN3gPOKVIHbqw4+I39ytwSo5CPO4MGOJRSW7mAOH +YR8fNIhZuWIiXi0RfrgSFGHwRIPXSZhWCMlwfOSmuuJcvM3qkbw1n+SyZVin3Lm3 +hv9yWrYgch8XewKCAQB9a8RaTFZwL54VeedJChmgTCWvPif6wQHIpqLeuS+jEwh4 +rlw4eGtNQ3M06AIJNEQahuVTyMdJwch66RqaXQxN/PBzANzPNBDmYqO+j+KY1sza +pIkLVA2lj01CFDh1npGlCJb2XrKliC7JOla+hHvkFErykS//aZfpkvFDxkHHTvoL +RZEm0c7muEzem/HP/73M9SSHLSX1EfM7erwuM5nTJLzCC1ujnxwibSX4ekQVPhUO +vTBQcQIU4cFzssG0obfYoJn2km7LlxXwc2QrDCPxwlG26zRmynqnHZc/42d3w6+a ++iUJc1MENVYddopgttTEU+kJrSnmEF0Dpf7pBOsBAoIBAFWPn6vk01g9oCFTUo2q +mXR3cBrDMYpUzuPXojWKCpYPb9Er7W1hBoxaMQRso+PHhjSJBnizpmJIFqG/KYv0 +Vfi3M+U8LVkTnUg5fNoL/1gW22b8sbkYxqHTjM1kb/xXmMygR4kTjgAqlpXF88qI +t3BGRj+Rl89PrAtDC1cO1eaz0vIN+mdmhL9/mYK6u+GQvMkZPXfQcW1Dp2u4W+sB +3Wzn4mwcblY9sXLcct5uX97jxR/+Y8ipXNyuGsCQFmWkJGqiafktKSPGeQ65i7dR +7fjR5FK3DyA/aWT18LJEtTmtCBlz9JDHx2elu6J9FusnX3CwXOYNURX5inhZhlA8 +MZECggEBAOo4fYcU+75WtZrzS49EBTYoRRHvihHcZwQ8P/J+pP8yuoD+bGbXyciS +5OV1yLEoScbzARa9jDvQhYSPyQV6QQcsCT45spIeHURzyYY30WhcluvE0U2BC+Sh +GslAiwA1IcDZ45hdbj9J33iZMzIroG1evnpOngUd6SwfT8da+MfhPNDnwcgy+HUG +bjOy6/1ds9saFQkKGgmUAt51hiHreCVMUbu+lNaqJRYMIPmx/zgqXhyhqMC+hh1S +GP/XqE9ylx3K769VsXS22IuhXJC5EaiSzqzyjVP4kzmCqccKBsngqKFGIwuFI25p +JpgsDDiLHGcoVG2ei6PE1GFlSixtFvI= +-----END PRIVATE KEY----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl b/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl new file mode 100644 index 000000000..4326d60bb --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl @@ -0,0 +1,15 @@ +listener "tcp" { + address = "0.0.0.0:8200" + tls_disable = "false" + tls_cert_file = "/certificates/cert.pem" + tls_key_file = "/certificates/key.pem" +} + +api_addr = "https://127.0.0.1:8201" + +#backend "file" { +# path = "/vault/file" +#} + +#default_lease_ttl = "168h" +#max_lease_ttl = "720h" diff --git a/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..83a405fb3 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml @@ -0,0 +1,37 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: http://hashicorp_vault:8200/ + VAULT_SKIP_VERIFY: 'true' + volumes: + - .:/setup:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/hashicorp-vault.yml new file mode 100644 index 000000000..d35fc0ee7 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestEnginePath-customSecretsPath + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: enginePath + value: customSecretsPath \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/setup-hashicorp-vault-secrets.sh b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/setup-hashicorp-vault-secrets.sh new file mode 100755 index 000000000..546dae349 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/setup-hashicorp-vault-secrets.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# Notice that while hashicorp supports multiple keys in a secret, +# our confirmance tests needs to go for the common demominator +# which is a secret store that only has name/value semantic. +# Hence we setup secret containing a single key with the their +# same name. + +set -eu + +MAX_ATTEMPTS=30 + +for attempt in `seq $MAX_ATTEMPTS`; do + # Test connectivity to vault server and create secrets to match + # conformance tests / contents from tests/conformance/secrets.json + if vault status && + vault secrets enable -path=customSecretsPath kv-v2 && # Enable this path with kv/version2 engine + vault kv put customSecretsPath/dapr/secretUnderCustomPath the=trick was=the path=parameter && + vault kv get customSecretsPath/dapr/secretUnderCustomPath ; + then + echo ✅ secrets set; + sleep 1; + exit 0; + else + echo "⏰ vault not available, waiting... - attempt $attempt of $MAX_ATTEMPTS"; + sleep 1; + fi +done; + +echo ❌ Failed to set secrets; +exit 1 diff --git a/tests/certification/secretstores/hashicorp/vault/components/enginePath/secret/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/enginePath/secret/hashicorp-vault.yml new file mode 100644 index 000000000..aa953d973 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/enginePath/secret/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestEnginePath-secret + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: enginePath + value: secret \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..90f3992be --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/docker-compose-hashicorp-vault.yml @@ -0,0 +1,38 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls=true + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + VAULT_SKIP_VERIFY: 'true' + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/hashicorp-vault.yml new file mode 100644 index 000000000..d60a34d05 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missing/hashicorp-vault.yml @@ -0,0 +1,19 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestVaultAddr-missing + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + # Yes, we commented out vaultAddr. + # Default value should kick in: https://127.0.0.1:8200. Notice: HTTPS (TLS) + # - name: vaultAddr + # value: "http://127.0.0.1:8200" + # Do not perform TLS verification since e are starting vault in development + # mode with a self-signed certificate + - name: skipVerify + value: true + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..90f3992be --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/docker-compose-hashicorp-vault.yml @@ -0,0 +1,38 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + # Force vault to use TLS/HTTPS in dev mode + entrypoint: vault server -dev-tls=true + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: https://hashicorp_vault:8200/ + VAULT_SKIP_VERIFY: 'true' + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/hashicorp-vault.yml new file mode 100644 index 000000000..83b5d7fdf --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/missingSkipVerifyFalse/hashicorp-vault.yml @@ -0,0 +1,19 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestVaultAddr-missingSkipVerifyFalse + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + # Yes, we commented out vaultAddr. + # Default value should kick in: https://127.0.0.1:8200. Notice: HTTPS (TLS) + # - name: vaultAddr + # value: "http://127.0.0.1:8200" + # Do not perform TLS verification since e are starting vault in development + # mode with a self-signed certificate + - name: skipVerify + value: false + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..0a8514409 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/docker-compose-hashicorp-vault.yml @@ -0,0 +1,36 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '11200:11200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:11200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: http://hashicorp_vault:11200/ + VAULT_SKIP_VERIFY: 'true' + volumes: + - ../../../../../../../../.github/infrastructure/conformance/hashicorp:/setup:ro + entrypoint: /setup/setup-hashicorp-vault-secrets.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/hashicorp-vault.yml new file mode 100644 index 000000000..f5c3d3264 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/nonStdPort/hashicorp-vault.yml @@ -0,0 +1,14 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestVaultAddr-nonStdPort + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + # Use non-standard port + - name: vaultAddr + value: "http://127.0.0.1:11200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/wrongAddress/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/wrongAddress/hashicorp-vault.yml new file mode 100644 index 000000000..5c4a548a9 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultAddr/wrongAddress/hashicorp-vault.yml @@ -0,0 +1,13 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestVaultAddr-wrongAddress + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:28234" # yeah.. let's hope no one starts a Vault here + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultKVPrefix/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultKVPrefix/hashicorp-vault.yml new file mode 100644 index 000000000..7d0b663e6 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultKVPrefix/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: vaultKVPrefix + value: alternativePrefix \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultKVUsePrefixFalse/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultKVUsePrefixFalse/hashicorp-vault.yml new file mode 100644 index 000000000..8179b6ee2 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultKVUsePrefixFalse/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: vaultKVUsePrefix + value: false \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/badVaultToken/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/badVaultToken/hashicorp-vault.yml new file mode 100644 index 000000000..34bfb0c29 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/badVaultToken/hashicorp-vault.yml @@ -0,0 +1,14 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestTokenAndTokenMountPath-badVaultToken + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it. + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken + value: "this-is-not-the-correct-vault-token-to-talk-to-our-server" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/both/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/both/hashicorp-vault.yml new file mode 100644 index 000000000..b747c743c --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/both/hashicorp-vault.yml @@ -0,0 +1,16 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestTokenAndTokenMountPath-both + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it. + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken + value: "vault-dev-root-token-id" + - name: vaultTokenMountPath + value: /tmp/vaultToken.txt \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/neither/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/neither/hashicorp-vault.yml new file mode 100644 index 000000000..08e74811f --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/neither/hashicorp-vault.yml @@ -0,0 +1,13 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestTokenAndTokenMountPath-neither + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it. + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + # no vaultToken or vaultTokenMountPath \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/hashicorp-vault.yml new file mode 100644 index 000000000..cf26809b2 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestTokenAndTokenMountPath-tokenMountPathHappyCase + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it. + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultTokenMountPath + # This is a long path but this file is in current directory ;) + value: components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt new file mode 100644 index 000000000..0fc2ab7bd --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathHappyCase/vault_token_file.txt @@ -0,0 +1 @@ +vault-dev-root-token-id \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathPointsToBrokenPath/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathPointsToBrokenPath/hashicorp-vault.yml new file mode 100644 index 000000000..9f0b65be2 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultTokenAndTokenMountPath/tokenMountPathPointsToBrokenPath/hashicorp-vault.yml @@ -0,0 +1,14 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestTokenAndTokenMountPath-tokenMountPathPointsToBrokenPath + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + ignoreErrors: true # This component will fail to load but we don't want Dapr to FATAL because of it. + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultTokenMountPath + value: /this/path/does/not/exist/vaultToken.txt \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/vaultValueTypeText/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/vaultValueTypeText/hashicorp-vault.yml new file mode 100644 index 000000000..94362ca78 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/vaultValueTypeText/hashicorp-vault.yml @@ -0,0 +1,15 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" + - name: vaultValueType + value: text # Turns Vault into a secret store with name/value semantics. \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml new file mode 100644 index 000000000..fd7620371 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml @@ -0,0 +1,37 @@ +version: '3.9' + +# Use a YAML reference to define VAULT_TOKEN and DOCKER_IMAGE only once +x-common-values: + # This should match tests/config/secrestore/hashicorp/vault/hashicorp-vault.yaml + # This should match .github/infrastructure/conformance/hashicorp/vault_token_file.txt + vault_token: &VAULT_TOKEN "vault-dev-root-token-id" + # Reuse the same docker image to save on resources and because the base vault image + # has everything we need for seeding the initial key values too. + vault_docker_image: &VAULT_DOCKER_IMAGE vault:1.12.1 + +services: + hashicorp_vault: + image: *VAULT_DOCKER_IMAGE + ports: + - '8200:8200' + cap_add: + - IPC_LOCK + environment: + VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" + VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN + + + # We define a aux. service to seed the expected conformance secrets to vault + seed_conformance_secrets: + image: *VAULT_DOCKER_IMAGE + depends_on: + - hashicorp_vault + environment: + VAULT_TOKEN : *VAULT_TOKEN + # We are using HTTPS + VAULT_ADDR: http://hashicorp_vault:8200/ + VAULT_SKIP_VERIFY: 'true' + volumes: + - .:/setup:ro + entrypoint: /setup/seed-secret-with-multiple-versions.sh + diff --git a/tests/certification/secretstores/hashicorp/vault/components/versioning/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/versioning/hashicorp-vault.yml new file mode 100644 index 000000000..74ce6249a --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/versioning/hashicorp-vault.yml @@ -0,0 +1,13 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-hashicorp-vault-TestVersioning + namespace: default +spec: + type: secretstores.hashicorp.vault + version: v1 + metadata: + - name: vaultAddr + value: "http://127.0.0.1:8200" + - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. + value: "vault-dev-root-token-id" \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/versioning/seed-secret-with-multiple-versions.sh b/tests/certification/secretstores/hashicorp/vault/components/versioning/seed-secret-with-multiple-versions.sh new file mode 100755 index 000000000..50a6f280d --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/components/versioning/seed-secret-with-multiple-versions.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# Notice that while hashicorp supports multiple keys in a secret, +# our confirmance tests needs to go for the common demominator +# which is a secret store that only has name/value semantic. +# Hence we setup secret containing a single key with the their +# same name. + +set -eu + +MAX_ATTEMPTS=30 + +for attempt in `seq $MAX_ATTEMPTS`; do + # Test connectivity to vault server and create secrets to match + # conformance tests / contents from tests/conformance/secrets.json + if vault status && + vault kv put secret/dapr/secretUnderTest versionedKey=initialVersion && + vault kv put secret/dapr/secretUnderTest versionedKey=secondVersion && + vault kv put secret/dapr/secretUnderTest versionedKey=v3 && + vault kv put secret/dapr/secretUnderTest versionedKey=v4 && + vault kv put secret/dapr/secretUnderTest versionedKey=latestValue && + vault kv get secret/dapr/secretUnderTest ; + then + echo ✅ secrets set; + sleep 1; + exit 0; + else + echo "⏰ vault not available, waiting... - attempt $attempt of $MAX_ATTEMPTS"; + sleep 1; + fi +done; + +echo ❌ Failed to set secrets; +exit 1 diff --git a/tests/certification/secretstores/hashicorp/vault/vault_test.go b/tests/certification/secretstores/hashicorp/vault/vault_test.go index 148416a28..338e32d7b 100644 --- a/tests/certification/secretstores/hashicorp/vault/vault_test.go +++ b/tests/certification/secretstores/hashicorp/vault/vault_test.go @@ -14,8 +14,14 @@ limitations under the License. package vault_test import ( + "bufio" + "bytes" "context" "fmt" + "io" + "os" + "path/filepath" + "strings" "testing" "time" @@ -37,11 +43,10 @@ import ( ) const ( - sidecarName = "hashicorp-vault-sidecar" - dockerComposeClusterYAML = "../../../../../.github/infrastructure/docker-compose-hashicorp-vault.yml" - dockerComposeProjectName = "hashicorp-vault" - secretStoreComponentPath = "./components/default" - secretStoreName = "my-hashicorp-vault" // as set in the component YAML + sidecarName = "hashicorp-vault-sidecar" + defaultDockerComposeClusterYAML = "../../../../../.github/infrastructure/docker-compose-hashicorp-vault.yml" + dockerComposeProjectName = "hashicorp-vault" + // secretStoreName = "my-hashicorp-vault" // as set in the component YAML networkInstabilityTime = 1 * time.Minute waitAfterInstabilityTime = networkInstabilityTime / 4 @@ -49,47 +54,25 @@ const ( ) func TestBasicSecretRetrieval(t *testing.T) { - ports, err := dapr_testing.GetFreePorts(2) - assert.NoError(t, err) + const ( + secretStoreComponentPath = "./components/default" + secretStoreName = "my-hashicorp-vault" // as set in the component YAML + ) - currentGrpcPort := ports[0] - currentHttpPort := ports[1] + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) - testGetKnownSecret := func(ctx flow.Context) error { - client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer client.Close() + // This test reuses the HashiCorp Vault's conformance test resources created using + // .github/infrastructure/docker-compose-hashicorp-vault.yml, + // so it reuses the tests/conformance/secretstores/secretstores.go test secrets. + testGetKnownSecret := testKeyValuesInSecret(currentGrpcPort, secretStoreName, + "secondsecret", map[string]string{ + "secondsecret": "efgh", + }) - emptyOpt := map[string]string{} - - // This test reuses the HashiCorp Vault's conformance test resources created using - // .github/infrastructure/docker-compose-hashicorp-vault.yml, - // so it reuses the tests/conformance/secretstores/secretstores.go test secrets. - res, err := client.GetSecret(ctx, secretStoreName, "secondsecret", emptyOpt) - assert.NoError(t, err) - assert.Equal(t, "efgh", res["secondsecret"]) - return nil - } - - testGetMissingSecret := func(ctx flow.Context) error { - client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer client.Close() - - emptyOpt := map[string]string{} - - _, getErr := client.GetSecret(ctx, secretStoreName, "this_secret_is_not_there", emptyOpt) - assert.Error(t, getErr) - - return nil - } + testGetMissingSecret := testSecretIsNotFound(currentGrpcPort, secretStoreName, "this_secret_is_not_there") flow.New(t, "Test component is up and we can retrieve some secrets"). - Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step(dockercompose.Run(dockerComposeProjectName, defaultDockerComposeClusterYAML)). Step("Waiting for component to start...", flow.Sleep(5*time.Second)). Step(sidecar.Run(sidecarName, embedded.WithoutApp(), @@ -99,47 +82,28 @@ func TestBasicSecretRetrieval(t *testing.T) { componentRuntimeOptions(), )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("Verify component is registered", testComponentFound(t, secretStoreName, currentGrpcPort)). + Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Run basic secret retrieval test", testGetKnownSecret). Step("Test retrieval of secret that does not exist", testGetMissingSecret). Step("Interrupt network for 1 minute", network.InterruptNetwork(networkInstabilityTime, nil, nil, servicePortToInterrupt)). Step("Wait for component to recover", flow.Sleep(waitAfterInstabilityTime)). Step("Run basic test again to verify reconnection occurred", testGetKnownSecret). - Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, defaultDockerComposeClusterYAML)). Run() } func TestMultipleKVRetrieval(t *testing.T) { - ports, err := dapr_testing.GetFreePorts(2) - assert.NoError(t, err) + const ( + secretStoreComponentPath = "./components/default" + secretStoreName = "my-hashicorp-vault" // as set in the component YAML + ) - currentGrpcPort := ports[0] - currentHttpPort := ports[1] - - testGetMultipleKeyValuesFromSecret := func(ctx flow.Context) error { - client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer client.Close() - - emptyOpt := map[string]string{} - - // This test reuses the HashiCorp Vault's conformance test resources created using - // .github/infrastructure/docker-compose-hashicorp-vault.yml, - // so it reuses the tests/conformance/secretstores/secretstores.go test secrets. - res, err := client.GetSecret(ctx, secretStoreName, "multiplekeyvaluessecret", emptyOpt) - assert.NoError(t, err) - assert.NotNil(t, res) - assert.Equal(t, "1", res["first"]) - assert.Equal(t, "2", res["second"]) - assert.Equal(t, "3", res["third"]) - return nil - } + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) flow.New(t, "Test retrieving multiple key values from a secret"). - Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step(dockercompose.Run(dockerComposeProjectName, defaultDockerComposeClusterYAML)). Step("Waiting for component to start...", flow.Sleep(5*time.Second)). Step(sidecar.Run(sidecarName, embedded.WithoutApp(), @@ -149,44 +113,356 @@ func TestMultipleKVRetrieval(t *testing.T) { componentRuntimeOptions(), )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("Verify component is registered", testComponentFound(t, secretStoreName, currentGrpcPort)). + Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Verify component has support for multiple key-values under the same secret", - testComponentHasFeature(t, secretStoreName, string(secretstores.FeatureMultipleKeyValuesPerSecret), currentGrpcPort)). - Step("Test retrieval of a secret with multiple key-values", testGetMultipleKeyValuesFromSecret). + testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). + Step("Test retrieval of a secret with multiple key-values", + testKeyValuesInSecret(currentGrpcPort, secretStoreName, "multiplekeyvaluessecret", map[string]string{ + "first": "1", + "second": "2", + "third": "3", + })). + Step("Test secret registered under a non-default vaultKVPrefix cannot be found", + testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretUnderAlternativePrefix")). + Step("Test secret registered with no prefix cannot be found", testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretWithNoPrefix")). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Run() +} + +func TestVaultKVPrefix(t *testing.T) { + const ( + secretStoreComponentPath = "./components/vaultKVPrefix" + secretStoreName = "my-hashicorp-vault" // as set in the component YAML + ) + + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) + + flow.New(t, "Test setting a non-default vaultKVPrefix value"). + Step(dockercompose.Run(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(secretStoreComponentPath), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify component has support for multiple key-values under the same secret", + testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). + Step("Test retrieval of a secret under a non-default vaultKVPrefix", + testKeyValuesInSecret(currentGrpcPort, secretStoreName, "secretUnderAlternativePrefix", map[string]string{ + "altPrefixKey": "altPrefixValue", + })). + Step("Test secret registered with no prefix cannot be found", testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretWithNoPrefix")). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Run() +} + +func TestVaultKVUsePrefixFalse(t *testing.T) { + const ( + secretStoreComponentPath = "./components/vaultKVUsePrefixFalse" + secretStoreName = "my-hashicorp-vault" // as set in the component YAML + ) + + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) + + flow.New(t, "Test using an empty vaultKVPrefix value"). + Step(dockercompose.Run(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(secretStoreComponentPath), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify component has support for multiple key-values under the same secret", + testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). + Step("Test retrieval of a secret registered with no prefix and assuming vaultKVUsePrefix=false", + testKeyValuesInSecret(currentGrpcPort, secretStoreName, "secretWithNoPrefix", map[string]string{ + "noPrefixKey": "noProblem", + })). + Step("Test secret registered under the default vaultKVPrefix cannot be found", + testSecretIsNotFound(currentGrpcPort, secretStoreName, "multiplekeyvaluessecret")). + Step("Test secret registered under a non-default vaultKVPrefix cannot be found", + testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretUnderAlternativePrefix")). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Run() +} + +func TestVaultValueTypeText(t *testing.T) { + const ( + secretStoreComponentPath = "./components/vaultValueTypeText" + secretStoreName = "my-hashicorp-vault" // as set in the component YAML + ) + + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) + + flow.New(t, "Test setting vaultValueType=text should cause it to behave with single-value semantics"). + Step(dockercompose.Run(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(secretStoreComponentPath), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify component DOES NOT support multiple key-values under the same secret", + testComponentDoesNotHaveFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). + Step("Test secret store presents name/value semantics for secrets", + // result has a single key with tha same name as the secret and a JSON-like content + testKeyValuesInSecret(currentGrpcPort, secretStoreName, "secondsecret", map[string]string{ + "secondsecret": "{\"secondsecret\":\"efgh\"}", + })). + Step("Test secret registered under a non-default vaultKVPrefix cannot be found", + testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretUnderAlternativePrefix")). + Step("Test secret registered with no prefix cannot be found", testSecretIsNotFound(currentGrpcPort, secretStoreName, "secretWithNoPrefix")). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, defaultDockerComposeClusterYAML)). + Run() +} + +func TestTokenAndTokenMountPath(t *testing.T) { + fs := NewFlowSettings(t) + fs.secretStoreComponentPathBase = "./components/vaultTokenAndTokenMountPath/" + fs.componentNamePrefix = "my-hashicorp-vault-TestTokenAndTokenMountPath-" + + createNegativeTestFlow(fs, + "Verify component initialization failure when BOTH vaultToken and vaultTokenMountPath are present", + "both", + "token mount path and token both set") + + createNegativeTestFlow(fs, + "Verify component initialization failure when NEITHER vaultToken nor vaultTokenMountPath are present", + "neither", + "token mount path and token not set") + + createNegativeTestFlow(fs, + "Verify component initialization failure when vaultTokenPath points to a non-existing file", + "tokenMountPathPointsToBrokenPath", + "couldn't read vault token from mount path") + + createInitSucceedsButComponentFailsFlow(fs, + "Verify failure when vaultToken value does not match our servers's value", + "badVaultToken", + false) + + createPositiveTestFlow(fs, + "Verify success when vaultTokenPath points to an existing file matching the configured secret we have for our secret seeder", + "tokenMountPathHappyCase", + false) +} + +func TestVaultAddr(t *testing.T) { + fs := NewFlowSettings(t) + fs.secretStoreComponentPathBase = "./components/vaultAddr/" + fs.componentNamePrefix = "my-hashicorp-vault-TestVaultAddr-" + + createInitSucceedsButComponentFailsFlow(fs, + "Verify initialization success but use failure when vaultAddr does not point to a valid vault server address", + "wrongAddress", + false) + + createPositiveTestFlow(fs, + "Verify success when vaultAddr is missing and skipVerify is true and vault is using a self-signed certificate", + "missing", + true) + + createPositiveTestFlow(fs, + "Verify success when vaultAddr points to a non-standard port", + "nonStdPort", + true) + + createInitSucceedsButComponentFailsFlow(fs, + "Verify initialization success but use failure when vaultAddr is missing and skipVerify is true and vault is using its own self-signed certificate", + "missingSkipVerifyFalse", + true) +} + +func TestEnginePathCustomSecretsPath(t *testing.T) { + const ( + secretStoreComponentPathBase = "./components/enginePath/" + componentNamePrefix = "my-hashicorp-vault-TestEnginePath-" + componentSuffix = "customSecretsPath" + componentName = componentNamePrefix + componentSuffix + ) + + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) + + componentPath := filepath.Join(secretStoreComponentPathBase, componentSuffix) + dockerComposeClusterYAML := filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + + flow.New(t, "Verify success when we set enginePath to a non-std value"). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHttpPort), + // Dapr log-level debug? + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("✅Verify component is registered", testComponentFound(componentName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("Verify that the custom path has secrets under it", testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort, componentName)). + Step("Verify that the custom path-specific secret is found", testKeyValuesInSecret(currentGrpcPort, componentName, + "secretUnderCustomPath", map[string]string{ + "the": "trick", + "was": "the", + "path": "parameter", + })). Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). Run() } -func testComponentFound(t *testing.T, targetComponentName string, currentGrpcPort int) flow.Runnable { +func TestEnginePathSecrets(t *testing.T) { + fs := NewFlowSettings(t) + fs.secretStoreComponentPathBase = "./components/enginePath/" + fs.componentNamePrefix = "my-hashicorp-vault-TestEnginePath-" + + createPositiveTestFlow(fs, + "Verify success when vaultEngine explicitly uses the secrets engine", + "secret", false) +} + +func TestCaFamilyOfFields(t *testing.T) { + fs := NewFlowSettings(t) + fs.secretStoreComponentPathBase = "./components/caFamily/" + fs.componentNamePrefix = "my-hashicorp-vault-TestCaFamilyOfFields-" + + createPositiveTestFlow(fs, + "Verify success when using a caCert to talk to vault with tlsServerName and enforceVerify", + "caCert", true) + + createPositiveTestFlow(fs, + "Verify success when using a caPath to talk to vault with tlsServerName and enforceVerify", + "caCert", true) + + createPositiveTestFlow(fs, + "Verify success when using a caPem to talk to vault with tlsServerName and enforceVerify", + "caPem", true) + + createInitSucceedsButComponentFailsFlow(fs, + "Verify successful initialization but secret retrieval failure when `caPem` is set to a valid server certificate (baseline) but `tlsServerName` does not match the server name", + "badTlsServerName", true) + + createInitSucceedsButComponentFailsFlow(fs, + "Verify successful initialization but secret retrieval failure when `caPem` is set to an invalid server certificate (flag under test) despite `tlsServerName` matching the server name ", + "badCaCert", true) + + createPositiveTestFlow(fs, + "Verify success when using a caPem is invalid but skipVerify is on", + "badCaCertAndSkipVerify", true) +} + +func TestVersioning(t *testing.T) { + const ( + componentPath = "./components/versioning/" + componentName = "my-hashicorp-vault-TestVersioning" + ) + dockerComposeClusterYAML := filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + + currentGrpcPort, currentHttpPort := GetCurrentGRPCAndHTTPPort(t) + + flow.New(t, "Verify success on retrieval of a past version of a secret"). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHttpPort), + // Dapr log-level debug? + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("✅Verify component is registered", testComponentFound(componentName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("Verify that we can list secrets", testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort, componentName)). + Step("Verify that the latest version of the secret is there", testKeyValuesInSecret(currentGrpcPort, componentName, + "secretUnderTest", map[string]string{ + "versionedKey": "latestValue", + })). + Step("Verify that a past version of the secret is there", testKeyValuesInSecret(currentGrpcPort, componentName, + "secretUnderTest", map[string]string{ + "versionedKey": "secondVersion", + }, "2")). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} + +// +// Aux. functions for testing key presence +// + +func testKeyValuesInSecret(currentGrpcPort int, secretStoreName string, secretName string, keyValueMap map[string]string, maybeVersionID ...string) flow.Runnable { return func(ctx flow.Context) error { - client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) if err != nil { panic(err) } - defer client.Close() + defer daprClient.Close() - clientCtx := context.Background() - - resp, err := client.GrpcClient().GetMetadata(clientCtx, &empty.Empty{}) - assert.NoError(t, err) - assert.NotNil(t, resp) - assert.NotNil(t, resp.GetRegisteredComponents()) - - // Find the component - componentFound := false - for _, component := range resp.GetRegisteredComponents() { - if component.GetName() == targetComponentName { - componentFound = true - break - } + metadata := map[string]string{} + if len(maybeVersionID) > 0 { + metadata["version_id"] = maybeVersionID[0] } - assert.True(t, componentFound) + + res, err := daprClient.GetSecret(ctx, secretStoreName, secretName, metadata) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, res) + + for key, valueExpected := range keyValueMap { + valueInSecret, exists := res[key] + assert.True(ctx.T, exists, "expected key not found in key") + assert.Equal(ctx.T, valueExpected, valueInSecret) + } + return nil + } +} + +func testSecretIsNotFound(currentGrpcPort int, secretStoreName string, secretName string) flow.Runnable { + return func(ctx flow.Context) error { + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer daprClient.Close() + + emptyOpt := map[string]string{} + + _, err = daprClient.GetSecret(ctx, secretStoreName, secretName, emptyOpt) + assert.Error(ctx.T, err) return nil } } -func testComponentHasFeature(t *testing.T, targetComponentName string, targetCapability string, currentGrpcPort int) flow.Runnable { +func testDefaultSecretIsFound(currentGrpcPort int, secretStoreName string) flow.Runnable { + return testKeyValuesInSecret(currentGrpcPort, secretStoreName, "multiplekeyvaluessecret", map[string]string{ + "first": "1", + "second": "2", + "third": "3", + }) +} + +func testComponentIsNotWorking(targetComponentName string, currentGrpcPort int) flow.Runnable { + return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") +} + +func testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort int, secretStoreName string) flow.Runnable { return func(ctx flow.Context) error { client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) if err != nil { @@ -194,37 +470,108 @@ func testComponentHasFeature(t *testing.T, targetComponentName string, targetCap } defer client.Close() - clientCtx := context.Background() + emptyOpt := map[string]string{} - resp, err := client.GrpcClient().GetMetadata(clientCtx, &empty.Empty{}) - assert.NoError(t, err) - assert.NotNil(t, resp) - assert.NotNil(t, resp.GetRegisteredComponents()) + res, err := client.GetBulkSecret(ctx, secretStoreName, emptyOpt) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, res) + assert.NotEmpty(ctx.T, res) - // Find the component - var capabilities []string = []string{} - for _, component := range resp.GetRegisteredComponents() { - if component.GetName() == targetComponentName { - capabilities = component.GetCapabilities() - break + for k, v := range res { + ctx.Logf("💡 %s", k) + for i, j := range v { + ctx.Logf("💡\t %s : %s", i, j) } } - assert.NotEmpty(t, capabilities) + return nil + } +} + +// +// Helper methods for checking component registration and availability of its features +// + +func testComponentFound(targetComponentName string, currentGrpcPort int) flow.Runnable { + return func(ctx flow.Context) error { + componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") + return nil + } +} + +// Due to https://github.com/dapr/dapr/issues/5487 we cannot perform negative tests +// for the component presence against the metadata registry. +// Instead, we turned testComponentNotFound into a simpler negative test that ensures a good key cannot be found +func testComponentNotFound(targetComponentName string, currentGrpcPort int) flow.Runnable { + // TODO(tmacam) once https://github.com/dapr/dapr/issues/5487 is fixed, uncomment the code bellow + return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") + + //return func(ctx flow.Context) error { + // // Find the component + // componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + // assert.False(ctx.T, componentFound, "Component was expected to be missing but it was found.") + // return nil + //} +} + +func testComponentDoesNotHaveFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { + return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, false) +} + +func testComponentHasFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { + return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, true) +} + +func testComponentAndFeaturePresence(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature, expectedToBeFound bool) flow.Runnable { + return func(ctx flow.Context) error { + componentFound, capabilities := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + + assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") + + targetCapabilityAsString := string(targetCapability) // Find capability capabilityFound := false for _, cap := range capabilities { - if cap == targetCapability { + if cap == targetCapabilityAsString { capabilityFound = true break } } - assert.True(t, capabilityFound) + assert.Equal(ctx.T, expectedToBeFound, capabilityFound) return nil } } +func getComponentCapabilities(ctx flow.Context, currentGrpcPort int, targetComponentName string) (found bool, capabilities []string) { + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer daprClient.Close() + + clientCtx := context.Background() + + resp, err := daprClient.GrpcClient().GetMetadata(clientCtx, &empty.Empty{}) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, resp) + assert.NotNil(ctx.T, resp.GetRegisteredComponents()) + + // Find the component + for _, component := range resp.GetRegisteredComponents() { + if component.GetName() == targetComponentName { + ctx.Logf("🩺 component found=%s", component) + return true, component.GetCapabilities() + } + } + return false, []string{} +} + +// +// Flow and test setup helpers +// + func componentRuntimeOptions() []runtime.Option { log := logger.NewLogger("dapr.components") @@ -236,3 +583,196 @@ func componentRuntimeOptions() []runtime.Option { runtime.WithSecretStores(secretStoreRegistry), } } + +func GetCurrentGRPCAndHTTPPort(t *testing.T) (int, int) { + ports, err := dapr_testing.GetFreePorts(2) + assert.NoError(t, err) + + currentGrpcPort := ports[0] + currentHttpPort := ports[1] + + return currentGrpcPort, currentHttpPort +} + +// +// Helper functions for asserting error messages during component initialization +// +// These can be exported to their own module. +// Do notice that they have side effects: using more than one in a single +// flow will cause only the latest to work. Perhaps this functionality +// (dapr.runtime log capture) could be baked into flows themselves? +// +// Also: this is not thread-safe nor concurrent safe: only one test +// can be run at a time to ensure deterministic capture of dapr.runtime output. + +type initErrorChecker func(ctx flow.Context, errorLine string) error + +func captureLogsAndCheckInitErrors(checker initErrorChecker) flow.Runnable { + // Setup log capture + logCaptor := &bytes.Buffer{} + runtimeLogger := logger.NewLogger("dapr.runtime") + runtimeLogger.SetOutput(io.MultiWriter(os.Stdout, logCaptor)) + + // Stop log capture, reset buffer just for good mesure + cleanup := func() { + logCaptor.Reset() + runtimeLogger.SetOutput(os.Stdout) + } + + grepInitErrorFromLogs := func() (string, error) { + errorMarker := []byte("INIT_COMPONENT_FAILURE") + scanner := bufio.NewScanner(logCaptor) + for scanner.Scan() { + if err := scanner.Err(); err != nil { + return "", err + } + if bytes.Contains(scanner.Bytes(), errorMarker) { + return scanner.Text(), nil + } + } + return "", scanner.Err() + } + + // Wraps the our initErrorChecker with cleanup and error-grepping logic so we only care about the + // log error + return func(ctx flow.Context) error { + defer cleanup() + + errorLine, err := grepInitErrorFromLogs() + if err != nil { + return err + } + ctx.Logf("👀 errorLine: %s", errorLine) + + return checker(ctx, errorLine) + } +} + +func assertNoInitializationErrorsForComponent(componentName string) flow.Runnable { + checker := func(ctx flow.Context, errorLine string) error { + componentFailedToInitialize := strings.Contains(errorLine, componentName) + assert.False(ctx.T, componentFailedToInitialize, + "Found component name mentioned in an component initialization error message: %s", errorLine) + + return nil + } + + return captureLogsAndCheckInitErrors(checker) +} + +func assertInitializationFailedWithErrorsForComponent(componentName string, additionalSubStringsToMatch ...string) flow.Runnable { + checker := func(ctx flow.Context, errorLine string) error { + assert.NotEmpty(ctx.T, errorLine, "Expected a component initialization error message but none found") + assert.Contains(ctx.T, errorLine, componentName, + "Expected to find component '%s' mentioned in error message but found none: %s", componentName, errorLine) + + for _, subString := range additionalSubStringsToMatch { + assert.Contains(ctx.T, errorLine, subString, + "Expected to find '%s' mentioned in error message but found none: %s", componentName, errorLine) + } + + return nil + } + + return captureLogsAndCheckInitErrors(checker) +} + +// +// Helper functions for common tests for happy case, init-but-does-not-work and fails-initialization tests +// These test re-use the same seed secrets. They aim to check how certain flags break or keep vault working +// instead of verifying some specific tha change key retrieval behavior. +// +// Those tests require a `/` structure. + +type commonFlowSettings struct { + t *testing.T + currentGrpcPort int + currentHttpPort int + secretStoreComponentPathBase string + componentNamePrefix string +} + +func NewFlowSettings(t *testing.T) *commonFlowSettings { + res := commonFlowSettings{} + res.t = t + res.currentGrpcPort, res.currentHttpPort = GetCurrentGRPCAndHTTPPort(t) + return &res +} + +func createPositiveTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + if useCustomDockerCompose { + dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + } + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("Test that the default secret is found", testDefaultSecretIsFound(fs.currentGrpcPort, componentName)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} + +func createInitSucceedsButComponentFailsFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool, initErrorCodes ...string) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + if useCustomDockerCompose { + dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + } + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("✅Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("🛑Verify component does not work", testComponentIsNotWorking(componentName, fs.currentGrpcPort)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} + +func createNegativeTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, initErrorCodes ...string) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + // TODO(tmacam) FIX https://github.com/dapr/dapr/issues/5487 + Step("🛑Verify component is NOT registered", testComponentNotFound(componentName, fs.currentGrpcPort)). + Step("Verify initialization error reported for component", assertInitializationFailedWithErrorsForComponent(componentName, initErrorCodes...)). + Step("🐞😱 Bug dependant behavior - test component is actually registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} From 385c6b79b67039ece5507ab31f796483049fd47e Mon Sep 17 00:00:00 2001 From: Bernd Verst <4535280+berndverst@users.noreply.github.com> Date: Mon, 28 Nov 2022 15:51:03 -0800 Subject: [PATCH 12/22] remove unnecessary reader close() Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> --- bindings/azure/blobstorage/blobstorage.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index 582de9878..3724a7e0f 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -194,10 +194,6 @@ func (a *AzureBlobStorage) get(ctx context.Context, req *bindings.InvokeRequest) if err != nil { return nil, fmt.Errorf("error reading az blob: %w", err) } - err = reader.Close() - if err != nil { - return nil, fmt.Errorf("error closing az blob reader: %w", err) - } var metadata map[string]string fetchMetadata, err := req.GetMetadataAsBool(metadataKeyIncludeMetadata) From 97bb296ffcbda33dfc7bdd936a528acac0826cb4 Mon Sep 17 00:00:00 2001 From: Tiago Alves Macambira Date: Mon, 28 Nov 2022 17:08:03 -0800 Subject: [PATCH 13/22] Fixes in response to code review. * Removes emojis from output * Auto-generate certificates on the fly * Move helper methods out of vault_test.go and into helper files. Signed-off-by: Tiago Alves Macambira --- secretstores/hashicorp/vault/vault.go | 4 +- .../secretstores/hashicorp/vault/README.md | 4 +- .../hashicorp/vault/capture_logs.go | 109 +++++ .../vault/components/caFamily/Makefile | 9 +- .../caFamily/caPem/hashicorp-vault.yml | 59 --- .../components/caFamily/certificates/cert.pem | 34 -- .../certificates/incorrect-ca-cert.pem | 34 -- .../certificates/incorrect-ca-key.pem | 52 --- .../components/caFamily/certificates/key.pem | 52 --- .../caFamily/vaultConfig/vault_server.hcl | 11 +- .../hashicorp/vault/flow_helpers.go | 157 +++++++ .../hashicorp/vault/metadata_helpers.go | 105 +++++ .../hashicorp/vault/secret_helpers.go | 106 +++++ .../hashicorp/vault/vault_test.go | 421 +----------------- 14 files changed, 512 insertions(+), 645 deletions(-) create mode 100644 tests/certification/secretstores/hashicorp/vault/capture_logs.go delete mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml delete mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem delete mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem delete mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem delete mode 100644 tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem create mode 100644 tests/certification/secretstores/hashicorp/vault/flow_helpers.go create mode 100644 tests/certification/secretstores/hashicorp/vault/metadata_helpers.go create mode 100644 tests/certification/secretstores/hashicorp/vault/secret_helpers.go diff --git a/secretstores/hashicorp/vault/vault.go b/secretstores/hashicorp/vault/vault.go index 0d540c2ee..ede97a2c0 100644 --- a/secretstores/hashicorp/vault/vault.go +++ b/secretstores/hashicorp/vault/vault.go @@ -510,7 +510,7 @@ func readCertificateFolder(certPool *x509.CertPool, path string) error { func (v *vaultSecretStore) Features() []secretstores.Feature { if v.vaultValueType == valueTypeText { return []secretstores.Feature{} - } else { - return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret} } + + return []secretstores.Feature{secretstores.FeatureMultipleKeyValuesPerSecret} } diff --git a/tests/certification/secretstores/hashicorp/vault/README.md b/tests/certification/secretstores/hashicorp/vault/README.md index b4ee693f5..9f4f9c2f3 100644 --- a/tests/certification/secretstores/hashicorp/vault/README.md +++ b/tests/certification/secretstores/hashicorp/vault/README.md @@ -136,13 +136,13 @@ TODO: Should we add code to enforce that only one of these is provided? Under the current directory run: ```shell -GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -v vault_test.go +GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -v . ``` To run an specific test run (replacing `TestVersioning` with the name of the test method): ```shell -GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -run TestVersioning -v vault_test.go +GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn go test -run TestVersioning -v . ``` ### Docker-compose diff --git a/tests/certification/secretstores/hashicorp/vault/capture_logs.go b/tests/certification/secretstores/hashicorp/vault/capture_logs.go new file mode 100644 index 000000000..3a44d288c --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/capture_logs.go @@ -0,0 +1,109 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vault_test + +import ( + "bufio" + "bytes" + "io" + "os" + "strings" + + "github.com/dapr/components-contrib/tests/certification/flow" + "github.com/dapr/kit/logger" + "github.com/stretchr/testify/assert" +) + +// +// Helper functions for asserting error messages during component initialization +// +// These can be exported to their own module. +// Do notice that they have side effects: using more than one in a single +// flow will cause only the latest to work. Perhaps this functionality +// (dapr.runtime log capture) could be baked into flows themselves? +// +// Also: this is not thread-safe nor concurrent safe: only one test +// can be run at a time to ensure deterministic capture of dapr.runtime output. + +type InitErrorChecker func(ctx flow.Context, errorLine string) error + +func CaptureLogsAndCheckInitErrors(checker InitErrorChecker) flow.Runnable { + // Setup log capture + logCaptor := &bytes.Buffer{} + runtimeLogger := logger.NewLogger("dapr.runtime") + runtimeLogger.SetOutput(io.MultiWriter(os.Stdout, logCaptor)) + + // Stop log capture, reset buffer just for good mesure + cleanup := func() { + logCaptor.Reset() + runtimeLogger.SetOutput(os.Stdout) + } + + grepInitErrorFromLogs := func() (string, error) { + errorMarker := []byte("INIT_COMPONENT_FAILURE") + scanner := bufio.NewScanner(logCaptor) + for scanner.Scan() { + if err := scanner.Err(); err != nil { + return "", err + } + if bytes.Contains(scanner.Bytes(), errorMarker) { + return scanner.Text(), nil + } + } + return "", scanner.Err() + } + + // Wraps our InitErrorChecker with cleanup and error-grepping logic so we only care about the + // log error + return func(ctx flow.Context) error { + defer cleanup() + + errorLine, err := grepInitErrorFromLogs() + if err != nil { + return err + } + ctx.Logf("captured errorLine: %s", errorLine) + + return checker(ctx, errorLine) + } +} + +func AssertNoInitializationErrorsForComponent(componentName string) flow.Runnable { + checker := func(ctx flow.Context, errorLine string) error { + componentFailedToInitialize := strings.Contains(errorLine, componentName) + assert.False(ctx.T, componentFailedToInitialize, + "Found component name mentioned in an component initialization error message: %s", errorLine) + + return nil + } + + return CaptureLogsAndCheckInitErrors(checker) +} + +func AssertInitializationFailedWithErrorsForComponent(componentName string, additionalSubStringsToMatch ...string) flow.Runnable { + checker := func(ctx flow.Context, errorLine string) error { + assert.NotEmpty(ctx.T, errorLine, "Expected a component initialization error message but none found") + assert.Contains(ctx.T, errorLine, componentName, + "Expected to find component '%s' mentioned in error message but found none: %s", componentName, errorLine) + + for _, subString := range additionalSubStringsToMatch { + assert.Contains(ctx.T, errorLine, subString, + "Expected to find '%s' mentioned in error message but found none: %s", componentName, errorLine) + } + + return nil + } + + return CaptureLogsAndCheckInitErrors(checker) +} diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile b/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile index 548a7edfc..58e877255 100644 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/Makefile @@ -8,26 +8,30 @@ all: $(TARGETS) # "x509: certificate relies on legacy Common Name field" errors certificates/key.pem certificates/cert.pem: + set -e; \ + mkdir -v -p certificates; \ openssl req -x509 -newkey rsa:4096 \ -keyout certificates/key.pem \ -out certificates/cert.pem \ -sha256 -days 3650 \ -nodes \ -addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \ - -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" + -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io"; \ chmod -v 644 certificates/key.pem certificates/cert.pem # We use this for negative tests that ensure we reject connecting to # a server using a distinct Certificate Authority -- despite the server certificate # having all the right identifiers certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem: + set -e; \ + mkdir -v -p certificates; \ openssl req -x509 -newkey rsa:4096 \ -keyout certificates/incorrect-ca-key.pem \ -out certificates/incorrect-ca-cert.pem \ -sha256 -days 3650 \ -nodes \ -addext "subjectAltName = DNS:hashicorp_vault,DNS:localhost,IP:127.0.0.1" \ - -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" + -subj "/C=CA/ST=BC/L=Vancouver/O=Dapr Testing/OU=Org/CN=www.dapr.io" ; \ chmod -v 644 certificates/incorrect-ca-key.pem certificates/incorrect-ca-cert.pem @@ -43,6 +47,7 @@ caPem/hashicorp-vault.yml: caPem/hashicorp-vault.yml.template certificates/cert. clean: rm -f -v $(TARGETS) + rmdir certificates .PHONY: clean .PHONY: all \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml deleted file mode 100644 index 9f9884e43..000000000 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/caPem/hashicorp-vault.yml +++ /dev/null @@ -1,59 +0,0 @@ -# -# THIS FILE IS AUTO-GENERATED - DO NOT EDIT -# - - -apiVersion: dapr.io/v1alpha1 -kind: Component -metadata: - name: my-hashicorp-vault-TestCaFamilyOfFields-caPem - namespace: default -spec: - type: secretstores.hashicorp.vault - version: v1 - metadata: - - name: vaultAddr - value: "https://127.0.0.1:8200" - # Enforce TLS verification because this test is all about this - - name: skipVerify - value: false - - name: vaultToken # Matches docker compose VAULT_DEV_ROOT_TOKEN_ID env. var. - value: "vault-dev-root-token-id" - - name: tlsServerName - value: hashicorp_vault - - name: caPem - value: |- - -----BEGIN CERTIFICATE----- - MIIF4TCCA8mgAwIBAgIUQz0IMcZaa13YeKVjvz8ESiNCEJgwDQYJKoZIhvcNAQEL - BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 - ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD - DAt3d3cuZGFwci5pbzAeFw0yMjExMjUwNDA4NTBaFw0zMjExMjIwNDA4NTBaMGkx - CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw - EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 - LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQxCUMQAfW - RDvmpCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qG - w4JzbHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7g - cbmXrMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw - 5160nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlks - GijEVyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrd - pPnkweg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21 - XadkKErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+Wyd - zZQQeORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZ - zReChaiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiG - roVdmA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxT - IM2tNdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABo4GAMH4wHQYDVR0OBBYEFH/Z - KI7WpyDBM3UZE4sFYp/Rt6WuMB8GA1UdIwQYMBaAFH/ZKI7WpyDBM3UZE4sFYp/R - t6WuMA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 - gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAKvq+GzTZVePm3Cg - TRgT9tL0IojzBwEVulQYM1zoBPS9d/djwIznfA5IMJDwZF50uhCOwZqmHUn4GJPB - ClkYmxjQlcwfYJjiU4sVPu7zNI/bfm7wZnJLbyUNYnshuBRQ6eianwqEo+ZeZQQd - 4fM9QyfYyvW2YanPSQLOtvE6nXZzkzpVMB1H+wp6klAQ6sThHqGVpGTeNxUBaVeV - dN9vBzIdRSJ0PlTmjCiBykB2HqLEMg9ZXKBHXgciI6APiSd6bd40KNKy8eoayFPQ - rx4tdxd8kbIMRyJG4puSEKAVDaUcFqgNXOFctS3d7JX9EGKGm+aWvd8CTEOtAay9 - VMb1f6mFmMPuGOrK4JQBVOriLVBpHT9QlOIWlj9CuaycHiPfU9p3A1qL72etFdNA - 1pQ44QYjiBVxpyQvLO1DGm/HrnShWPoyBRaT2lQbMUudqeQMkQQQXRDBK4L3CIwP - pBNg/S5rJAdyAZrpCtjK896bGscCplKI6/Io0g2vOcdLrtwAn23ocshL6PWndue8 - k6XUS1LFLKz/cgRzzk93yD5VMYkYwo0hfHdpsF9AELl6DHsILEvkAYmR8zJcz/o8 - hpsTwp3eNexA//gED4f4qWoTbnr1ofFToloQqC/nWhtNaO0BNClyJH8cYcVNQLFX - LFXkjVxkrXK8v2vNPR2KvyXleKFk - -----END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem deleted file mode 100644 index b6d963737..000000000 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/cert.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIF4TCCA8mgAwIBAgIUQz0IMcZaa13YeKVjvz8ESiNCEJgwDQYJKoZIhvcNAQEL -BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 -ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD -DAt3d3cuZGFwci5pbzAeFw0yMjExMjUwNDA4NTBaFw0zMjExMjIwNDA4NTBaMGkx -CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw -EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 -LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQxCUMQAfW -RDvmpCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qG -w4JzbHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7g -cbmXrMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw -5160nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlks -GijEVyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrd -pPnkweg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21 -XadkKErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+Wyd -zZQQeORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZ -zReChaiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiG -roVdmA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxT -IM2tNdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABo4GAMH4wHQYDVR0OBBYEFH/Z -KI7WpyDBM3UZE4sFYp/Rt6WuMB8GA1UdIwQYMBaAFH/ZKI7WpyDBM3UZE4sFYp/R -t6WuMA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 -gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAKvq+GzTZVePm3Cg -TRgT9tL0IojzBwEVulQYM1zoBPS9d/djwIznfA5IMJDwZF50uhCOwZqmHUn4GJPB -ClkYmxjQlcwfYJjiU4sVPu7zNI/bfm7wZnJLbyUNYnshuBRQ6eianwqEo+ZeZQQd -4fM9QyfYyvW2YanPSQLOtvE6nXZzkzpVMB1H+wp6klAQ6sThHqGVpGTeNxUBaVeV -dN9vBzIdRSJ0PlTmjCiBykB2HqLEMg9ZXKBHXgciI6APiSd6bd40KNKy8eoayFPQ -rx4tdxd8kbIMRyJG4puSEKAVDaUcFqgNXOFctS3d7JX9EGKGm+aWvd8CTEOtAay9 -VMb1f6mFmMPuGOrK4JQBVOriLVBpHT9QlOIWlj9CuaycHiPfU9p3A1qL72etFdNA -1pQ44QYjiBVxpyQvLO1DGm/HrnShWPoyBRaT2lQbMUudqeQMkQQQXRDBK4L3CIwP -pBNg/S5rJAdyAZrpCtjK896bGscCplKI6/Io0g2vOcdLrtwAn23ocshL6PWndue8 -k6XUS1LFLKz/cgRzzk93yD5VMYkYwo0hfHdpsF9AELl6DHsILEvkAYmR8zJcz/o8 -hpsTwp3eNexA//gED4f4qWoTbnr1ofFToloQqC/nWhtNaO0BNClyJH8cYcVNQLFX -LFXkjVxkrXK8v2vNPR2KvyXleKFk ------END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem deleted file mode 100644 index 1bdae2e7a..000000000 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-cert.pem +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIF4TCCA8mgAwIBAgIUSrQ0syOfHO5v4Jl7gqdachXf1o8wDQYJKoZIhvcNAQEL -BQAwaTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAkJDMRIwEAYDVQQHDAlWYW5jb3V2 -ZXIxFTATBgNVBAoMDERhcHIgVGVzdGluZzEMMAoGA1UECwwDT3JnMRQwEgYDVQQD -DAt3d3cuZGFwci5pbzAeFw0yMjExMjUxOTQ0MDJaFw0zMjExMjIxOTQ0MDJaMGkx -CzAJBgNVBAYTAkNBMQswCQYDVQQIDAJCQzESMBAGA1UEBwwJVmFuY291dmVyMRUw -EwYDVQQKDAxEYXByIFRlc3RpbmcxDDAKBgNVBAsMA09yZzEUMBIGA1UEAwwLd3d3 -LmRhcHIuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDCdxTPbiMc -Gx7l/6cBI8nuvrX0AA+OZNoxNRSa/Y5LNXOdIFbMvBHgK4spQKN2RXVjLB9PZ6Tz -rNxlQNgMlF3dOVGxFVBLhjt1acDPXjeDYeCrq6lj5NnqBUJGE7Weau8KIAh1iDfp -pFT5Sa7spVwdFpVcgS/WUvB7LMIqZJgCvydMw1DMM8iE7KbuHBeGO0dkELDt1b28 -sYAB2LV1pesr4yIVeBcqDmZJhHhKyXeNi0RxYwVR+c5/AIcy4oz3AwGaj00xCSRS -tbUZYT3wtKuFWajLVaFhhWspqnEgDfGaYgRWMBhybLUBJSkTi1y6XfGPbJg5p9cr -rXuLNeqwavJqi3/ow7N6ybCC+gpZFGtotUIVe6G9Gw4puPtpL8dXRt5UGI77lUMA -cjaRTql4RZG9yiWxvkppbJohYzZj39buVVtnfK4h6fVeOsIrotjq6A07PmrC9IZG -tYyShDc0lk0ns08PuaFxUEWDFSNgPXzZh7jVXykBRqWkqsAVUhve8NYBB0GyEIJ3 -fl/Nbb0ODqQXrknvD2af9jRrd0yC3NSg3+3pW9bMLe1qA28GiisGREhIV2I7WIm8 -nDQX/sxE1WOVlL5QQP5mnkZEJJIOQoq5AT+orFquvbCUYhyqf5VVM07+H3A/C6Au -AZ0EBBzBKdF15UvPA68Nqef/OX4jCs584wIDAQABo4GAMH4wHQYDVR0OBBYEFHUA -p2sagqDSpNEfGHXLQTQPCsC6MB8GA1UdIwQYMBaAFHUAp2sagqDSpNEfGHXLQTQP -CsC6MA8GA1UdEwEB/wQFMAMBAf8wKwYDVR0RBCQwIoIPaGFzaGljb3JwX3ZhdWx0 -gglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggIBAG/8gN+7C+ROZrDS -fWHYA68jwdQWqe5+5SlZ4sMEbboA7+++csptBi27oQEtCdsTMx/4eC8/Topsz1// -OcHPo+/pQQW5VWo1Ny0Nfq9TJ+CZ9NuEoizSnLvVWhEBclA7bhkGvp3cqXTa6XqH -EDSur0ltQRhs0F+zFRPuPqEIJziLv54BEnt1iM2ydv3yVi0dF9Xz8BE92pB93ONd -PnnvCjFhvZn9X2oogBgf0HaMTQDj02mm25q86NVZ5qSEBuc+NI/8l7s5ruo+HXcY -q2WqAgwnQfmYUrNqHNmB0zj0+NygZytWmPYb1GVSi+3PcgVKW08EsQ7i8MI00CCY -/J2Pb/wHcu1VSRjX3ijhcp4MDfHQmFAnRyaey/ocHdUrBiTtWzNszD5DQhMPOKGx -ksItrRDExgDkVZspqli72oFnZyF3V4NEAo/ZDk2k5o91huyc7d/sQ4mc2ghJfNCT -aMWsHbYF7oUkwvun4K8duePB0M1JZS4qXG0kmQrEfUSocS3U8AWItvVQ9H0DCbpT -pcQFBqCuaj3ehuzsExbKLKI6+VrqTXZi8ZPozyxbkWuXnXSPFdG5wn5eQrFQxGnt -jFjrzTFeo9kzp3a7fYVveR70xYF3hdtHbPRhxt18k8BZB1vLrb08v9df0LAFfcd2 -vljYnSZYxz/14hzgCxFSQq6D92/E ------END CERTIFICATE----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem deleted file mode 100644 index 0d0003c60..000000000 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/incorrect-ca-key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQDCdxTPbiMcGx7l -/6cBI8nuvrX0AA+OZNoxNRSa/Y5LNXOdIFbMvBHgK4spQKN2RXVjLB9PZ6TzrNxl -QNgMlF3dOVGxFVBLhjt1acDPXjeDYeCrq6lj5NnqBUJGE7Weau8KIAh1iDfppFT5 -Sa7spVwdFpVcgS/WUvB7LMIqZJgCvydMw1DMM8iE7KbuHBeGO0dkELDt1b28sYAB -2LV1pesr4yIVeBcqDmZJhHhKyXeNi0RxYwVR+c5/AIcy4oz3AwGaj00xCSRStbUZ -YT3wtKuFWajLVaFhhWspqnEgDfGaYgRWMBhybLUBJSkTi1y6XfGPbJg5p9crrXuL -NeqwavJqi3/ow7N6ybCC+gpZFGtotUIVe6G9Gw4puPtpL8dXRt5UGI77lUMAcjaR -Tql4RZG9yiWxvkppbJohYzZj39buVVtnfK4h6fVeOsIrotjq6A07PmrC9IZGtYyS -hDc0lk0ns08PuaFxUEWDFSNgPXzZh7jVXykBRqWkqsAVUhve8NYBB0GyEIJ3fl/N -bb0ODqQXrknvD2af9jRrd0yC3NSg3+3pW9bMLe1qA28GiisGREhIV2I7WIm8nDQX -/sxE1WOVlL5QQP5mnkZEJJIOQoq5AT+orFquvbCUYhyqf5VVM07+H3A/C6AuAZ0E -BBzBKdF15UvPA68Nqef/OX4jCs584wIDAQABAoICAQCm8+dY4ryf36TaX284qkou -f2rlLbwtSuaMgn7LRc6JQT2d82qx4PET3S5fX1A3NRC/8Nx8poXWclzRTSdvPV2M -lS5Ocvb5sCeR+RYAsmnEkR57JCiMS6jOom8wjLFLbZEFx1Sb2zPtkhkl4J2eK6V2 -j7HxtjOktJYjmdyk2rIrAYOzAqh2eCq5/BagrFuB8ZisDyxnNC7uNhGpBC1d8PGD -P0A+4Fg60hv9GA7SXj8WtS8wjYu+wlIHdSOdiyTs2Jbi5A6of6nAnKH7RSIRansr -RDuHPmALwqirH9p5Y58+JNKGUEpcynlnn0ixr98PXaIKuXfDYBZ6ODmt3b88cMTn -NgQ0AF9SLOqtong3roxq/fluHmD7TbX3sryBmjEUtdKJ4SwIYRbqJt6yKTn99VBJ -tSBxokz2s8/ExnnYmiOEMmf6Ri8pmszu5hy8tswvVaHY9Vgu+KhF4spfyy6tWUly -ducfmvnNqpp9f+KID73pIN0OV0Wb/2smvmBeM8AQqh7KOcBvE9Uep7sNZs/6MnuK -ZodQf4PlwiE50Z05qiYqivy74U/57Sw30nBd0m4B7gWwDKRd0dMxanv2JVQ+AEq7 -Fsue7/CqQbejG5ExspOFb5sFrQLD3MD5//TIAQCjUjEGGMEX/Su+if7viw8b2Ztg -v2yaEqLYf/nKxyjMQ3zyKQKCAQEA73YxAFgI8/hqmAwvorIvVhVAzPFRq9lYU5ol -ic8GbQjv403Qlc9mIv5VJulNHIP3jBiDbI0BGyavvZ4emwxd5F+YzUMCfN+M6brL -opL6/SeBd6clGqYVIYRPMEh5i4hXgfDHZtLEkUhoNULyo+1TtLFiLTufeQl1i3u3 -VeCLhadpg3VQMzo2ADzDDWV4gm+Zj6vdhk4ia20JZZs6+jbehi62JVcOW7wA7A1/ -UotYLNzWJ+WMfG5chLqC4FGA7p0mAz7XBXO+4TNGnoeliBohba5OIvDX2HAiOqk7 -IUzmBzq3ycTn0yQzrk51/1s99TNJ6YtFiLISmrxtpy9K5vcS7QKCAQEAz+VT4ZJV -B0JSvAuJs/OOTrdaHRG3U/39ZRZ7B/LstUYk0Mw6gNvCB/I66LFjwnv9sv8vwPDy -32fWyjt4c1mOkAWw8kSi2Z7e+/Tbkuhi2UwrIuF2Zk6nUyP0oDD03xYOryEcgxWd -JtW4eOA96BU42tApyj+9D3JJshinVD+QgTg6GlxPWqwHQAqMPqOpuEbMJBQhDlZu -dFtlYv+866hcoeJd54SZhXQqqMD/XOEL+n5CcSGOO0pt5vCAFDoT7Vws/xQ5frx/ -m1LSVu8nbLVXS37NbRRHeKV7aK3jQ6duG7iC1xccWlUKh16CQKgqWz7WEGS1b5dR -MbYxBd0Zd1TFDwKCAQEArLeNJHhbDM2y5LR1b14iMm7l7Gxqwg7kXHikdr+yHNcD -X+nydvu+6aKUfJpuGhE9bfkIYjVaBOFkhNoVrTPATUZ+ih65HqSHmNY4pqxpCEuE -YG9Ynd4JA8HQ9DxyHqhapcirqoh/a2LUdwYwyPgXFg+Thpior76Y3+B+Hhz1xZM4 -0a6+CBUGeilZbsIvp7UjB7Oo9oRI4z8kNfs/ENaerh3nFwuxuYzjBV++5CTJlqI6 -fVBegil/5eQ5Hd7rpjAHCPQ8VxxjIz++wf2I8aAXWGsOxLj+lohayADkO2Khz7kU -cx3pMCu+cwz4oxSGneM+fosLvkrijGU4mgvMdMblCQKCAQB62xID5p766DXOTJ82 -ycKaP/4v2Y1WRG2fdHaGTweVZHtTLK2SAswaOAqaAmJqxy04v1cwFPPiFBI5doWK -3SzDbamQsgDuy9UIXj34Bf6MXVfMiCKY+PgmyMPCesvqnbVVxyJ7UKWLEpeuTw4m -fYwYuxVHIP2QCEEGz0zrG5lA08J6W3zFn421ScZxKfSdIrF2zLJwL6Gcf3pd07WI -Kfl77TMDIzg6RlkDWvJNp+yVPlHzWxobbbOe2xdFXMDz7xnkL8Z+X9SlLH+Cwlex -BUUuJyQsxuQpptlUFhaMn4ARP6uKgmzN8R2Eu9QLc5V8UJjeHTWfWXOxBfLYfT2U -aHL/AoIBAQCPc8rfH3M0ZWv8edsibvOgUtJ3yG4+IiRjLEnNhK6NVZHfX9RIAmqO -csIYRhV8hjBVLwAc12a3t105JXfbYnQ9ucwsXmSKt0W+CDOCOMKCEvUv/33ePhZN -dwmyb+E9C32mb/xWipmt/t8ucNUDkX81U7tauEWjx2tQv5Db5iGmuoIkPAxbeOLc -JRNTyYzBYiG7j3nKo/6Yg69eUZibh1M0Dg6NIZ9ltmU50yB7JQBCxrJGz7VcPmJb -ute7XRuTHKHjESeTHkC5RsSAOc1cLmcu/W3qWDYZaFAo7pX3e3bWqAbatVaqSs6C -WG6Z5JfRpAOCbhDnmIuc1NxwhVyG8c3q ------END PRIVATE KEY----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem b/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem deleted file mode 100644 index 239be4c7c..000000000 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/certificates/key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDQxCUMQAfWRDvm -pCYV/2W5hhWutQlPL48oajtxmX8qeiPoiSKbbirOXUnKBqLM2QVRupkjC2qGw4Jz -bHfxxipaTvpof5Zh53GwomBeeDpAQGWiFpd6ObUoLzxWlN2RuDCZx44fob7gcbmX -rMawL6H7qpo92cgMDudh+30ICwNe2lSvbq5p4kMWjxwFSyErvwfAKXKuMtIw5160 -nLWpbMFlKTj1oYeQWbjDNA168SUGkkaRIC/2uxZ5I9GIQtk8h5NXI0RxDlksGijE -VyMtbi25tpefNCX1F1oG/sjLthdliXfSbGLNGKdgiNdvuhJIq0x2aFiNwcrdpPnk -weg7k6Ew4v9kewaIh7UttMO9MMGcAsDN+ympYaodgrk/qw4285Bl328sUC21Xadk -KErcxnEW8bc5JHZkflH/jC5Z+tWThpgQKz6aIw/h9ApXUMpwqcJKrES4+WydzZQQ -eORliiefBcMv6Yq7oE9mzq1vjWyCYqt/dAAOJ1mZGnzGAnKeubtPeAICfbCZzReC -haiyqcM8rvtxpE2ldskroUT312bTIdpP90QVgbGGseJ///y5SjmnAGLEJiiGroVd -mA/tmi7buXR5SqOrqL4037rCNY+8QThmZuH24UZCoPPRAbkQp1wF2qQCcVxTIM2t -NdR6ItHldE+5TS7uhQ4eJI9XfXs7CwIDAQABAoICAQCThohHp9fh6kYKLmVblidk -ewRHeVcixhD8FlX7aOUcN0O4x2/VNny5Z+MFCLty1smTf7FHuoGEyhQdTMFV8Rts -xfLedYrnlI4arCQ9nehMDzXC3QQeMzl5NCgHZxtMJkTx5rrgT4R7RuJH9KhTSNXG -6kAlBQkAvGd2LimkzWOMW+0MK8LEwEd4YZkDhJvkNhJcEO4he3hdZqLeLv+QwnHH -8uF1crhBoaWXC+mav13SzvtfAsfiK0MuR8mB6PtqcsQEB8ANxH3vVG0KkikhqYJW -glmS/17zW5Ua7GEo03ylHAe4gy8ukAV3ijvzkCHriGF4KzSouBGLn1GX/g8GSsTU -Z8xjkQ7/fvL0BxngglmjQOJtqmhGbX9vBwJB7Lufdo2uv3/1+oHVDRgtGx6IldAz -ZoiZj1owoGs9wxx6EoDnh4L51u/Kg18yjk7VhOU1TLo+bO97pHcEV3T20Vk5ZdPY -xJ4YSBtaX9RhvEPDK+gZur2tLO0i4B1j5JrqHg+w9ROj2jeYtDP9Ji7TiwJa6crw -TzSOZq+5Bbdc3LzAmG/1plLbJquusi0bi+GZoS+Cadpv0pAefGxsa8TW+0fDKfxc -xkRW50Dh3bSv7VCuEyqgGpU2Kqkz0heYa1xCuzYUDtphelBS2Q92gbS2G3nB6zF8 -r/HDS3fE68SSo1hdJvpTAQKCAQEA9Pv8I8ZDHfSiKPUcOQWDjv+t7XkoWqa71Nkl -B+exmL3MkmzPV7AwYv8mJwdgsildQl92/JE8khNtetLfbmr+AkSYuHi8H96NFMfM -feQsv16noC2vjH2wHIsR1YcZlvGHK0tK05s7PZxLVWcoHAqzRw0tV/1VdcHq54t/ -QfrqQFdrQ4G+K/iYyT3MqErWdk566JVQbA2HZxhbau0Dm8V2lx9+5FmWo01GNQ2d -ZyigSUOWnxYWz4tvA9BQvGZ3NKRp6+vgb6zIcFuSL66bwtc3xi6pJm5yKMQR9TKm -fypq54wUvkYS098C/MSBDxy/mPlzFW4YZb0//n3D2HglOgRNsQKCAQEA2idAu3GH -+m6skYX5efTBw3Rz3wv+iopo8K/8ToYETbRdtJV1dLXcR2W4b9ebc+IkIkDOicgO -4P2eai/CSCpoL+/fI0wd2eyfT6oACQMKoz0lgY39gg5/lnNbjrZuwgH2o+epFi5I -YhZgaXT6/DhuM8ROx0TViqGyWEWz7hgw+fY3WpnmPQqO/83kxh4akzVJetdZzkLc -XKJtT0aW8MJ+g4TQUE1j3GzBTN3gPOKVIHbqw4+I39ytwSo5CPO4MGOJRSW7mAOH -YR8fNIhZuWIiXi0RfrgSFGHwRIPXSZhWCMlwfOSmuuJcvM3qkbw1n+SyZVin3Lm3 -hv9yWrYgch8XewKCAQB9a8RaTFZwL54VeedJChmgTCWvPif6wQHIpqLeuS+jEwh4 -rlw4eGtNQ3M06AIJNEQahuVTyMdJwch66RqaXQxN/PBzANzPNBDmYqO+j+KY1sza -pIkLVA2lj01CFDh1npGlCJb2XrKliC7JOla+hHvkFErykS//aZfpkvFDxkHHTvoL -RZEm0c7muEzem/HP/73M9SSHLSX1EfM7erwuM5nTJLzCC1ujnxwibSX4ekQVPhUO -vTBQcQIU4cFzssG0obfYoJn2km7LlxXwc2QrDCPxwlG26zRmynqnHZc/42d3w6+a -+iUJc1MENVYddopgttTEU+kJrSnmEF0Dpf7pBOsBAoIBAFWPn6vk01g9oCFTUo2q -mXR3cBrDMYpUzuPXojWKCpYPb9Er7W1hBoxaMQRso+PHhjSJBnizpmJIFqG/KYv0 -Vfi3M+U8LVkTnUg5fNoL/1gW22b8sbkYxqHTjM1kb/xXmMygR4kTjgAqlpXF88qI -t3BGRj+Rl89PrAtDC1cO1eaz0vIN+mdmhL9/mYK6u+GQvMkZPXfQcW1Dp2u4W+sB -3Wzn4mwcblY9sXLcct5uX97jxR/+Y8ipXNyuGsCQFmWkJGqiafktKSPGeQ65i7dR -7fjR5FK3DyA/aWT18LJEtTmtCBlz9JDHx2elu6J9FusnX3CwXOYNURX5inhZhlA8 -MZECggEBAOo4fYcU+75WtZrzS49EBTYoRRHvihHcZwQ8P/J+pP8yuoD+bGbXyciS -5OV1yLEoScbzARa9jDvQhYSPyQV6QQcsCT45spIeHURzyYY30WhcluvE0U2BC+Sh -GslAiwA1IcDZ45hdbj9J33iZMzIroG1evnpOngUd6SwfT8da+MfhPNDnwcgy+HUG -bjOy6/1ds9saFQkKGgmUAt51hiHreCVMUbu+lNaqJRYMIPmx/zgqXhyhqMC+hh1S -GP/XqE9ylx3K769VsXS22IuhXJC5EaiSzqzyjVP4kzmCqccKBsngqKFGIwuFI25p -JpgsDDiLHGcoVG2ei6PE1GFlSixtFvI= ------END PRIVATE KEY----- diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl b/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl index 4326d60bb..8d18bad85 100644 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/vaultConfig/vault_server.hcl @@ -3,13 +3,4 @@ listener "tcp" { tls_disable = "false" tls_cert_file = "/certificates/cert.pem" tls_key_file = "/certificates/key.pem" -} - -api_addr = "https://127.0.0.1:8201" - -#backend "file" { -# path = "/vault/file" -#} - -#default_lease_ttl = "168h" -#max_lease_ttl = "720h" +} \ No newline at end of file diff --git a/tests/certification/secretstores/hashicorp/vault/flow_helpers.go b/tests/certification/secretstores/hashicorp/vault/flow_helpers.go new file mode 100644 index 000000000..62034e384 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/flow_helpers.go @@ -0,0 +1,157 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vault_test + +import ( + "path/filepath" + "testing" + "time" + + "github.com/dapr/components-contrib/secretstores/hashicorp/vault" + "github.com/dapr/components-contrib/tests/certification/embedded" + "github.com/dapr/components-contrib/tests/certification/flow" + "github.com/dapr/components-contrib/tests/certification/flow/dockercompose" + "github.com/dapr/components-contrib/tests/certification/flow/sidecar" + secretstores_loader "github.com/dapr/dapr/pkg/components/secretstores" + "github.com/dapr/dapr/pkg/runtime" + dapr_testing "github.com/dapr/dapr/pkg/testing" + "github.com/dapr/kit/logger" + "github.com/stretchr/testify/assert" +) + +// +// Flow and test setup helpers +// + +func componentRuntimeOptions() []runtime.Option { + log := logger.NewLogger("dapr.components") + + secretStoreRegistry := secretstores_loader.NewRegistry() + secretStoreRegistry.Logger = log + secretStoreRegistry.RegisterComponent(vault.NewHashiCorpVaultSecretStore, "hashicorp.vault") + + return []runtime.Option{ + runtime.WithSecretStores(secretStoreRegistry), + } +} + +func GetCurrentGRPCAndHTTPPort(t *testing.T) (int, int) { + ports, err := dapr_testing.GetFreePorts(2) + assert.NoError(t, err) + + currentGrpcPort := ports[0] + currentHttpPort := ports[1] + + return currentGrpcPort, currentHttpPort +} + +// +// Helper functions for common tests for happy case, init-but-does-not-work and fails-initialization tests +// These test re-use the same seed secrets. They aim to check how certain flags break or keep vault working +// instead of verifying some specific tha change key retrieval behavior. +// +// Those tests require a `/` structure. + +type commonFlowSettings struct { + t *testing.T + currentGrpcPort int + currentHttpPort int + secretStoreComponentPathBase string + componentNamePrefix string +} + +func NewFlowSettings(t *testing.T) *commonFlowSettings { + res := commonFlowSettings{} + res.t = t + res.currentGrpcPort, res.currentHttpPort = GetCurrentGRPCAndHTTPPort(t) + return &res +} + +func createPositiveTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + if useCustomDockerCompose { + dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + } + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(componentPath)). + Step("Test that the default secret is found", testDefaultSecretIsFound(fs.currentGrpcPort, componentName)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} + +func createInitSucceedsButComponentFailsFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool, initErrorCodes ...string) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + if useCustomDockerCompose { + dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") + } + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + Step("Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(componentPath)). + Step("Verify component does not work", testComponentIsNotWorking(componentName, fs.currentGrpcPort)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} + +func createNegativeTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, initErrorCodes ...string) { + componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) + componentName := fs.componentNamePrefix + componentSuffix + dockerComposeClusterYAML := defaultDockerComposeClusterYAML + + flow.New(fs.t, flowDescription). + Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). + Step("Waiting for component to start...", flow.Sleep(5*time.Second)). + Step(sidecar.Run(sidecarName, + embedded.WithoutApp(), + embedded.WithComponentsPath(componentPath), + embedded.WithDaprGRPCPort(fs.currentGrpcPort), + embedded.WithDaprHTTPPort(fs.currentHttpPort), + componentRuntimeOptions(), + )). + Step("Waiting for component to load...", flow.Sleep(5*time.Second)). + // TODO(tmacam) FIX https://github.com/dapr/dapr/issues/5487 + Step("Verify component is NOT registered", testComponentNotFound(componentName, fs.currentGrpcPort)). + Step("Verify initialization error reported for component", AssertInitializationFailedWithErrorsForComponent(componentName, initErrorCodes...)). + Step(" Bug dependant behavior - test component is actually registered", testComponentFound(componentName, fs.currentGrpcPort)). + Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). + Run() +} diff --git a/tests/certification/secretstores/hashicorp/vault/metadata_helpers.go b/tests/certification/secretstores/hashicorp/vault/metadata_helpers.go new file mode 100644 index 000000000..29b3b4160 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/metadata_helpers.go @@ -0,0 +1,105 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vault_test + +import ( + "context" + "fmt" + + "github.com/dapr/components-contrib/secretstores" + "github.com/dapr/components-contrib/tests/certification/flow" + "github.com/dapr/go-sdk/client" + "github.com/golang/protobuf/ptypes/empty" + "github.com/stretchr/testify/assert" +) + +// +// Helper methods for checking component registration and availability of its features +// + +func testComponentFound(targetComponentName string, currentGrpcPort int) flow.Runnable { + return func(ctx flow.Context) error { + componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") + return nil + } +} + +// Due to https://github.com/dapr/dapr/issues/5487 we cannot perform negative tests +// for the component presence against the metadata registry. +// Instead, we turned testComponentNotFound into a simpler negative test that ensures a good key cannot be found +func testComponentNotFound(targetComponentName string, currentGrpcPort int) flow.Runnable { + // TODO(tmacam) once https://github.com/dapr/dapr/issues/5487 is fixed, uncomment the code bellow + return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") + + //return func(ctx flow.Context) error { + // // Find the component + // componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + // assert.False(ctx.T, componentFound, "Component was expected to be missing but it was found.") + // return nil + //} +} + +func testComponentDoesNotHaveFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { + return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, false) +} + +func testComponentHasFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { + return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, true) +} + +func testComponentAndFeaturePresence(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature, expectedToBeFound bool) flow.Runnable { + return func(ctx flow.Context) error { + componentFound, capabilities := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) + + assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") + + targetCapabilityAsString := string(targetCapability) + // Find capability + capabilityFound := false + for _, cap := range capabilities { + if cap == targetCapabilityAsString { + capabilityFound = true + break + } + } + assert.Equal(ctx.T, expectedToBeFound, capabilityFound) + + return nil + } +} + +func getComponentCapabilities(ctx flow.Context, currentGrpcPort int, targetComponentName string) (found bool, capabilities []string) { + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer daprClient.Close() + + clientCtx := context.Background() + + resp, err := daprClient.GrpcClient().GetMetadata(clientCtx, &empty.Empty{}) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, resp) + assert.NotNil(ctx.T, resp.GetRegisteredComponents()) + + // Find the component + for _, component := range resp.GetRegisteredComponents() { + if component.GetName() == targetComponentName { + ctx.Logf("component found=%s", component) + return true, component.GetCapabilities() + } + } + return false, []string{} +} diff --git a/tests/certification/secretstores/hashicorp/vault/secret_helpers.go b/tests/certification/secretstores/hashicorp/vault/secret_helpers.go new file mode 100644 index 000000000..61e6bf027 --- /dev/null +++ b/tests/certification/secretstores/hashicorp/vault/secret_helpers.go @@ -0,0 +1,106 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package vault_test + +import ( + "fmt" + "github.com/dapr/components-contrib/tests/certification/flow" + "github.com/dapr/go-sdk/client" + "github.com/stretchr/testify/assert" +) + +// +// Aux. functions for testing key presence +// + +func testKeyValuesInSecret(currentGrpcPort int, secretStoreName string, secretName string, keyValueMap map[string]string, maybeVersionID ...string) flow.Runnable { + return func(ctx flow.Context) error { + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer daprClient.Close() + + metadata := map[string]string{} + if len(maybeVersionID) > 0 { + metadata["version_id"] = maybeVersionID[0] + } + + res, err := daprClient.GetSecret(ctx, secretStoreName, secretName, metadata) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, res) + + for key, valueExpected := range keyValueMap { + valueInSecret, exists := res[key] + assert.True(ctx.T, exists, "expected key not found in key") + assert.Equal(ctx.T, valueExpected, valueInSecret) + } + return nil + } +} + +func testSecretIsNotFound(currentGrpcPort int, secretStoreName string, secretName string) flow.Runnable { + return func(ctx flow.Context) error { + daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer daprClient.Close() + + emptyOpt := map[string]string{} + + _, err = daprClient.GetSecret(ctx, secretStoreName, secretName, emptyOpt) + assert.Error(ctx.T, err) + + return nil + } +} + +func testDefaultSecretIsFound(currentGrpcPort int, secretStoreName string) flow.Runnable { + return testKeyValuesInSecret(currentGrpcPort, secretStoreName, "multiplekeyvaluessecret", map[string]string{ + "first": "1", + "second": "2", + "third": "3", + }) +} + +func testComponentIsNotWorking(targetComponentName string, currentGrpcPort int) flow.Runnable { + return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") +} + +func testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort int, secretStoreName string) flow.Runnable { + return func(ctx flow.Context) error { + client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer client.Close() + + emptyOpt := map[string]string{} + + res, err := client.GetBulkSecret(ctx, secretStoreName, emptyOpt) + assert.NoError(ctx.T, err) + assert.NotNil(ctx.T, res) + assert.NotEmpty(ctx.T, res) + + for k, v := range res { + ctx.Logf("💡 %s", k) + for i, j := range v { + ctx.Logf("💡\t %s : %s", i, j) + } + } + + return nil + } +} diff --git a/tests/certification/secretstores/hashicorp/vault/vault_test.go b/tests/certification/secretstores/hashicorp/vault/vault_test.go index 338e32d7b..467e8a8a2 100644 --- a/tests/certification/secretstores/hashicorp/vault/vault_test.go +++ b/tests/certification/secretstores/hashicorp/vault/vault_test.go @@ -14,32 +14,18 @@ limitations under the License. package vault_test import ( - "bufio" - "bytes" "context" - "fmt" - "io" - "os" + "os/exec" "path/filepath" - "strings" "testing" "time" "github.com/dapr/components-contrib/secretstores" - "github.com/dapr/components-contrib/secretstores/hashicorp/vault" "github.com/dapr/components-contrib/tests/certification/embedded" "github.com/dapr/components-contrib/tests/certification/flow" "github.com/dapr/components-contrib/tests/certification/flow/dockercompose" "github.com/dapr/components-contrib/tests/certification/flow/network" "github.com/dapr/components-contrib/tests/certification/flow/sidecar" - secretstores_loader "github.com/dapr/dapr/pkg/components/secretstores" - "github.com/dapr/dapr/pkg/runtime" - dapr_testing "github.com/dapr/dapr/pkg/testing" - "github.com/dapr/go-sdk/client" - "github.com/dapr/kit/logger" - "github.com/stretchr/testify/assert" - - "github.com/golang/protobuf/ptypes/empty" ) const ( @@ -83,7 +69,7 @@ func TestBasicSecretRetrieval(t *testing.T) { )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Run basic secret retrieval test", testGetKnownSecret). Step("Test retrieval of secret that does not exist", testGetMissingSecret). Step("Interrupt network for 1 minute", @@ -114,7 +100,7 @@ func TestMultipleKVRetrieval(t *testing.T) { )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Verify component has support for multiple key-values under the same secret", testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). Step("Test retrieval of a secret with multiple key-values", @@ -150,7 +136,7 @@ func TestVaultKVPrefix(t *testing.T) { )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Verify component has support for multiple key-values under the same secret", testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). Step("Test retrieval of a secret under a non-default vaultKVPrefix", @@ -182,7 +168,7 @@ func TestVaultKVUsePrefixFalse(t *testing.T) { )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Verify component has support for multiple key-values under the same secret", testComponentHasFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). Step("Test retrieval of a secret registered with no prefix and assuming vaultKVUsePrefix=false", @@ -217,7 +203,7 @@ func TestVaultValueTypeText(t *testing.T) { )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). Step("Verify component is registered", testComponentFound(secretStoreName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(secretStoreComponentPath)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(secretStoreComponentPath)). Step("Verify component DOES NOT support multiple key-values under the same secret", testComponentDoesNotHaveFeature(currentGrpcPort, secretStoreName, secretstores.FeatureMultipleKeyValuesPerSecret)). Step("Test secret store presents name/value semantics for secrets", @@ -314,8 +300,8 @@ func TestEnginePathCustomSecretsPath(t *testing.T) { componentRuntimeOptions(), )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("✅Verify component is registered", testComponentFound(componentName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("Verify component is registered", testComponentFound(componentName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(componentPath)). Step("Verify that the custom path has secrets under it", testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort, componentName)). Step("Verify that the custom path-specific secret is found", testKeyValuesInSecret(currentGrpcPort, componentName, "secretUnderCustomPath", map[string]string{ @@ -342,6 +328,19 @@ func TestCaFamilyOfFields(t *testing.T) { fs.secretStoreComponentPathBase = "./components/caFamily/" fs.componentNamePrefix = "my-hashicorp-vault-TestCaFamilyOfFields-" + // Generate certificates and caPem/hashicorp-vault.yml + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel() + makeCmd := exec.CommandContext(ctx, "make", + // Change to components/caFamily directory so files are generated relative to that directory + "-C", fs.secretStoreComponentPathBase, + ) + + if out, err := makeCmd.CombinedOutput(); err != nil { + t.Logf("Make exited with error %s", out) + t.Fatal(err) + } + createPositiveTestFlow(fs, "Verify success when using a caCert to talk to vault with tlsServerName and enforceVerify", "caCert", true) @@ -388,8 +387,8 @@ func TestVersioning(t *testing.T) { componentRuntimeOptions(), )). Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("✅Verify component is registered", testComponentFound(componentName, currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). + Step("Verify component is registered", testComponentFound(componentName, currentGrpcPort)). + Step("Verify no errors regarding component initialization", AssertNoInitializationErrorsForComponent(componentPath)). Step("Verify that we can list secrets", testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort, componentName)). Step("Verify that the latest version of the secret is there", testKeyValuesInSecret(currentGrpcPort, componentName, "secretUnderTest", map[string]string{ @@ -402,377 +401,3 @@ func TestVersioning(t *testing.T) { Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). Run() } - -// -// Aux. functions for testing key presence -// - -func testKeyValuesInSecret(currentGrpcPort int, secretStoreName string, secretName string, keyValueMap map[string]string, maybeVersionID ...string) flow.Runnable { - return func(ctx flow.Context) error { - daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer daprClient.Close() - - metadata := map[string]string{} - if len(maybeVersionID) > 0 { - metadata["version_id"] = maybeVersionID[0] - } - - res, err := daprClient.GetSecret(ctx, secretStoreName, secretName, metadata) - assert.NoError(ctx.T, err) - assert.NotNil(ctx.T, res) - - for key, valueExpected := range keyValueMap { - valueInSecret, exists := res[key] - assert.True(ctx.T, exists, "expected key not found in key") - assert.Equal(ctx.T, valueExpected, valueInSecret) - } - return nil - } -} - -func testSecretIsNotFound(currentGrpcPort int, secretStoreName string, secretName string) flow.Runnable { - return func(ctx flow.Context) error { - daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer daprClient.Close() - - emptyOpt := map[string]string{} - - _, err = daprClient.GetSecret(ctx, secretStoreName, secretName, emptyOpt) - assert.Error(ctx.T, err) - - return nil - } -} - -func testDefaultSecretIsFound(currentGrpcPort int, secretStoreName string) flow.Runnable { - return testKeyValuesInSecret(currentGrpcPort, secretStoreName, "multiplekeyvaluessecret", map[string]string{ - "first": "1", - "second": "2", - "third": "3", - }) -} - -func testComponentIsNotWorking(targetComponentName string, currentGrpcPort int) flow.Runnable { - return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") -} - -func testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort int, secretStoreName string) flow.Runnable { - return func(ctx flow.Context) error { - client, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer client.Close() - - emptyOpt := map[string]string{} - - res, err := client.GetBulkSecret(ctx, secretStoreName, emptyOpt) - assert.NoError(ctx.T, err) - assert.NotNil(ctx.T, res) - assert.NotEmpty(ctx.T, res) - - for k, v := range res { - ctx.Logf("💡 %s", k) - for i, j := range v { - ctx.Logf("💡\t %s : %s", i, j) - } - } - - return nil - } -} - -// -// Helper methods for checking component registration and availability of its features -// - -func testComponentFound(targetComponentName string, currentGrpcPort int) flow.Runnable { - return func(ctx flow.Context) error { - componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) - assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") - return nil - } -} - -// Due to https://github.com/dapr/dapr/issues/5487 we cannot perform negative tests -// for the component presence against the metadata registry. -// Instead, we turned testComponentNotFound into a simpler negative test that ensures a good key cannot be found -func testComponentNotFound(targetComponentName string, currentGrpcPort int) flow.Runnable { - // TODO(tmacam) once https://github.com/dapr/dapr/issues/5487 is fixed, uncomment the code bellow - return testSecretIsNotFound(currentGrpcPort, targetComponentName, "multiplekeyvaluessecret") - - //return func(ctx flow.Context) error { - // // Find the component - // componentFound, _ := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) - // assert.False(ctx.T, componentFound, "Component was expected to be missing but it was found.") - // return nil - //} -} - -func testComponentDoesNotHaveFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { - return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, false) -} - -func testComponentHasFeature(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature) flow.Runnable { - return testComponentAndFeaturePresence(currentGrpcPort, targetComponentName, targetCapability, true) -} - -func testComponentAndFeaturePresence(currentGrpcPort int, targetComponentName string, targetCapability secretstores.Feature, expectedToBeFound bool) flow.Runnable { - return func(ctx flow.Context) error { - componentFound, capabilities := getComponentCapabilities(ctx, currentGrpcPort, targetComponentName) - - assert.True(ctx.T, componentFound, "Component was expected to be found but it was missing.") - - targetCapabilityAsString := string(targetCapability) - // Find capability - capabilityFound := false - for _, cap := range capabilities { - if cap == targetCapabilityAsString { - capabilityFound = true - break - } - } - assert.Equal(ctx.T, expectedToBeFound, capabilityFound) - - return nil - } -} - -func getComponentCapabilities(ctx flow.Context, currentGrpcPort int, targetComponentName string) (found bool, capabilities []string) { - daprClient, err := client.NewClientWithPort(fmt.Sprint(currentGrpcPort)) - if err != nil { - panic(err) - } - defer daprClient.Close() - - clientCtx := context.Background() - - resp, err := daprClient.GrpcClient().GetMetadata(clientCtx, &empty.Empty{}) - assert.NoError(ctx.T, err) - assert.NotNil(ctx.T, resp) - assert.NotNil(ctx.T, resp.GetRegisteredComponents()) - - // Find the component - for _, component := range resp.GetRegisteredComponents() { - if component.GetName() == targetComponentName { - ctx.Logf("🩺 component found=%s", component) - return true, component.GetCapabilities() - } - } - return false, []string{} -} - -// -// Flow and test setup helpers -// - -func componentRuntimeOptions() []runtime.Option { - log := logger.NewLogger("dapr.components") - - secretStoreRegistry := secretstores_loader.NewRegistry() - secretStoreRegistry.Logger = log - secretStoreRegistry.RegisterComponent(vault.NewHashiCorpVaultSecretStore, "hashicorp.vault") - - return []runtime.Option{ - runtime.WithSecretStores(secretStoreRegistry), - } -} - -func GetCurrentGRPCAndHTTPPort(t *testing.T) (int, int) { - ports, err := dapr_testing.GetFreePorts(2) - assert.NoError(t, err) - - currentGrpcPort := ports[0] - currentHttpPort := ports[1] - - return currentGrpcPort, currentHttpPort -} - -// -// Helper functions for asserting error messages during component initialization -// -// These can be exported to their own module. -// Do notice that they have side effects: using more than one in a single -// flow will cause only the latest to work. Perhaps this functionality -// (dapr.runtime log capture) could be baked into flows themselves? -// -// Also: this is not thread-safe nor concurrent safe: only one test -// can be run at a time to ensure deterministic capture of dapr.runtime output. - -type initErrorChecker func(ctx flow.Context, errorLine string) error - -func captureLogsAndCheckInitErrors(checker initErrorChecker) flow.Runnable { - // Setup log capture - logCaptor := &bytes.Buffer{} - runtimeLogger := logger.NewLogger("dapr.runtime") - runtimeLogger.SetOutput(io.MultiWriter(os.Stdout, logCaptor)) - - // Stop log capture, reset buffer just for good mesure - cleanup := func() { - logCaptor.Reset() - runtimeLogger.SetOutput(os.Stdout) - } - - grepInitErrorFromLogs := func() (string, error) { - errorMarker := []byte("INIT_COMPONENT_FAILURE") - scanner := bufio.NewScanner(logCaptor) - for scanner.Scan() { - if err := scanner.Err(); err != nil { - return "", err - } - if bytes.Contains(scanner.Bytes(), errorMarker) { - return scanner.Text(), nil - } - } - return "", scanner.Err() - } - - // Wraps the our initErrorChecker with cleanup and error-grepping logic so we only care about the - // log error - return func(ctx flow.Context) error { - defer cleanup() - - errorLine, err := grepInitErrorFromLogs() - if err != nil { - return err - } - ctx.Logf("👀 errorLine: %s", errorLine) - - return checker(ctx, errorLine) - } -} - -func assertNoInitializationErrorsForComponent(componentName string) flow.Runnable { - checker := func(ctx flow.Context, errorLine string) error { - componentFailedToInitialize := strings.Contains(errorLine, componentName) - assert.False(ctx.T, componentFailedToInitialize, - "Found component name mentioned in an component initialization error message: %s", errorLine) - - return nil - } - - return captureLogsAndCheckInitErrors(checker) -} - -func assertInitializationFailedWithErrorsForComponent(componentName string, additionalSubStringsToMatch ...string) flow.Runnable { - checker := func(ctx flow.Context, errorLine string) error { - assert.NotEmpty(ctx.T, errorLine, "Expected a component initialization error message but none found") - assert.Contains(ctx.T, errorLine, componentName, - "Expected to find component '%s' mentioned in error message but found none: %s", componentName, errorLine) - - for _, subString := range additionalSubStringsToMatch { - assert.Contains(ctx.T, errorLine, subString, - "Expected to find '%s' mentioned in error message but found none: %s", componentName, errorLine) - } - - return nil - } - - return captureLogsAndCheckInitErrors(checker) -} - -// -// Helper functions for common tests for happy case, init-but-does-not-work and fails-initialization tests -// These test re-use the same seed secrets. They aim to check how certain flags break or keep vault working -// instead of verifying some specific tha change key retrieval behavior. -// -// Those tests require a `/` structure. - -type commonFlowSettings struct { - t *testing.T - currentGrpcPort int - currentHttpPort int - secretStoreComponentPathBase string - componentNamePrefix string -} - -func NewFlowSettings(t *testing.T) *commonFlowSettings { - res := commonFlowSettings{} - res.t = t - res.currentGrpcPort, res.currentHttpPort = GetCurrentGRPCAndHTTPPort(t) - return &res -} - -func createPositiveTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool) { - componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) - componentName := fs.componentNamePrefix + componentSuffix - - dockerComposeClusterYAML := defaultDockerComposeClusterYAML - if useCustomDockerCompose { - dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") - } - - flow.New(fs.t, flowDescription). - Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). - Step("Waiting for component to start...", flow.Sleep(5*time.Second)). - Step(sidecar.Run(sidecarName, - embedded.WithoutApp(), - embedded.WithComponentsPath(componentPath), - embedded.WithDaprGRPCPort(fs.currentGrpcPort), - embedded.WithDaprHTTPPort(fs.currentHttpPort), - componentRuntimeOptions(), - )). - Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). - Step("Test that the default secret is found", testDefaultSecretIsFound(fs.currentGrpcPort, componentName)). - Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). - Run() -} - -func createInitSucceedsButComponentFailsFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, useCustomDockerCompose bool, initErrorCodes ...string) { - componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) - componentName := fs.componentNamePrefix + componentSuffix - - dockerComposeClusterYAML := defaultDockerComposeClusterYAML - if useCustomDockerCompose { - dockerComposeClusterYAML = filepath.Join(componentPath, "docker-compose-hashicorp-vault.yml") - } - - flow.New(fs.t, flowDescription). - Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). - Step("Waiting for component to start...", flow.Sleep(5*time.Second)). - Step(sidecar.Run(sidecarName, - embedded.WithoutApp(), - embedded.WithComponentsPath(componentPath), - embedded.WithDaprGRPCPort(fs.currentGrpcPort), - embedded.WithDaprHTTPPort(fs.currentHttpPort), - componentRuntimeOptions(), - )). - Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - Step("✅Verify component is registered", testComponentFound(componentName, fs.currentGrpcPort)). - Step("Verify no errors regarding component initialization", assertNoInitializationErrorsForComponent(componentPath)). - Step("🛑Verify component does not work", testComponentIsNotWorking(componentName, fs.currentGrpcPort)). - Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). - Run() -} - -func createNegativeTestFlow(fs *commonFlowSettings, flowDescription string, componentSuffix string, initErrorCodes ...string) { - componentPath := filepath.Join(fs.secretStoreComponentPathBase, componentSuffix) - componentName := fs.componentNamePrefix + componentSuffix - dockerComposeClusterYAML := defaultDockerComposeClusterYAML - - flow.New(fs.t, flowDescription). - Step(dockercompose.Run(dockerComposeProjectName, dockerComposeClusterYAML)). - Step("Waiting for component to start...", flow.Sleep(5*time.Second)). - Step(sidecar.Run(sidecarName, - embedded.WithoutApp(), - embedded.WithComponentsPath(componentPath), - embedded.WithDaprGRPCPort(fs.currentGrpcPort), - embedded.WithDaprHTTPPort(fs.currentHttpPort), - componentRuntimeOptions(), - )). - Step("Waiting for component to load...", flow.Sleep(5*time.Second)). - // TODO(tmacam) FIX https://github.com/dapr/dapr/issues/5487 - Step("🛑Verify component is NOT registered", testComponentNotFound(componentName, fs.currentGrpcPort)). - Step("Verify initialization error reported for component", assertInitializationFailedWithErrorsForComponent(componentName, initErrorCodes...)). - Step("🐞😱 Bug dependant behavior - test component is actually registered", testComponentFound(componentName, fs.currentGrpcPort)). - Step("Stop HashiCorp Vault server", dockercompose.Stop(dockerComposeProjectName, dockerComposeClusterYAML)). - Run() -} From cdac8123f3805eddb43d2d75291a68e0c19b1643 Mon Sep 17 00:00:00 2001 From: Tiago Alves Macambira Date: Mon, 28 Nov 2022 17:39:59 -0800 Subject: [PATCH 14/22] Small fixes (documentation, comments) Signed-off-by: Tiago Alves Macambira --- .../hashicorp/vault/components/caFamily/README.md | 1 + .../customSecretsPath/docker-compose-hashicorp-vault.yml | 4 +--- .../components/versioning/docker-compose-hashicorp-vault.yml | 5 +---- .../secretstores/hashicorp/vault/secret_helpers.go | 5 +++-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md b/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md index 708bd2bd7..830a668ba 100644 --- a/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md +++ b/tests/certification/secretstores/hashicorp/vault/components/caFamily/README.md @@ -20,6 +20,7 @@ Besides `-dev-tls`, we also instruct vault to use a configuration that defines a We use this certificate we generated to assist with the validation of `caPem`, `caCert`, `caPath`, `skipValidate` and `tlsServerName` flags. All of these refer to the same certificate. Testing `caPem` is a bit special in that it needs the certificate inlined in the component YAML file. A Makefile is included here in order to document and to ease re-generation of the certificate and keys. It will also re-generate the `caPem`-dependent component YAML, so one does not have to remember updating it whenever the certificate is updated or regenerated. +As a matter of fact, our code does not ship with any of these certificates. Instead, this Makefile is invoked at the begging on `TestCaFamilyOfFields` test. # Misc. references diff --git a/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml index 83a405fb3..ef4244434 100644 --- a/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml +++ b/tests/certification/secretstores/hashicorp/vault/components/enginePath/customSecretsPath/docker-compose-hashicorp-vault.yml @@ -28,10 +28,8 @@ services: - hashicorp_vault environment: VAULT_TOKEN : *VAULT_TOKEN - # We are using HTTPS VAULT_ADDR: http://hashicorp_vault:8200/ - VAULT_SKIP_VERIFY: 'true' volumes: - .:/setup:ro - entrypoint: /setup/setup-hashicorp-vault-secrets.sh + entrypoint: /setup/setup-hashicorp-vault-secrets.sh # <<< Use our custom secret seeder for the enginePath/customSecretsPath diff --git a/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml b/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml index fd7620371..bdcf03479 100644 --- a/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml +++ b/tests/certification/secretstores/hashicorp/vault/components/versioning/docker-compose-hashicorp-vault.yml @@ -20,7 +20,6 @@ services: VAULT_DEV_LISTEN_ADDRESS: "0.0.0.0:8200" VAULT_DEV_ROOT_TOKEN_ID: *VAULT_TOKEN - # We define a aux. service to seed the expected conformance secrets to vault seed_conformance_secrets: image: *VAULT_DOCKER_IMAGE @@ -28,10 +27,8 @@ services: - hashicorp_vault environment: VAULT_TOKEN : *VAULT_TOKEN - # We are using HTTPS VAULT_ADDR: http://hashicorp_vault:8200/ - VAULT_SKIP_VERIFY: 'true' volumes: - .:/setup:ro - entrypoint: /setup/seed-secret-with-multiple-versions.sh + entrypoint: /setup/seed-secret-with-multiple-versions.sh # <<< Use our custom secret seeder for the versioning test diff --git a/tests/certification/secretstores/hashicorp/vault/secret_helpers.go b/tests/certification/secretstores/hashicorp/vault/secret_helpers.go index 61e6bf027..94435f7fd 100644 --- a/tests/certification/secretstores/hashicorp/vault/secret_helpers.go +++ b/tests/certification/secretstores/hashicorp/vault/secret_helpers.go @@ -15,6 +15,7 @@ package vault_test import ( "fmt" + "github.com/dapr/components-contrib/tests/certification/flow" "github.com/dapr/go-sdk/client" "github.com/stretchr/testify/assert" @@ -95,9 +96,9 @@ func testGetBulkSecretsWorksAndFoundKeys(currentGrpcPort int, secretStoreName st assert.NotEmpty(ctx.T, res) for k, v := range res { - ctx.Logf("💡 %s", k) + ctx.Logf("Secret %s", k) for i, j := range v { - ctx.Logf("💡\t %s : %s", i, j) + ctx.Logf("\t key-value pair: %s : %s", i, j) } } From 46fabfa0fec06a51f479c948325e35a234536aa3 Mon Sep 17 00:00:00 2001 From: Ryan Lettieri <67934986+RyanLettieri@users.noreply.github.com> Date: Tue, 29 Nov 2022 10:35:48 -0700 Subject: [PATCH 15/22] Creation of Certification Test for CockroachDB (#2222) * First commit of cockroachDB cert test but it has some errors when stopping/starting container Signed-off-by: Ryan Lettieri * Creation of CockroachDB certification test Signed-off-by: Ryan Lettieri * Removing ping function from cockroachDB deleteValue func Signed-off-by: Ryan Lettieri * Spelling mistake and moving Ping function in cockroachDB into Init method Signed-off-by: Ryan Lettieri * First set of updates for cockroachDB cert PR Signed-off-by: Ryan Lettieri * More updates to cockroachDB cert test Signed-off-by: Ryan Lettieri * Lint fix for cockrochdb Signed-off-by: Ryan Lettieri * Fixes to go.mod and go.som files for cockroachDB Signed-off-by: Ryan Lettieri * Renaming variable for number of connection retry attempts Signed-off-by: Ryan Lettieri * Removing ttl from cockroach metadata in test Signed-off-by: Ryan Lettieri * Updating go.mod files to master and updating retry in cockroachDB Signed-off-by: Ryan Lettieri Signed-off-by: Ryan Lettieri Co-authored-by: Ryan Lettieri Co-authored-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> Co-authored-by: Dapr Bot <56698301+dapr-bot@users.noreply.github.com> --- .github/workflows/certification.yml | 1 + state/cockroachdb/cockroachdb_access.go | 45 +- .../bindings/alicloud/dubbo/go.mod | 3 +- .../bindings/alicloud/dubbo/go.sum | 1 + .../bindings/alicloud/nacos/go.mod | 3 +- .../bindings/alicloud/nacos/go.sum | 1 + .../bindings/azure/blobstorage/go.mod | 3 +- .../bindings/azure/blobstorage/go.sum | 1 + .../bindings/azure/cosmosdb/go.mod | 3 +- .../bindings/azure/cosmosdb/go.sum | 1 + .../bindings/azure/eventhubs/go.mod | 3 +- .../bindings/azure/eventhubs/go.sum | 1 + .../bindings/azure/servicebusqueues/go.mod | 3 +- .../bindings/azure/servicebusqueues/go.sum | 1 + .../bindings/azure/storagequeues/go.mod | 3 +- .../bindings/azure/storagequeues/go.sum | 1 + tests/certification/bindings/kafka/go.mod | 3 +- tests/certification/bindings/kafka/go.sum | 1 + .../bindings/localstorage/go.mod | 3 +- .../bindings/localstorage/go.sum | 1 + tests/certification/bindings/postgres/go.mod | 3 +- tests/certification/bindings/postgres/go.sum | 1 + tests/certification/bindings/rabbitmq/go.mod | 3 +- tests/certification/bindings/rabbitmq/go.sum | 1 + tests/certification/bindings/redis/go.mod | 3 +- tests/certification/bindings/redis/go.sum | 1 + tests/certification/embedded/embedded.go | 4 +- tests/certification/go.mod | 3 +- tests/certification/go.sum | 1 + .../pubsub/azure/eventhubs/go.mod | 3 +- .../pubsub/azure/eventhubs/go.sum | 1 + .../pubsub/azure/servicebus/topics/go.mod | 3 +- .../pubsub/azure/servicebus/topics/go.sum | 1 + tests/certification/pubsub/kafka/go.mod | 3 +- tests/certification/pubsub/kafka/go.sum | 1 + tests/certification/pubsub/mqtt/go.mod | 3 +- tests/certification/pubsub/mqtt/go.sum | 1 + tests/certification/pubsub/rabbitmq/go.mod | 3 +- tests/certification/pubsub/rabbitmq/go.sum | 1 + .../secretstores/azure/keyvault/go.mod | 3 +- .../secretstores/azure/keyvault/go.sum | 1 + .../secretstores/hashicorp/vault/go.mod | 3 +- .../secretstores/hashicorp/vault/go.sum | 1 + .../secretstores/local/env/go.mod | 3 +- .../secretstores/local/env/go.sum | 1 + .../secretstores/local/file/go.mod | 3 +- .../secretstores/local/file/go.sum | 1 + .../state/azure/blobstorage/go.mod | 3 +- .../state/azure/blobstorage/go.sum | 1 + .../certification/state/azure/cosmosdb/go.mod | 3 +- .../certification/state/azure/cosmosdb/go.sum | 1 + .../state/azure/tablestorage/go.mod | 3 +- .../state/azure/tablestorage/go.sum | 1 + tests/certification/state/cassandra/go.mod | 3 +- tests/certification/state/cassandra/go.sum | 1 + .../certification/state/cockroachdb/README.md | 42 + .../state/cockroachdb/cockroachdb_test.go | 271 ++++++ .../components/standard/cockroachdb.yaml | 17 + .../state/cockroachdb/config.yaml | 6 + .../state/cockroachdb/docker-compose.yml | 21 + tests/certification/state/cockroachdb/go.mod | 146 +++ tests/certification/state/cockroachdb/go.sum | 917 ++++++++++++++++++ tests/certification/state/memcached/go.mod | 3 +- tests/certification/state/memcached/go.sum | 1 + tests/certification/state/mongodb/go.mod | 3 +- tests/certification/state/mongodb/go.sum | 1 + tests/certification/state/mysql/go.mod | 3 +- tests/certification/state/mysql/go.sum | 1 + tests/certification/state/postgresql/go.mod | 3 +- tests/certification/state/postgresql/go.sum | 1 + .../state/postgresql/postgresql_test.go | 5 +- tests/certification/state/redis/go.mod | 3 +- tests/certification/state/redis/go.sum | 1 + tests/certification/state/sqlserver/go.mod | 3 +- tests/certification/state/sqlserver/go.sum | 1 + 75 files changed, 1561 insertions(+), 42 deletions(-) create mode 100644 tests/certification/state/cockroachdb/README.md create mode 100644 tests/certification/state/cockroachdb/cockroachdb_test.go create mode 100644 tests/certification/state/cockroachdb/components/standard/cockroachdb.yaml create mode 100644 tests/certification/state/cockroachdb/config.yaml create mode 100644 tests/certification/state/cockroachdb/docker-compose.yml create mode 100644 tests/certification/state/cockroachdb/go.mod create mode 100644 tests/certification/state/cockroachdb/go.sum diff --git a/.github/workflows/certification.yml b/.github/workflows/certification.yml index dfa2228dc..80f4dd140 100644 --- a/.github/workflows/certification.yml +++ b/.github/workflows/certification.yml @@ -53,6 +53,7 @@ jobs: - pubsub.mqtt - state.mongodb - state.redis + - state.cockroachdb - state.postgresql - state.cassandra - state.memcached diff --git a/state/cockroachdb/cockroachdb_access.go b/state/cockroachdb/cockroachdb_access.go index 6fdb454fc..b05553341 100644 --- a/state/cockroachdb/cockroachdb_access.go +++ b/state/cockroachdb/cockroachdb_access.go @@ -15,11 +15,13 @@ package cockroachdb import ( "database/sql" + "database/sql/driver" "encoding/base64" "encoding/json" "errors" "fmt" "strconv" + "time" "github.com/dapr/components-contrib/metadata" "github.com/dapr/components-contrib/state" @@ -27,15 +29,17 @@ import ( "github.com/dapr/components-contrib/state/utils" "github.com/dapr/kit/logger" "github.com/dapr/kit/ptr" + "github.com/dapr/kit/retry" // Blank import for the underlying PostgreSQL driver. _ "github.com/jackc/pgx/v5/stdlib" ) const ( - connectionStringKey = "connectionString" - errMissingConnectionString = "missing connection string" - tableName = "state" + connectionStringKey = "connectionString" + errMissingConnectionString = "missing connection string" + tableName = "state" + defaultMaxConnectionAttempts = 5 // A bad driver connection error can occur inside the sql code so this essentially allows for more retries since the sql code does not allow that to be changed ) // cockroachDBAccess implements dbaccess. @@ -47,8 +51,9 @@ type cockroachDBAccess struct { } type cockroachDBMetadata struct { - ConnectionString string - TableName string + ConnectionString string + TableName string + MaxConnectionAttempts *int } // newCockroachDBAccess creates a new instance of cockroachDBAccess. @@ -109,6 +114,12 @@ func (p *cockroachDBAccess) Init(metadata state.Metadata) error { return err } + // Ensure that a connection to the database is actually established + err = p.Ping() + if err != nil { + return err + } + return nil } @@ -188,6 +199,7 @@ func (p *cockroachDBAccess) BulkSet(req []state.SetRequest) error { // Get returns data from the database. If data does not exist for the key an empty state.GetResponse will be returned. func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, error) { p.logger.Debug("Getting state value from CockroachDB") + if req.Key == "" { return nil, fmt.Errorf("missing key in get operation") } @@ -236,6 +248,7 @@ func (p *cockroachDBAccess) Get(req *state.GetRequest) (*state.GetResponse, erro // Delete removes an item from the state store. func (p *cockroachDBAccess) Delete(req *state.DeleteRequest) error { p.logger.Debug("Deleting state value from CockroachDB") + if req.Key == "" { return fmt.Errorf("missing key in delete operation") } @@ -386,7 +399,27 @@ func (p *cockroachDBAccess) Query(req *state.QueryRequest) (*state.QueryResponse // Ping implements database ping. func (p *cockroachDBAccess) Ping() error { - return p.db.Ping() + retryCount := defaultMaxConnectionAttempts + if p.metadata.MaxConnectionAttempts != nil && *p.metadata.MaxConnectionAttempts >= 0 { + retryCount = *p.metadata.MaxConnectionAttempts + } + config := retry.DefaultConfig() + config.Policy = retry.PolicyExponential + config.MaxInterval = 100 * time.Millisecond + config.MaxRetries = int64(retryCount) + backoff := config.NewBackOff() + + return retry.NotifyRecover(func() error { + err := p.db.Ping() + if errors.Is(err, driver.ErrBadConn) { + return fmt.Errorf("error when attempting to establish connection with cockroachDB: %v", err) + } + return nil + }, backoff, func(err error, _ time.Duration) { + p.logger.Debugf("Could not establish connection with cockroachDB. Retrying...: %v", err) + }, func() { + p.logger.Debug("Successfully established connection with cockroachDB after it previously failed") + }) } // Close implements io.Close. diff --git a/tests/certification/bindings/alicloud/dubbo/go.mod b/tests/certification/bindings/alicloud/dubbo/go.mod index 3f16003fa..c642f6f20 100644 --- a/tests/certification/bindings/alicloud/dubbo/go.mod +++ b/tests/certification/bindings/alicloud/dubbo/go.mod @@ -7,7 +7,7 @@ require ( github.com/apache/dubbo-go-hessian2 v1.11.3 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -103,6 +103,7 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/pelletier/go-toml v1.9.4 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/alicloud/dubbo/go.sum b/tests/certification/bindings/alicloud/dubbo/go.sum index 29228ce8d..ef135aca1 100644 --- a/tests/certification/bindings/alicloud/dubbo/go.sum +++ b/tests/certification/bindings/alicloud/dubbo/go.sum @@ -696,6 +696,7 @@ github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhEC github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= diff --git a/tests/certification/bindings/alicloud/nacos/go.mod b/tests/certification/bindings/alicloud/nacos/go.mod index 085f76367..13774365e 100644 --- a/tests/certification/bindings/alicloud/nacos/go.mod +++ b/tests/certification/bindings/alicloud/nacos/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/nacos-group/nacos-sdk-go/v2 v2.1.2 @@ -78,6 +78,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/alicloud/nacos/go.sum b/tests/certification/bindings/alicloud/nacos/go.sum index ff48f8312..1bc9fceda 100644 --- a/tests/certification/bindings/alicloud/nacos/go.sum +++ b/tests/certification/bindings/alicloud/nacos/go.sum @@ -397,6 +397,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/bindings/azure/blobstorage/go.mod b/tests/certification/bindings/azure/blobstorage/go.mod index 39df468c9..9e9befe77 100644 --- a/tests/certification/bindings/azure/blobstorage/go.mod +++ b/tests/certification/bindings/azure/blobstorage/go.mod @@ -6,7 +6,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -96,6 +96,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/azure/blobstorage/go.sum b/tests/certification/bindings/azure/blobstorage/go.sum index 0200c2d33..d394b07e3 100644 --- a/tests/certification/bindings/azure/blobstorage/go.sum +++ b/tests/certification/bindings/azure/blobstorage/go.sum @@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/azure/cosmosdb/go.mod b/tests/certification/bindings/azure/cosmosdb/go.mod index 886fc97c8..d4982bd3b 100644 --- a/tests/certification/bindings/azure/cosmosdb/go.mod +++ b/tests/certification/bindings/azure/cosmosdb/go.mod @@ -6,7 +6,7 @@ require ( github.com/a8m/documentdb v1.3.1-0.20220405205223-5b41ba0aaeb1 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -98,6 +98,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/azure/cosmosdb/go.sum b/tests/certification/bindings/azure/cosmosdb/go.sum index 82ff71cf6..0e0926256 100644 --- a/tests/certification/bindings/azure/cosmosdb/go.sum +++ b/tests/certification/bindings/azure/cosmosdb/go.sum @@ -459,6 +459,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/azure/eventhubs/go.mod b/tests/certification/bindings/azure/eventhubs/go.mod index e700c189c..0b4cbbe0a 100644 --- a/tests/certification/bindings/azure/eventhubs/go.mod +++ b/tests/certification/bindings/azure/eventhubs/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -104,6 +104,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/azure/eventhubs/go.sum b/tests/certification/bindings/azure/eventhubs/go.sum index 2ffcf1e77..01b5653a3 100644 --- a/tests/certification/bindings/azure/eventhubs/go.sum +++ b/tests/certification/bindings/azure/eventhubs/go.sum @@ -479,6 +479,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/azure/servicebusqueues/go.mod b/tests/certification/bindings/azure/servicebusqueues/go.mod index 3f276e42d..02fd6594c 100644 --- a/tests/certification/bindings/azure/servicebusqueues/go.mod +++ b/tests/certification/bindings/azure/servicebusqueues/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -100,6 +100,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/azure/servicebusqueues/go.sum b/tests/certification/bindings/azure/servicebusqueues/go.sum index aab8e8327..75fb02275 100644 --- a/tests/certification/bindings/azure/servicebusqueues/go.sum +++ b/tests/certification/bindings/azure/servicebusqueues/go.sum @@ -462,6 +462,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/azure/storagequeues/go.mod b/tests/certification/bindings/azure/storagequeues/go.mod index 6698ef29e..38daa144c 100644 --- a/tests/certification/bindings/azure/storagequeues/go.mod +++ b/tests/certification/bindings/azure/storagequeues/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -97,6 +97,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/azure/storagequeues/go.sum b/tests/certification/bindings/azure/storagequeues/go.sum index 9776a9019..3ff221002 100644 --- a/tests/certification/bindings/azure/storagequeues/go.sum +++ b/tests/certification/bindings/azure/storagequeues/go.sum @@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/kafka/go.mod b/tests/certification/bindings/kafka/go.mod index 39c70e7c5..d72b3a0c8 100644 --- a/tests/certification/bindings/kafka/go.mod +++ b/tests/certification/bindings/kafka/go.mod @@ -7,7 +7,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -87,6 +87,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/bindings/kafka/go.sum b/tests/certification/bindings/kafka/go.sum index 1f2b81f1d..b44b743f2 100644 --- a/tests/certification/bindings/kafka/go.sum +++ b/tests/certification/bindings/kafka/go.sum @@ -409,6 +409,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/bindings/localstorage/go.mod b/tests/certification/bindings/localstorage/go.mod index ee5a3a95d..db673b92b 100644 --- a/tests/certification/bindings/localstorage/go.mod +++ b/tests/certification/bindings/localstorage/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-00010101000000-000000000000 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -75,6 +75,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/localstorage/go.sum b/tests/certification/bindings/localstorage/go.sum index 0d8e9d344..e3d0de29b 100644 --- a/tests/certification/bindings/localstorage/go.sum +++ b/tests/certification/bindings/localstorage/go.sum @@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/bindings/postgres/go.mod b/tests/certification/bindings/postgres/go.mod index 42f2f4519..288a7e0aa 100644 --- a/tests/certification/bindings/postgres/go.mod +++ b/tests/certification/bindings/postgres/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/lib/pq v1.10.7 @@ -79,6 +79,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/postgres/go.sum b/tests/certification/bindings/postgres/go.sum index 752fd2a1e..d147d6e19 100644 --- a/tests/certification/bindings/postgres/go.sum +++ b/tests/certification/bindings/postgres/go.sum @@ -389,6 +389,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/bindings/rabbitmq/go.mod b/tests/certification/bindings/rabbitmq/go.mod index 075e437e5..852cd314f 100644 --- a/tests/certification/bindings/rabbitmq/go.mod +++ b/tests/certification/bindings/rabbitmq/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/rabbitmq/amqp091-go v1.5.0 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/rabbitmq/go.sum b/tests/certification/bindings/rabbitmq/go.sum index a4eff7e01..84bbe9fbe 100644 --- a/tests/certification/bindings/rabbitmq/go.sum +++ b/tests/certification/bindings/rabbitmq/go.sum @@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/bindings/redis/go.mod b/tests/certification/bindings/redis/go.mod index 40e8b93ba..eff24118a 100644 --- a/tests/certification/bindings/redis/go.mod +++ b/tests/certification/bindings/redis/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220908221803-2b5650c2faa4 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/go-redis/redis/v8 v8.11.5 @@ -76,6 +76,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/bindings/redis/go.sum b/tests/certification/bindings/redis/go.sum index eb9fe226b..657d19e28 100644 --- a/tests/certification/bindings/redis/go.sum +++ b/tests/certification/bindings/redis/go.sum @@ -385,6 +385,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/embedded/embedded.go b/tests/certification/embedded/embedded.go index 4a66187a7..071cafb57 100644 --- a/tests/certification/embedded/embedded.go +++ b/tests/certification/embedded/embedded.go @@ -22,13 +22,13 @@ import ( global_config "github.com/dapr/dapr/pkg/config" env "github.com/dapr/dapr/pkg/config/env" "github.com/dapr/dapr/pkg/cors" - "github.com/dapr/dapr/pkg/grpc" "github.com/dapr/dapr/pkg/modes" "github.com/dapr/dapr/pkg/operator/client" "github.com/dapr/dapr/pkg/resiliency" "github.com/dapr/dapr/pkg/runtime" "github.com/dapr/dapr/pkg/runtime/security" "github.com/dapr/kit/logger" + "github.com/phayes/freeport" ) const ( @@ -138,7 +138,7 @@ func NewRuntime(appID string, opts ...Option) (*runtime.DaprRuntime, *runtime.Co } if runtimeConfig.InternalGRPCPort == 0 { - if runtimeConfig.InternalGRPCPort, err = grpc.GetFreePort(); err != nil { + if runtimeConfig.InternalGRPCPort, err = freeport.GetFreePort(); err != nil { return nil, nil, err } } diff --git a/tests/certification/go.mod b/tests/certification/go.mod index bb8662ceb..f620600f5 100644 --- a/tests/certification/go.mod +++ b/tests/certification/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/go-cmp v0.5.9 @@ -134,6 +134,7 @@ require ( require ( github.com/cenkalti/backoff/v4 v4.1.3 + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/tylertreat/comcast v1.0.1 ) diff --git a/tests/certification/go.sum b/tests/certification/go.sum index 113c706b3..e06085a52 100644 --- a/tests/certification/go.sum +++ b/tests/certification/go.sum @@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/pubsub/azure/eventhubs/go.mod b/tests/certification/pubsub/azure/eventhubs/go.mod index a49ec755b..ee7111901 100644 --- a/tests/certification/pubsub/azure/eventhubs/go.mod +++ b/tests/certification/pubsub/azure/eventhubs/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v1.4.0-rc2 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -104,6 +104,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/pubsub/azure/eventhubs/go.sum b/tests/certification/pubsub/azure/eventhubs/go.sum index bba9d03a7..c03b2f154 100644 --- a/tests/certification/pubsub/azure/eventhubs/go.sum +++ b/tests/certification/pubsub/azure/eventhubs/go.sum @@ -479,6 +479,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/pubsub/azure/servicebus/topics/go.mod b/tests/certification/pubsub/azure/servicebus/topics/go.mod index eaf00930e..e52b273f0 100644 --- a/tests/certification/pubsub/azure/servicebus/topics/go.mod +++ b/tests/certification/pubsub/azure/servicebus/topics/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -100,6 +100,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/pubsub/azure/servicebus/topics/go.sum b/tests/certification/pubsub/azure/servicebus/topics/go.sum index aab8e8327..75fb02275 100644 --- a/tests/certification/pubsub/azure/servicebus/topics/go.sum +++ b/tests/certification/pubsub/azure/servicebus/topics/go.sum @@ -462,6 +462,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/pubsub/kafka/go.mod b/tests/certification/pubsub/kafka/go.mod index 270a76518..e5bbc93e0 100644 --- a/tests/certification/pubsub/kafka/go.mod +++ b/tests/certification/pubsub/kafka/go.mod @@ -7,7 +7,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220519061249-c2cb1dad5bb0 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/google/uuid v1.3.0 @@ -87,6 +87,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/pubsub/kafka/go.sum b/tests/certification/pubsub/kafka/go.sum index 1f2b81f1d..b44b743f2 100644 --- a/tests/certification/pubsub/kafka/go.sum +++ b/tests/certification/pubsub/kafka/go.sum @@ -409,6 +409,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/pubsub/mqtt/go.mod b/tests/certification/pubsub/mqtt/go.mod index d05b98913..a62f8408f 100644 --- a/tests/certification/pubsub/mqtt/go.mod +++ b/tests/certification/pubsub/mqtt/go.mod @@ -6,7 +6,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v1.4.0-rc2 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/eclipse/paho.mqtt.golang v1.4.2 @@ -79,6 +79,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/pubsub/mqtt/go.sum b/tests/certification/pubsub/mqtt/go.sum index b8ad6725c..b856fb9cc 100644 --- a/tests/certification/pubsub/mqtt/go.sum +++ b/tests/certification/pubsub/mqtt/go.sum @@ -388,6 +388,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/pubsub/rabbitmq/go.mod b/tests/certification/pubsub/rabbitmq/go.mod index 8135796bf..7ed2b6880 100644 --- a/tests/certification/pubsub/rabbitmq/go.mod +++ b/tests/certification/pubsub/rabbitmq/go.mod @@ -6,7 +6,7 @@ require ( github.com/cenkalti/backoff/v4 v4.1.3 github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/rabbitmq/amqp091-go v1.5.0 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/pubsub/rabbitmq/go.sum b/tests/certification/pubsub/rabbitmq/go.sum index a4eff7e01..84bbe9fbe 100644 --- a/tests/certification/pubsub/rabbitmq/go.sum +++ b/tests/certification/pubsub/rabbitmq/go.sum @@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/secretstores/azure/keyvault/go.mod b/tests/certification/secretstores/azure/keyvault/go.mod index 50595d243..ae8ce1a62 100644 --- a/tests/certification/secretstores/azure/keyvault/go.mod +++ b/tests/certification/secretstores/azure/keyvault/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -97,6 +97,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/secretstores/azure/keyvault/go.sum b/tests/certification/secretstores/azure/keyvault/go.sum index 4fa12be75..f04fccff0 100644 --- a/tests/certification/secretstores/azure/keyvault/go.sum +++ b/tests/certification/secretstores/azure/keyvault/go.sum @@ -456,6 +456,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/secretstores/hashicorp/vault/go.mod b/tests/certification/secretstores/hashicorp/vault/go.mod index c35b32c21..80a65c5aa 100644 --- a/tests/certification/secretstores/hashicorp/vault/go.mod +++ b/tests/certification/secretstores/hashicorp/vault/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e // We require dapr/dapr#5208 merged + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 // We require dapr/dapr#5208 merged github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/golang/protobuf v1.5.2 @@ -74,6 +74,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/secretstores/hashicorp/vault/go.sum b/tests/certification/secretstores/hashicorp/vault/go.sum index 551dc9dff..b7055998c 100644 --- a/tests/certification/secretstores/hashicorp/vault/go.sum +++ b/tests/certification/secretstores/hashicorp/vault/go.sum @@ -379,6 +379,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/secretstores/local/env/go.mod b/tests/certification/secretstores/local/env/go.mod index 7eb46dd7c..8884d561c 100644 --- a/tests/certification/secretstores/local/env/go.mod +++ b/tests/certification/secretstores/local/env/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -74,6 +74,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/secretstores/local/env/go.sum b/tests/certification/secretstores/local/env/go.sum index 823b0c866..434e7f2ae 100644 --- a/tests/certification/secretstores/local/env/go.sum +++ b/tests/certification/secretstores/local/env/go.sum @@ -379,6 +379,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/secretstores/local/file/go.mod b/tests/certification/secretstores/local/file/go.mod index daaabeafd..f2e519b71 100644 --- a/tests/certification/secretstores/local/file/go.mod +++ b/tests/certification/secretstores/local/file/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -74,6 +74,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/secretstores/local/file/go.sum b/tests/certification/secretstores/local/file/go.sum index 823b0c866..434e7f2ae 100644 --- a/tests/certification/secretstores/local/file/go.sum +++ b/tests/certification/secretstores/local/file/go.sum @@ -379,6 +379,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/azure/blobstorage/go.mod b/tests/certification/state/azure/blobstorage/go.mod index 1caa631ff..381e48ec6 100644 --- a/tests/certification/state/azure/blobstorage/go.mod +++ b/tests/certification/state/azure/blobstorage/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -96,6 +96,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/state/azure/blobstorage/go.sum b/tests/certification/state/azure/blobstorage/go.sum index 0200c2d33..d394b07e3 100644 --- a/tests/certification/state/azure/blobstorage/go.sum +++ b/tests/certification/state/azure/blobstorage/go.sum @@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/state/azure/cosmosdb/go.mod b/tests/certification/state/azure/cosmosdb/go.mod index 44f1f6f01..074aade1a 100644 --- a/tests/certification/state/azure/cosmosdb/go.mod +++ b/tests/certification/state/azure/cosmosdb/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -97,6 +97,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/state/azure/cosmosdb/go.sum b/tests/certification/state/azure/cosmosdb/go.sum index e1969c129..cceb78629 100644 --- a/tests/certification/state/azure/cosmosdb/go.sum +++ b/tests/certification/state/azure/cosmosdb/go.sum @@ -456,6 +456,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/state/azure/tablestorage/go.mod b/tests/certification/state/azure/tablestorage/go.mod index b6a64984a..03fe8f8c3 100644 --- a/tests/certification/state/azure/tablestorage/go.mod +++ b/tests/certification/state/azure/tablestorage/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -96,6 +96,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/tests/certification/state/azure/tablestorage/go.sum b/tests/certification/state/azure/tablestorage/go.sum index 658835afc..54bfe7f73 100644 --- a/tests/certification/state/azure/tablestorage/go.sum +++ b/tests/certification/state/azure/tablestorage/go.sum @@ -454,6 +454,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/tests/certification/state/cassandra/go.mod b/tests/certification/state/cassandra/go.mod index 7d7293273..a40f94f60 100644 --- a/tests/certification/state/cassandra/go.mod +++ b/tests/certification/state/cassandra/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211026011813-36b75e9ae272 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/cassandra/go.sum b/tests/certification/state/cassandra/go.sum index e9734c081..4fd9c7ee9 100644 --- a/tests/certification/state/cassandra/go.sum +++ b/tests/certification/state/cassandra/go.sum @@ -391,6 +391,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/cockroachdb/README.md b/tests/certification/state/cockroachdb/README.md new file mode 100644 index 000000000..41fc558a8 --- /dev/null +++ b/tests/certification/state/cockroachdb/README.md @@ -0,0 +1,42 @@ +# CockroachDB State Store Certification + +The purpose of this module is to provide tests that certify the CockroachDB State Store as a stable component. + +## Test plan + +## Connection Test +* Verify the connection is established to CockroachDB. + * Create component spec. + * Run the component with docker-compose + * Run dapr application with component. + * Ensure that you have access to the queue and connection to the queue is established. + +## Basic Operations Test +* Verify that cockroachDB can save, retrieve, and delete states + * Save basic state information with a specified key + * Perform a Get Operation with that same key and ensure the the data previously written is retrieved + * Delete the state item + * Perform another Get Operation and verify that the data retreived is a nil byte array + + +## ETAG Test +* Verify cockroachDB Etag behavior + * Save state without an etag and ensure default etag (value of 1) is created + * Save state with a new, previously unsused etag and ensure that no item is updated + * Get state with etag of 1 and verify that our first written data is retrieved + * Overwrite the initial data through a Set operation with an etag value of 1 + * Run a Get Operation and verify that the previous Set operation was successful + +## Transactions Test +* Verify that cockroachDB can handle multiple opperations in a single request + * Save basic state information with a specified key + * Perform a Get Operation with that same key and ensure the the data previously written is retrieved + * Run a suite of set and delete requests + * Run a Get Operation on the data that should've been deleted from the Delete operation in the multi command and verify that the data no longer exists + * Retrieve data written from set requests and verify the data was correctly written + +## Restart Test +* Verify that cockroachDB can have state data persist after a restart + * Stop cockroachDB by calling a dockercompose stop command + * Start cockroachDB by calling a dockercompose start command + * Perform a Get Operation using a previously inserted key and verify that the data previously saved before the restart is returned \ No newline at end of file diff --git a/tests/certification/state/cockroachdb/cockroachdb_test.go b/tests/certification/state/cockroachdb/cockroachdb_test.go new file mode 100644 index 000000000..fbb7cda18 --- /dev/null +++ b/tests/certification/state/cockroachdb/cockroachdb_test.go @@ -0,0 +1,271 @@ +/* +Copyright 2021 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cockroachdb_test + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/dapr/components-contrib/state" + state_cockroach "github.com/dapr/components-contrib/state/cockroachdb" + "github.com/dapr/components-contrib/tests/certification/embedded" + "github.com/dapr/components-contrib/tests/certification/flow" + "github.com/dapr/components-contrib/tests/certification/flow/dockercompose" + "github.com/dapr/components-contrib/tests/certification/flow/sidecar" + state_loader "github.com/dapr/dapr/pkg/components/state" + "github.com/dapr/dapr/pkg/runtime" + dapr_testing "github.com/dapr/dapr/pkg/testing" + goclient "github.com/dapr/go-sdk/client" + "github.com/dapr/kit/logger" + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +const ( + sidecarNamePrefix = "cockroach-sidecar-" + dockerComposeYAML = "docker-compose.yml" + stateStoreName = "statestore" + certificationTestPrefix = "stable-certification-" + stateStoreNoConfigError = "error saving state: rpc error: code = FailedPrecondition desc = state store is not configured" +) + +func TestCockroach(t *testing.T) { + log := logger.NewLogger("dapr.components") + + stateStore := state_cockroach.New(log).(*state_cockroach.CockroachDB) + ports, err := dapr_testing.GetFreePorts(3) + assert.NoError(t, err) + + stateRegistry := state_loader.NewRegistry() + stateRegistry.Logger = log + stateRegistry.RegisterComponent(func(l logger.Logger) state.Store { + return stateStore + }, "cockroachdb") + + currentGrpcPort := ports[0] + currentHTTPPort := ports[1] + + // Generate a unique value for the key being inserted to ensure no conflicts occur + keyOne := uuid.New() + keyOneString := strings.Replace(keyOne.String(), "-", "", -1) + + basicTest := func(ctx flow.Context) error { + client, err := goclient.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer client.Close() + + err = stateStore.Ping() + assert.Equal(t, nil, err) + + err = client.SaveState(ctx, stateStoreName, certificationTestPrefix+"key1", []byte("certificationdata"), nil) + assert.NoError(t, err) + + // get state + item, err := client.GetState(ctx, stateStoreName, certificationTestPrefix+"key1", nil) + assert.NoError(t, err) + assert.Equal(t, "certificationdata", string(item.Value)) + + errUpdate := client.SaveState(ctx, stateStoreName, certificationTestPrefix+"key1", []byte("cockroachCertUpdate"), nil) + assert.NoError(t, errUpdate) + item, errUpdatedGet := client.GetState(ctx, stateStoreName, certificationTestPrefix+"key1", nil) + assert.NoError(t, errUpdatedGet) + assert.Equal(t, "cockroachCertUpdate", string(item.Value)) + + // delete state + err = client.DeleteState(ctx, stateStoreName, certificationTestPrefix+"key1", nil) + assert.NoError(t, err) + + // get state + item, errUpdatedGet = client.GetState(ctx, stateStoreName, certificationTestPrefix+"key1", nil) + assert.NoError(t, errUpdatedGet) + assert.Equal(t, []byte(nil), item.Value) + return nil + } + + // Check if TCP port is actually open + testGetAfterCockroachdbRestart := func(ctx flow.Context) error { + client, err := goclient.NewClientWithPort(fmt.Sprint(currentGrpcPort)) + if err != nil { + panic(err) + } + defer client.Close() + + err = stateStore.Ping() + assert.Equal(t, nil, err) + + resp, err := stateStore.Get(&state.GetRequest{ + Key: keyOneString, + }) + assert.NoError(t, err) + assert.Equal(t, "2", *resp.ETag) // 2 is returned since the previous etag value of "1" was incremented by 1 when the update occurred + assert.Equal(t, "\"Overwrite Success\"", string(resp.Data)) + + return nil + } + + //ETag test + eTagTest := func(ctx flow.Context) error { + etag1 := "1" + etag100 := "100" + + // Setting with nil etag will insert an item with an etag value of 1 unless there is a conflict + err := stateStore.Set(&state.SetRequest{ + Key: keyOneString, + Value: "v1", + }) + assert.NoError(t, err) + + // Setting with an etag wil do an update, not an insert so an error is expected since the etag of 100 is not present + err = stateStore.Set(&state.SetRequest{ + Key: keyOneString, + Value: "v3", + ETag: &etag100, + }) + assert.Equal(t, fmt.Errorf("no item was updated"), err) + + resp, err := stateStore.Get(&state.GetRequest{ + Key: keyOneString, + }) + assert.NoError(t, err) + assert.Equal(t, etag1, *resp.ETag) //1 is returned since the default when the new data is written is a value of 1 + assert.Equal(t, "\"v1\"", string(resp.Data)) //v1 is returned since it was the only item successfully inserted with the key of keyOneString + + // This will update the value stored in key K with "Overwrite Success" since the previously created etag has a value of 1 + // It will also increment the etag stored by a value of 1 + err = stateStore.Set(&state.SetRequest{ + Key: keyOneString, + Value: "Overwrite Success", + ETag: &etag1, + }) + assert.NoError(t, err) + + resp, err = stateStore.Get(&state.GetRequest{ + Key: keyOneString, + }) + assert.NoError(t, err) + assert.Equal(t, "2", *resp.ETag) //2 is returned since the previous etag value of "1" was incremented by 1 when the update occurred + assert.Equal(t, "\"Overwrite Success\"", string(resp.Data)) + + return nil + } + + // Transaction related test - also for Multi + transactionsTest := func(ctx flow.Context) error { + + // Set state to allow for a delete operation inside the multi list + err = stateStore.Set(&state.SetRequest{Key: certificationTestPrefix + "key1", Value: []byte("certificationdata")}) + assert.NoError(t, err) + + // get state + item, errUpdatedGet := stateStore.Get(&state.GetRequest{Key: certificationTestPrefix + "key1"}) + assert.NoError(t, errUpdatedGet) + assert.Equal(t, []byte("certificationdata"), item.Data) + + err = stateStore.Multi(&state.TransactionalStateRequest{ + Operations: []state.TransactionalStateOperation{ + { + Operation: state.Upsert, + Request: state.SetRequest{ + Key: "reqKey1", + Value: "reqVal1", + Metadata: map[string]string{}, + }, + }, + { + Operation: state.Upsert, + Request: state.SetRequest{ + Key: "reqKey2", + Value: "reqVal2", + Metadata: map[string]string{}, + }, + }, + { + Operation: state.Upsert, + Request: state.SetRequest{ + Key: "reqKey3", + Value: "reqVal3", + }, + }, + { + Operation: state.Upsert, + Request: state.SetRequest{ + Key: "reqKey1", + Value: "reqVal101", + Metadata: map[string]string{}, + }, + }, + { + Operation: state.Upsert, + Request: state.SetRequest{ + Key: "reqKey3", + Value: "reqVal103", + Metadata: map[string]string{}, + }, + }, + { + Operation: state.Delete, + Request: state.DeleteRequest{ + Key: certificationTestPrefix + "key1", + Metadata: map[string]string{}, + }, + }, + }, + }) + assert.Equal(t, nil, err) + + // get state + item, errUpdatedGet = stateStore.Get(&state.GetRequest{Key: certificationTestPrefix + "key1"}) + assert.NoError(t, errUpdatedGet) + assert.Equal(t, []byte(nil), item.Data) + + resp1, err := stateStore.Get(&state.GetRequest{ + Key: "reqKey1", + }) + assert.NoError(t, err) + assert.Equal(t, "2", *resp1.ETag) + assert.Equal(t, "\"reqVal101\"", string(resp1.Data)) + + resp3, err := stateStore.Get(&state.GetRequest{ + Key: "reqKey3", + }) + assert.NoError(t, err) + assert.Equal(t, "2", *resp3.ETag) + assert.Equal(t, "\"reqVal103\"", string(resp3.Data)) + return nil + } + + flow.New(t, "Connecting cockroachdb And Verifying majority of the tests here"). + Step(dockercompose.Run("cockroachdb", dockerComposeYAML)). + Step("Waiting for cockroachdb readiness", flow.Sleep(30*time.Second)). + Step(sidecar.Run(sidecarNamePrefix+"dockerDefault", + embedded.WithoutApp(), + embedded.WithDaprGRPCPort(currentGrpcPort), + embedded.WithDaprHTTPPort(currentHTTPPort), + embedded.WithComponentsPath("components/standard"), + runtime.WithStates(stateRegistry), + )). + Step("Run basic test", basicTest). + Step("Run eTag test", eTagTest). + Step("Run transactions test", transactionsTest). + Step("Stop cockroachdb server", dockercompose.Stop("cockroachdb", dockerComposeYAML, "cockroachdb")). + Step("Sleep after dockercompose stop", flow.Sleep(10*time.Second)). + Step("Start cockroachdb server", dockercompose.Start("cockroachdb", dockerComposeYAML, "cockroachdb")). + Step("wait for component to start", flow.Sleep(10*time.Second)). + Step("Get Values Saved Earlier And Not Expired, after cockroachdb restart", testGetAfterCockroachdbRestart). + Run() +} diff --git a/tests/certification/state/cockroachdb/components/standard/cockroachdb.yaml b/tests/certification/state/cockroachdb/components/standard/cockroachdb.yaml new file mode 100644 index 000000000..a1087752e --- /dev/null +++ b/tests/certification/state/cockroachdb/components/standard/cockroachdb.yaml @@ -0,0 +1,17 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.cockroachdb + metadata: + - name: cockroachdbHost + value: localhost:26257 + - name: cockroachdbPassword + value: "" + - name: initTimeout + value: 5m + - name: timeout + value: 20s + - name: connectionString + value: "host=localhost user=root port=26257 connect_timeout=10 database=dapr_test" \ No newline at end of file diff --git a/tests/certification/state/cockroachdb/config.yaml b/tests/certification/state/cockroachdb/config.yaml new file mode 100644 index 000000000..6c95e632f --- /dev/null +++ b/tests/certification/state/cockroachdb/config.yaml @@ -0,0 +1,6 @@ +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: keyvaultconfig +spec: + features: diff --git a/tests/certification/state/cockroachdb/docker-compose.yml b/tests/certification/state/cockroachdb/docker-compose.yml new file mode 100644 index 000000000..b8f3a7d27 --- /dev/null +++ b/tests/certification/state/cockroachdb/docker-compose.yml @@ -0,0 +1,21 @@ +version: '3.5' +services: + cockroachdb: + image: cockroachdb/cockroach:v21.2.3 + hostname: cockroachdb + command: start-single-node --cluster-name=single-node --logtostderr=WARNING --log-file-verbosity=WARNING --insecure + restart: always + security_opt: + - no-new-privileges + ports: + - "26257:26257" + + cockroachdb-init: + hostname: cockroachdb-init + image: timveil/cockroachdb-remote-client:latest + environment: + - COCKROACH_HOST=cockroachdb:26257 + - COCKROACH_INSECURE=true + - DATABASE_NAME=dapr_test + depends_on: + - cockroachdb diff --git a/tests/certification/state/cockroachdb/go.mod b/tests/certification/state/cockroachdb/go.mod new file mode 100644 index 000000000..9941f5365 --- /dev/null +++ b/tests/certification/state/cockroachdb/go.mod @@ -0,0 +1,146 @@ +module github.com/dapr/components-contrib/tests/certification/state/cockroachdb + +go 1.19 + +require ( + github.com/dapr/components-contrib v1.9.1 + github.com/dapr/components-contrib/tests/certification v0.0.0-20221111215803-c92827c3defc + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 + github.com/dapr/go-sdk v1.6.0 + github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f + github.com/google/uuid v1.3.0 + github.com/stretchr/testify v1.8.1 +) + +require ( + contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect + github.com/AdhityaRamadhanus/fasthttpcors v0.0.0-20170121111917-d4c07198763a // indirect + github.com/PuerkitoBio/purell v1.2.0 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed // indirect + github.com/armon/go-metrics v0.4.1 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.1.3 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fasthttp/router v1.4.12 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-kit/log v0.2.1 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/cel-go v0.12.5 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/grandcat/zeroconf v1.0.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect + github.com/hashicorp/consul/api v1.13.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v1.3.1 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/serf v0.9.7 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgx/v5 v5.0.4 // indirect + github.com/jhump/protoreflect v1.13.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/miekg/dns v1.1.50 // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.13.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.37.0 // indirect + github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/statsd_exporter v0.22.7 // indirect + github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/sony/gobreaker v0.5.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect + github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.41.0 // indirect + go.opencensus.io v0.23.0 // indirect + go.opentelemetry.io/otel v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.11.1 // indirect + go.opentelemetry.io/otel/sdk v1.11.1 // indirect + go.opentelemetry.io/otel/trace v1.11.1 // indirect + go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f // indirect + golang.org/x/mod v0.6.0 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/oauth2 v0.1.0 // indirect + golang.org/x/sync v0.1.0 // indirect + golang.org/x/sys v0.1.0 // indirect + golang.org/x/term v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect + golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect + golang.org/x/tools v0.2.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c // indirect + google.golang.org/grpc v1.50.1 // indirect + google.golang.org/protobuf v1.28.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.25.3 // indirect + k8s.io/apiextensions-apiserver v0.25.3 // indirect + k8s.io/apimachinery v0.25.3 // indirect + k8s.io/client-go v0.25.3 // indirect + k8s.io/component-base v0.25.3 // indirect + k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + k8s.io/utils v0.0.0-20221012122500-cfd413dd9e85 // indirect + sigs.k8s.io/controller-runtime v0.13.0 // indirect + sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +replace github.com/dapr/components-contrib/tests/certification => ../../ + +// replace github.com/dapr/dapr => github.com/berndverst/dapr v1.1.3-0.20221105062638-159383e4fac0 + +replace github.com/dapr/components-contrib => ../../../../ diff --git a/tests/certification/state/cockroachdb/go.sum b/tests/certification/state/cockroachdb/go.sum new file mode 100644 index 000000000..af8ef31de --- /dev/null +++ b/tests/certification/state/cockroachdb/go.sum @@ -0,0 +1,917 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= +contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AdhityaRamadhanus/fasthttpcors v0.0.0-20170121111917-d4c07198763a h1:XVdatQFSP2YhJGjqLLIfW8QBk4loz/SCe/PxkXDiW+s= +github.com/AdhityaRamadhanus/fasthttpcors v0.0.0-20170121111917-d4c07198763a/go.mod h1:C0A1KeiVHs+trY6gUTPhhGammbrZ30ZfXRW/nuT7HLw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig= +github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed h1:ue9pVfIcP+QMEjfgo/Ez4ZjNZfonGgR6NgjMaJMu1Cg= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220418222510-f25a4f6275ed/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 h1:WbME5tjM4LJybkpsgT9zpccX07N1cFhH2ShbeSUwynM= +github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4/go.mod h1:noFtU2Oo1/YfAgiqbU1/JVG81+20b/mOs3Ziwq/fMrU= +github.com/dapr/go-sdk v1.6.0 h1:jg5A2khSCHF8bGZsig5RWN/gD0jjitszc2V6Uq2pPdY= +github.com/dapr/go-sdk v1.6.0/go.mod h1:KLQBltoD9K0w5hKTihdcyg9Epob9gypwL5dYcQzPro4= +github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f h1:K6XJz+p6bQwqqI+GyQP/jjjqfsdjK0Loe2ZYQ5gXut4= +github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f/go.mod h1:i9t09QZw346M2RbuK7oJhssOP0HCAQObz61U4SBNJSU= +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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fasthttp/router v1.4.12 h1:QEgK+UKARaC1bAzJgnIhdUMay6nwp+YFq6VGPlyKN1o= +github.com/fasthttp/router v1.4.12/go.mod h1:41Qdc4Z4T2pWVVtATHCnoUnOtxdBoeKEYJTXhHwbxCQ= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/cel-go v0.12.5 h1:DmzaiSgoaqGCjtpPQWl26/gND+yRpim56H1jCVev6d8= +github.com/google/cel-go v0.12.5/go.mod h1:Jk7ljRzLBhkmiAwBoUxB1sZSCVBAzkqPF25olK/iRDw= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/grandcat/zeroconf v1.0.0 h1:uHhahLBKqwWBV6WZUDAT71044vwOTL+McW0mBJvo6kE= +github.com/grandcat/zeroconf v1.0.0/go.mod h1:lTKmG1zh86XyCoUeIHSA4FJMBwCJiQmGfcP2PdzytEs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/hashicorp/consul/api v1.13.0 h1:2hnLQ0GjQvw7f3O61jMO8gbasZviZTrt9R8WzgiirHc= +github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= +github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +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/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +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.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= +github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +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-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7 h1:hkdgbqizGQHuU5IPqYM1JdSMV8nKfpuOnZYXssk9muY= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgx/v5 v5.0.4 h1:r5O6y84qHX/z/HZV40JBdx2obsHz7/uRj5b+CcYEdeY= +github.com/jackc/pgx/v5 v5.0.4/go.mod h1:U0ynklHtgg43fue9Ly30w3OCSTDPlXjig9ghrNGaguQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= +github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= +github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= +github.com/jhump/protoreflect v1.13.0 h1:zrrZqa7JAc2YGgPSzZZkmUXJ5G6NRPdxOg/9t7ISImA= +github.com/jhump/protoreflect v1.13.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +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/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/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +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.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= +github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= +github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= +github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU= +github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= +github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= +github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= +github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= +github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= +github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo= +github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/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 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/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.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= +github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde h1:AMNpJRc7P+GTwVbl8DkK2I9I8BBUzNiHuH/tlxrpan0= +github.com/tidwall/transform v0.0.0-20201103190739-32f242e2dbde/go.mod h1:MvrEmduDUz4ST5pGZ7CABCnOU5f3ZiOAZzT6b1A6nX8= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= +github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= +go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 h1:MEQNafcNCB0uQIti/oHgU7CZpUMYQ7qigBwMVKycHvc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1/go.mod h1:19O5I2U5iys38SsmT2uDJja/300woyzE1KPIQxEUBUc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 h1:LYyG/f1W/jzAix16jbksJfMQFpOH/Ma6T639pVPMgfI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1/go.mod h1:QrRRQiY3kzAoYPNLP0W/Ikg0gR6V3LMc+ODSxr7yyvg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1 h1:tFl63cpAAcD9TOU6U8kZU7KyXuSRYAZlbx1C61aaB74= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.11.1/go.mod h1:X620Jww3RajCJXw/unA+8IRTgxkdS7pi+ZwK9b7KUJk= +go.opentelemetry.io/otel/exporters/zipkin v1.11.1 h1:JlJ3/oQoyqlrPDCfsSVFcHgGeHvZq+hr1VPWtiYCXTo= +go.opentelemetry.io/otel/exporters/zipkin v1.11.1/go.mod h1:T4S6aVwIS1+MHA+dJHCcPROtZe6ORwnv5vMKPRapsFw= +go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= +go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= +go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= +go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +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.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f h1:Al51T6tzvuh3oiwX11vex3QgJ2XTedFPGmbEVh8cdoc= +golang.org/x/exp v0.0.0-20221028150844-83b7d23a625f/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +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= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.25.3 h1:Q1v5UFfYe87vi5H7NU0p4RXC26PPMT8KOpr1TLQbCMQ= +k8s.io/api v0.25.3/go.mod h1:o42gKscFrEVjHdQnyRenACrMtbuJsVdP+WVjqejfzmI= +k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k= +k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo= +k8s.io/apimachinery v0.25.3 h1:7o9ium4uyUOM76t6aunP0nZuex7gDf8VGwkR5RcJnQc= +k8s.io/apimachinery v0.25.3/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo= +k8s.io/client-go v0.25.3 h1:oB4Dyl8d6UbfDHD8Bv8evKylzs3BXzzufLiO27xuPs0= +k8s.io/client-go v0.25.3/go.mod h1:t39LPczAIMwycjcXkVc+CB+PZV69jQuNx4um5ORDjQA= +k8s.io/component-base v0.25.3 h1:UrsxciGdrCY03ULT1h/S/gXFCOPnLhUVwSyx+hM/zq4= +k8s.io/component-base v0.25.3/go.mod h1:WYoS8L+IlTZgU7rhAl5Ctpw0WdMxDfCC5dkxcEFa/TI= +k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= +k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/utils v0.0.0-20221012122500-cfd413dd9e85 h1:cTdVh7LYu82xeClmfzGtgyspNh6UxpwLWGi8R4sspNo= +k8s.io/utils v0.0.0-20221012122500-cfd413dd9e85/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= +sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/tests/certification/state/memcached/go.mod b/tests/certification/state/memcached/go.mod index 0aca607b4..60d0c9482 100644 --- a/tests/certification/state/memcached/go.mod +++ b/tests/certification/state/memcached/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -75,6 +75,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/memcached/go.sum b/tests/certification/state/memcached/go.sum index 16bbfd64f..1f7d070ad 100644 --- a/tests/certification/state/memcached/go.sum +++ b/tests/certification/state/memcached/go.sum @@ -381,6 +381,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/mongodb/go.mod b/tests/certification/state/mongodb/go.mod index 319c56b9c..a71aa5812 100644 --- a/tests/certification/state/mongodb/go.mod +++ b/tests/certification/state/mongodb/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -76,6 +76,7 @@ require ( github.com/montanaflynn/stats v0.6.6 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/mongodb/go.sum b/tests/certification/state/mongodb/go.sum index c4ec85592..606f14894 100644 --- a/tests/certification/state/mongodb/go.sum +++ b/tests/certification/state/mongodb/go.sum @@ -387,6 +387,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/mysql/go.mod b/tests/certification/state/mysql/go.mod index acc2457b8..9cd3102df 100644 --- a/tests/certification/state/mysql/go.mod +++ b/tests/certification/state/mysql/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -75,6 +75,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/mysql/go.sum b/tests/certification/state/mysql/go.sum index fdf8cd1b8..9f63889be 100644 --- a/tests/certification/state/mysql/go.sum +++ b/tests/certification/state/mysql/go.sum @@ -382,6 +382,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/postgresql/go.mod b/tests/certification/state/postgresql/go.mod index c362c0938..41af005a3 100644 --- a/tests/certification/state/postgresql/go.mod +++ b/tests/certification/state/postgresql/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/postgresql/go.sum b/tests/certification/state/postgresql/go.sum index 0ba906b62..8254bf310 100644 --- a/tests/certification/state/postgresql/go.sum +++ b/tests/certification/state/postgresql/go.sum @@ -386,6 +386,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/postgresql/postgresql_test.go b/tests/certification/state/postgresql/postgresql_test.go index 7868fa5fb..29ccdb61b 100644 --- a/tests/certification/state/postgresql/postgresql_test.go +++ b/tests/certification/state/postgresql/postgresql_test.go @@ -184,7 +184,8 @@ func TestPostgreSQL(t *testing.T) { }, }, }) - assert.Equal(t, nil, err) + require.NoError(t, err) + resp1, err := stateStore.Get(&state.GetRequest{ Key: "reqKey1", }) @@ -206,7 +207,7 @@ func TestPostgreSQL(t *testing.T) { // save state _, err = client.GetState(ctx, stateStoreName, certificationTestPrefix+"key1", nil) - assert.NoError(t, err) + require.NoError(t, err) return nil } diff --git a/tests/certification/state/redis/go.mod b/tests/certification/state/redis/go.mod index 919e983e8..fe78b1bca 100644 --- a/tests/certification/state/redis/go.mod +++ b/tests/certification/state/redis/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20220526162429-d03aeba3e0d6 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/redis/go.sum b/tests/certification/state/redis/go.sum index eb9fe226b..657d19e28 100644 --- a/tests/certification/state/redis/go.sum +++ b/tests/certification/state/redis/go.sum @@ -385,6 +385,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/tests/certification/state/sqlserver/go.mod b/tests/certification/state/sqlserver/go.mod index a7372193c..3cb0d6b4e 100644 --- a/tests/certification/state/sqlserver/go.mod +++ b/tests/certification/state/sqlserver/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/dapr/components-contrib v1.9.1-0.20221025205611-e38369028650 github.com/dapr/components-contrib/tests/certification v0.0.0-20211130185200-4918900c09e1 - github.com/dapr/dapr v1.9.1-0.20221101183153-7e3635f1491e + github.com/dapr/dapr v1.9.4-0.20221121055721-6683f7582ac4 github.com/dapr/go-sdk v1.5.1-0.20221004175845-b465b1fa0721 github.com/dapr/kit v0.0.3-0.20221102045011-c213121f0b4f github.com/stretchr/testify v1.8.1 @@ -77,6 +77,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.1 // indirect + github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/tests/certification/state/sqlserver/go.sum b/tests/certification/state/sqlserver/go.sum index 0b3a8dd5e..d6c5d2e07 100644 --- a/tests/certification/state/sqlserver/go.sum +++ b/tests/certification/state/sqlserver/go.sum @@ -390,6 +390,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= +github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= From 47b0d7367657cd7ee6d41e58bcbcfa04574d8201 Mon Sep 17 00:00:00 2001 From: thielepaul Date: Tue, 29 Nov 2022 19:06:20 +0100 Subject: [PATCH 16/22] Add mqtt retained information to pubsub message metadata (#2299) Signed-off-by: Paul Thiele Signed-off-by: Paul Thiele Co-authored-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> Co-authored-by: Alessandro (Ale) Segala <43508+ItalyPaleAle@users.noreply.github.com> Co-authored-by: Dapr Bot <56698301+dapr-bot@users.noreply.github.com> --- pubsub/mqtt/mqtt.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pubsub/mqtt/mqtt.go b/pubsub/mqtt/mqtt.go index f3c12f769..fec6dc77b 100644 --- a/pubsub/mqtt/mqtt.go +++ b/pubsub/mqtt/mqtt.go @@ -22,6 +22,7 @@ import ( "fmt" "net/url" "regexp" + "strconv" "strings" "sync" "time" @@ -276,8 +277,9 @@ func (m *mqttPubSub) onMessage(ctx context.Context) func(client mqtt.Client, mqt }() msg := pubsub.NewMessage{ - Topic: mqttMsg.Topic(), - Data: mqttMsg.Payload(), + Topic: mqttMsg.Topic(), + Data: mqttMsg.Payload(), + Metadata: map[string]string{"retained": strconv.FormatBool(mqttMsg.Retained())}, } topicHandler := m.handlerForTopic(msg.Topic) From 9e9d7086e171ee0c99ba295ddf445287effd62f7 Mon Sep 17 00:00:00 2001 From: John Ewart Date: Tue, 29 Nov 2022 13:36:49 -0800 Subject: [PATCH 17/22] Allow HTTP binding to not error on non-200 responses Signed-off-by: John Ewart --- bindings/http/http.go | 30 ++++++++++++++---- bindings/http/http_test.go | 63 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 6 deletions(-) diff --git a/bindings/http/http.go b/bindings/http/http.go index fac33aacd..ccf629f6d 100644 --- a/bindings/http/http.go +++ b/bindings/http/http.go @@ -28,6 +28,7 @@ import ( "github.com/mitchellh/mapstructure" "github.com/dapr/components-contrib/bindings" + "github.com/dapr/components-contrib/internal/utils" "github.com/dapr/kit/logger" ) @@ -35,10 +36,10 @@ import ( // //revive:disable-next-line type HTTPSource struct { - metadata httpMetadata - client *http.Client - - logger logger.Logger + metadata httpMetadata + client *http.Client + errorIfNot2XX bool + logger logger.Logger } type httpMetadata struct { @@ -70,6 +71,13 @@ func (h *HTTPSource) Init(metadata bindings.Metadata) error { Transport: netTransport, } + if val, ok := metadata.Properties["errorIfNot2XX"]; ok { + h.errorIfNot2XX = utils.IsTruthy(val) + } else { + // Default behavior + h.errorIfNot2XX = true + } + return nil } @@ -91,6 +99,9 @@ func (h *HTTPSource) Operations() []bindings.OperationKind { // Invoke performs an HTTP request to the configured HTTP endpoint. func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bindings.InvokeResponse, error) { u := h.metadata.URL + + errorIfNot2XX := h.errorIfNot2XX // Default to the component config (default is true) + if req.Metadata != nil { if path, ok := req.Metadata["path"]; ok { // Simplicity and no "../../.." type exploits. @@ -99,6 +110,13 @@ func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (* return nil, fmt.Errorf("invalid path: %s", path) } } + + if _, ok := req.Metadata["errorIfNot2XX"]; ok { + errorIfNot2XX = utils.IsTruthy(req.Metadata["errorIfNot2XX"]) + } + } else { + // Prevent things below from failing if req.Metadata is nil. + req.Metadata = make(map[string]string) } var body io.Reader @@ -164,8 +182,8 @@ func (h *HTTPSource) Invoke(ctx context.Context, req *bindings.InvokeRequest) (* metadata[key] = strings.Join(values, ", ") } - // Create an error for non-200 status codes. - if resp.StatusCode/100 != 2 { + // Create an error for non-200 status codes unless suppressed. + if errorIfNot2XX && resp.StatusCode/100 != 2 { err = fmt.Errorf("received status code %d", resp.StatusCode) } diff --git a/bindings/http/http_test.go b/bindings/http/http_test.go index 746fc052a..fe6d374e3 100644 --- a/bindings/http/http_test.go +++ b/bindings/http/http_test.go @@ -172,6 +172,69 @@ func TestInit(t *testing.T) { path: "/", err: "received status code 500", }, + "internal server error suppressed": { + input: "internal server error", // trigger 500 + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, + path: "/", + err: "", + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + response, err := hs.Invoke(context.TODO(), &bindings.InvokeRequest{ + Data: []byte(tc.input), + Metadata: tc.metadata, + Operation: bindings.OperationKind(tc.operation), + }) + if tc.err == "" { + require.NoError(t, err) + assert.Equal(t, tc.path, path) + assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) + assert.Equal(t, "text/plain", response.Metadata["Content-Type"]) + } else { + require.Error(t, err) + assert.Equal(t, tc.err, err.Error()) + } + }) + } + + // Test with errorIfNot2XX set to false + hs = bindingHttp.NewHTTP(logger.NewLogger("test")) + m.Properties["errorIfNot2XX"] = "false" + + initErr := hs.Init(m) + require.NoError(t, initErr) + + tests = map[string]struct { + input string + operation string + metadata map[string]string + path string + err string + }{ + "internal server error": { + input: "internal server error", + operation: "post", + metadata: map[string]string{"path": "/"}, + path: "/", + err: "", + }, + "internal server error overridden": { + input: "internal server error", + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "true"}, + path: "/", + err: "received status code 500", + }, + "internal server error suppressed by request and component": { + input: "internal server error", // trigger 500 + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, + path: "/", + err: "", + }, } for name, tc := range tests { From 4227cf7716aeb51572614ac39a5d0857fa2cc60f Mon Sep 17 00:00:00 2001 From: John Ewart Date: Tue, 29 Nov 2022 13:24:32 -0800 Subject: [PATCH 18/22] Update tests to be a little more isolated Signed-off-by: John Ewart --- bindings/http/http_test.go | 431 +++++++++++++++++++++++-------------- 1 file changed, 271 insertions(+), 160 deletions(-) diff --git a/bindings/http/http_test.go b/bindings/http/http_test.go index fe6d374e3..55e6ec800 100644 --- a/bindings/http/http_test.go +++ b/bindings/http/http_test.go @@ -18,6 +18,7 @@ import ( "io" "net/http" "net/http/httptest" + "strconv" "strings" "testing" @@ -45,209 +46,319 @@ func TestOperations(t *testing.T) { }, opers) } -func TestInit(t *testing.T) { - var path string +type TestCase struct { + input string + operation string + metadata map[string]string + path string + err string + statusCode int +} - s := httptest.NewServer( - http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - path = req.URL.Path - input := req.Method - if req.Body != nil { - defer req.Body.Close() - b, _ := io.ReadAll(req.Body) - if len(b) > 0 { - input = string(b) - } - } - inputFromHeader := req.Header.Get("X-Input") - if inputFromHeader != "" { - input = inputFromHeader - } - w.Header().Set("Content-Type", "text/plain") - if input == "internal server error" { - w.WriteHeader(http.StatusInternalServerError) - } - w.Write([]byte(strings.ToUpper(input))) - }), - ) - defer s.Close() +func (tc TestCase) ToInvokeRequest() bindings.InvokeRequest { + + requestMetadata := tc.metadata + + if requestMetadata == nil { + requestMetadata = map[string]string{} + } + + requestMetadata["X-Status-Code"] = strconv.Itoa(tc.statusCode) + + return bindings.InvokeRequest{ + Data: []byte(tc.input), + Metadata: requestMetadata, + Operation: bindings.OperationKind(tc.operation), + } +} + +type HttpHandler struct { + Path string +} + +func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + h.Path = req.URL.Path + + input := req.Method + if req.Body != nil { + defer req.Body.Close() + b, _ := io.ReadAll(req.Body) + if len(b) > 0 { + input = string(b) + } + } + inputFromHeader := req.Header.Get("X-Input") + if inputFromHeader != "" { + input = inputFromHeader + } + + w.Header().Set("Content-Type", "text/plain") + + statusCode := req.Header.Get("X-Status-Code") + if statusCode != "" { + code, _ := strconv.Atoi(statusCode) + w.WriteHeader(code) + } + + w.Write([]byte(strings.ToUpper(input))) +} + +func NewHttpHandler() *HttpHandler { + return &HttpHandler{ + Path: "/", + } +} + +func InitBinding(s *httptest.Server, extraProps map[string]string) (bindings.OutputBinding, error) { m := bindings.Metadata{Base: metadata.Base{ Properties: map[string]string{ "url": s.URL, }, }} + + if extraProps != nil { + for k, v := range extraProps { + m.Properties[k] = v + } + } + hs := bindingHttp.NewHTTP(logger.NewLogger("test")) err := hs.Init(m) + return hs, err +} + +func TestInit(t *testing.T) { + handler := NewHttpHandler() + s := httptest.NewServer(handler) + defer s.Close() + + _, err := InitBinding(s, nil) + require.NoError(t, err) +} + +func TestDefaultBehavior(t *testing.T) { + handler := NewHttpHandler() + s := httptest.NewServer(handler) + defer s.Close() + + hs, err := InitBinding(s, nil) require.NoError(t, err) - tests := map[string]struct { - input string - operation string - metadata map[string]string - path string - err string - }{ + tests := map[string]TestCase{ "get": { - input: "GET", - operation: "get", - metadata: nil, - path: "/", - err: "", + input: "GET", + operation: "get", + metadata: nil, + path: "/", + err: "", + statusCode: 200, }, "request headers": { - input: "OVERRIDE", - operation: "get", - metadata: map[string]string{"X-Input": "override"}, - path: "/", - err: "", + input: "OVERRIDE", + operation: "get", + metadata: map[string]string{"X-Input": "override"}, + path: "/", + err: "", + statusCode: 200, }, "post": { - input: "expected", - operation: "post", - metadata: map[string]string{"path": "/test"}, - path: "/test", - err: "", + input: "expected", + operation: "post", + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "", + statusCode: 201, }, "put": { - input: "expected", - operation: "put", - metadata: map[string]string{"path": "/test"}, - path: "/test", - err: "", + input: "expected", + operation: "put", + statusCode: 204, + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "", }, "patch": { - input: "expected", - operation: "patch", - metadata: map[string]string{"path": "/test"}, - path: "/test", - err: "", + input: "expected", + operation: "patch", + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "", + statusCode: 206, }, "delete": { - input: "DELETE", - operation: "delete", - metadata: nil, - path: "/", - err: "", + input: "DELETE", + operation: "delete", + metadata: nil, + path: "/", + err: "", + statusCode: 200, }, "options": { - input: "OPTIONS", - operation: "options", - metadata: nil, - path: "/", - err: "", + input: "OPTIONS", + operation: "options", + metadata: nil, + path: "/", + err: "", + statusCode: 200, }, "trace": { - input: "TRACE", - operation: "trace", - metadata: nil, - path: "/", - err: "", + input: "TRACE", + operation: "trace", + metadata: nil, + path: "/", + err: "", + statusCode: 200, }, "backward compatibility": { - input: "expected", - operation: "create", - metadata: map[string]string{"path": "/test"}, - path: "/test", - err: "", + input: "expected", + operation: "create", + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "", + statusCode: 200, }, "invalid path": { - input: "expected", - operation: "POST", - metadata: map[string]string{"path": "/../test"}, - path: "", - err: "invalid path: /../test", + input: "expected", + operation: "POST", + metadata: map[string]string{"path": "/../test"}, + path: "", + err: "invalid path: /../test", + statusCode: 400, }, "invalid operation": { - input: "notvalid", - operation: "notvalid", - metadata: map[string]string{"path": "/test"}, - path: "/test", - err: "invalid operation: notvalid", + input: "notvalid", + operation: "notvalid", + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "invalid operation: notvalid", + statusCode: 400, }, "internal server error": { - input: "internal server error", - operation: "post", - metadata: map[string]string{"path": "/"}, - path: "/", - err: "received status code 500", + input: "internal server error", + operation: "post", + metadata: map[string]string{"path": "/"}, + path: "/", + err: "received status code 500", + statusCode: 500, }, "internal server error suppressed": { - input: "internal server error", // trigger 500 - operation: "post", - metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, - path: "/", - err: "", + input: "internal server error", // trigger 500 downstream + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, + path: "/", + err: "", + statusCode: 500, + }, + "redirect should not yield an error": { + input: "show me the treasure!", + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, + path: "/", + err: "", + statusCode: 302, + }, + "redirect results in an error if not suppressed": { + input: "show me the treasure!", + operation: "post", + metadata: map[string]string{"path": "/"}, + path: "/", + err: "received status code 302", + statusCode: 302, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { - response, err := hs.Invoke(context.TODO(), &bindings.InvokeRequest{ - Data: []byte(tc.input), - Metadata: tc.metadata, - Operation: bindings.OperationKind(tc.operation), - }) + req := tc.ToInvokeRequest() + response, err := hs.Invoke(context.TODO(), &req) if tc.err == "" { require.NoError(t, err) - assert.Equal(t, tc.path, path) - assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) - assert.Equal(t, "text/plain", response.Metadata["Content-Type"]) - } else { - require.Error(t, err) - assert.Equal(t, tc.err, err.Error()) - } - }) - } - - // Test with errorIfNot2XX set to false - hs = bindingHttp.NewHTTP(logger.NewLogger("test")) - m.Properties["errorIfNot2XX"] = "false" - - initErr := hs.Init(m) - require.NoError(t, initErr) - - tests = map[string]struct { - input string - operation string - metadata map[string]string - path string - err string - }{ - "internal server error": { - input: "internal server error", - operation: "post", - metadata: map[string]string{"path": "/"}, - path: "/", - err: "", - }, - "internal server error overridden": { - input: "internal server error", - operation: "post", - metadata: map[string]string{"path": "/", "errorIfNot2XX": "true"}, - path: "/", - err: "received status code 500", - }, - "internal server error suppressed by request and component": { - input: "internal server error", // trigger 500 - operation: "post", - metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, - path: "/", - err: "", - }, - } - - for name, tc := range tests { - t.Run(name, func(t *testing.T) { - response, err := hs.Invoke(context.TODO(), &bindings.InvokeRequest{ - Data: []byte(tc.input), - Metadata: tc.metadata, - Operation: bindings.OperationKind(tc.operation), - }) - if tc.err == "" { - require.NoError(t, err) - assert.Equal(t, tc.path, path) - assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) + assert.Equal(t, tc.path, handler.Path) + if tc.statusCode != 204 { + // 204 will return no content, so we should skip checking + assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) + } + assert.Equal(t, "text/plain", response.Metadata["Content-Type"]) + } else { + require.Error(t, err) + assert.Equal(t, tc.err, err.Error()) + } + }) + } +} + +func TestNon2XXErrorsSuppressed(t *testing.T) { + + handler := NewHttpHandler() + s := httptest.NewServer(handler) + defer s.Close() + + hs, err := InitBinding(s, map[string]string{"errorIfNot2XX": "false"}) + require.NoError(t, err) + + tests := map[string]TestCase{ + "internal server error": { + input: "internal server error", + operation: "post", + metadata: map[string]string{"path": "/"}, + path: "/", + err: "", + statusCode: 500, + }, + "internal server error overridden": { + input: "internal server error", + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "true"}, + path: "/", + err: "received status code 500", + statusCode: 500, + }, + "internal server error suppressed by request and component": { + input: "internal server error", // trigger 500 + operation: "post", + metadata: map[string]string{"path": "/", "errorIfNot2XX": "false"}, + path: "/", + err: "", + statusCode: 500, + }, + "trace": { + input: "TRACE", + operation: "trace", + metadata: nil, + path: "/", + err: "", + statusCode: 200, + }, + "backward compatibility": { + input: "expected", + operation: "create", + metadata: map[string]string{"path": "/test"}, + path: "/test", + err: "", + statusCode: 200, + }, + "invalid path": { + input: "expected", + operation: "POST", + metadata: map[string]string{"path": "/../test"}, + path: "", + err: "invalid path: /../test", + statusCode: 400, + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + req := tc.ToInvokeRequest() + response, err := hs.Invoke(context.TODO(), &req) + if tc.err == "" { + require.NoError(t, err) + assert.Equal(t, tc.path, handler.Path) + if tc.statusCode != 204 { + // 204 will return no content, so we should skip checking + assert.Equal(t, strings.ToUpper(tc.input), string(response.Data)) + } assert.Equal(t, "text/plain", response.Metadata["Content-Type"]) } else { require.Error(t, err) From 49bdf702e9e08aeac13e17cbe24d1ad467801c4b Mon Sep 17 00:00:00 2001 From: John Ewart Date: Tue, 29 Nov 2022 13:51:56 -0800 Subject: [PATCH 19/22] gofumpt'd Signed-off-by: John Ewart --- bindings/http/http_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/bindings/http/http_test.go b/bindings/http/http_test.go index 55e6ec800..4ea8d959f 100644 --- a/bindings/http/http_test.go +++ b/bindings/http/http_test.go @@ -56,7 +56,6 @@ type TestCase struct { } func (tc TestCase) ToInvokeRequest() bindings.InvokeRequest { - requestMetadata := tc.metadata if requestMetadata == nil { @@ -110,7 +109,6 @@ func NewHttpHandler() *HttpHandler { } func InitBinding(s *httptest.Server, extraProps map[string]string) (bindings.OutputBinding, error) { - m := bindings.Metadata{Base: metadata.Base{ Properties: map[string]string{ "url": s.URL, @@ -289,7 +287,6 @@ func TestDefaultBehavior(t *testing.T) { } func TestNon2XXErrorsSuppressed(t *testing.T) { - handler := NewHttpHandler() s := httptest.NewServer(handler) defer s.Close() From aef7ec77dc2252da978aba1aa76d2b27cd49914c Mon Sep 17 00:00:00 2001 From: John Ewart Date: Tue, 29 Nov 2022 14:56:06 -0800 Subject: [PATCH 20/22] Fix naming to make ci-linter happy Signed-off-by: John Ewart --- bindings/http/http_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bindings/http/http_test.go b/bindings/http/http_test.go index 4ea8d959f..d88e8aad4 100644 --- a/bindings/http/http_test.go +++ b/bindings/http/http_test.go @@ -71,11 +71,11 @@ func (tc TestCase) ToInvokeRequest() bindings.InvokeRequest { } } -type HttpHandler struct { +type HTTPHandler struct { Path string } -func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { +func (h *HTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { h.Path = req.URL.Path input := req.Method @@ -102,8 +102,8 @@ func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { w.Write([]byte(strings.ToUpper(input))) } -func NewHttpHandler() *HttpHandler { - return &HttpHandler{ +func NewHTTPHandler() *HTTPHandler { + return &HTTPHandler{ Path: "/", } } @@ -127,7 +127,7 @@ func InitBinding(s *httptest.Server, extraProps map[string]string) (bindings.Out } func TestInit(t *testing.T) { - handler := NewHttpHandler() + handler := NewHTTPHandler() s := httptest.NewServer(handler) defer s.Close() @@ -136,7 +136,7 @@ func TestInit(t *testing.T) { } func TestDefaultBehavior(t *testing.T) { - handler := NewHttpHandler() + handler := NewHTTPHandler() s := httptest.NewServer(handler) defer s.Close() @@ -287,7 +287,7 @@ func TestDefaultBehavior(t *testing.T) { } func TestNon2XXErrorsSuppressed(t *testing.T) { - handler := NewHttpHandler() + handler := NewHTTPHandler() s := httptest.NewServer(handler) defer s.Close() From b4c65ed195882444294196c1958915ee0f4066cc Mon Sep 17 00:00:00 2001 From: Tiago Alves Macambira Date: Tue, 29 Nov 2022 16:49:32 -0800 Subject: [PATCH 21/22] Enforce error checking for Vault component initialization on tests. Tests in vault_test.go had the following : ```go // This call will throw an error on Windows systems because of the of // the call x509.SystemCertPool() because system root pool is not // available on Windows so ignore the error for when the tests are run // on the Windows platform during CI _ = target.Init(m) ``` As of Go 1.18 this is not the case for Windows anymore and we can instead enforce error checking. References: * https://github.com/golang/go/issues/16736 * https://github.com/golang/go/issues/18609 * https://github.com/rancher/system-agent/pull/84 * https://github.com/jaegertracing/jaeger/pull/2756 Given Dapr depends on Go 1.19, we can enforce tests on `Init` result and remove this comment. While enforcing error checking we notice that the code above was actually hiding errors in the test setup. Component initialization was ending prematurely due to those errors and the test code was wrongfully testing for the behavior of a component that has not been successfully initialized. This is also addressed in this PR. Closes #2330. Signed-off-by: Tiago Alves Macambira --- secretstores/hashicorp/vault/vault_test.go | 117 ++++++++++----------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/secretstores/hashicorp/vault/vault_test.go b/secretstores/hashicorp/vault/vault_test.go index 0fc662e84..fff233445 100644 --- a/secretstores/hashicorp/vault/vault_test.go +++ b/secretstores/hashicorp/vault/vault_test.go @@ -28,49 +28,53 @@ import ( const ( // base64 encoded certificate. - certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" - expectedTok = "myRootToken" - expectedTokMountPath = "./vault.txt" + certificate = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURVakNDQWpvQ0NRRFlZdzdMeXN4VXRUQU5CZ2txaGtpRzl3MEJBUXNGQURCck1Rc3dDUVlEVlFRR0V3SkQKUVRFWk1CY0dBMVVFQ0F3UVFuSnBkR2x6YUNCRGIyeDFiV0pwWVRFU01CQUdBMVVFQnd3SlZtRnVZMjkxZG1WeQpNUk13RVFZRFZRUUtEQXB0YVhOb2NtRmpiM0p3TVJnd0ZnWURWUVFEREE5MllYVnNkSEJ5YjJwbFkzUXVhVzh3CkhoY05NVGt4TVRBeE1UQTBPREV5V2hjTk1qQXhNRE14TVRBME9ERXlXakJyTVFzd0NRWURWUVFHRXdKRFFURVoKTUJjR0ExVUVDQXdRUW5KcGRHbHphQ0JEYjJ4MWJXSnBZVEVTTUJBR0ExVUVCd3dKVm1GdVkyOTFkbVZ5TVJNdwpFUVlEVlFRS0RBcHRhWE5vY21GamIzSndNUmd3RmdZRFZRUUREQTkyWVhWc2RIQnliMnBsWTNRdWFXOHdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3JtaitTTmtGUHEvK2FXUFV1MlpFamtSK3AKTm1PeEVNSnZZcGhHNkJvRFAySE9ZbGRzdk9FWkRkbTBpWFlmeFIwZm5rUmtTMWEzSlZiYmhINWJnTElKb0dxcwo5aWpzN2hyQ0Rrdk9uRWxpUEZuc05pQ2NWNDNxNkZYaFMvNFpoNGpOMnlyUkU2UmZiS1BEeUw0a282NkFhSld1CnVkTldKVWpzSFZBSWowZHlnTXFKYm0rT29iSzk5ckUxcDg5Z3RNUStJdzFkWnUvUFF4SjlYOStMeXdxZUxPckQKOWhpNWkxajNFUUp2RXQxSVUzclEwc2E0NU5zZkt4YzEwZjdhTjJuSDQzSnhnMVRiZXNPOWYrcWlyeDBHYmVSYQpyVmNaazNVaFc2cHZmam9XbDBEc0NwNTJwZDBQN05rUmhmak44b2RMN0h3bFVIc1NqemlSYytsTG5YREJBZ01CCkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSVdKdmRPZ01PUnQxWk53SENkNTNieTlkMlBkcW5tWHFZZ20KNDZHK2Fvb1dSeTJKMEMwS3ZOVGZGbEJFOUlydzNXUTVNMnpqY25qSUp5bzNLRUM5TDdPMnQ1WC9LTGVDck5ZVgpIc1d4cU5BTVBGY2VBa09HT0I1TThGVllkdjJTaVV2UDJjMEZQSzc2WFVzcVNkdnRsWGFkTk5ENzE3T0NTNm0yCnBIVjh1NWJNd1VmR2NCVFpEV2o4bjIzRVdHaXdnYkJkdDc3Z3h3YWc5NTROZkM2Ny9nSUc5ZlRrTTQ4aVJCUzEKc0NGYVBjMkFIT3hiMSs0ajVCMVY2Z29iZDZYWkFvbHdNaTNHUUtkbEM1NXZNeTNwK09WbDNNbEc3RWNTVUpMdApwZ2ZKaWw3L3dTWWhpUnhJU3hrYkk5cWhvNEwzZm5PZVB3clFVd2FzU1ZiL1lxbHZ2WHM9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" + expectedTok = "myRootToken" + expectedTokenMountFileContents = "Hey! TokenMountFile contents here!" ) +func createTempFileWithContent(t *testing.T, contents string) (fileName string, cleanUpFunc func()) { + dir := os.TempDir() + f, err := os.CreateTemp(dir, "vault-token") + assert.NoError(t, err) + fileName = f.Name() + cleanUpFunc = func() { + os.Remove(fileName) + } + + _, err = f.WriteString(contents) + assert.NoError(t, err) + + return fileName, cleanUpFunc +} + +func createTokenMountPathFile(t *testing.T) (fileName string, cleanUpFunc func()) { + return createTempFileWithContent(t, expectedTokenMountFileContents) +} + func TestReadVaultToken(t *testing.T) { + tokenString := "This-IS-TheRootToken" + tmpFileName, cleanUpFunc := createTempFileWithContent(t, tokenString) + defer cleanUpFunc() + t.Run("read correct token", func(t *testing.T) { - dir := os.TempDir() - f, err := os.CreateTemp(dir, "vault-token") - assert.NoError(t, err) - fileName := f.Name() - defer os.Remove(fileName) - - tokenString := "thisisnottheroottoken" - _, err = f.WriteString(tokenString) - assert.NoError(t, err) - v := vaultSecretStore{ - vaultTokenMountPath: f.Name(), + vaultTokenMountPath: tmpFileName, } - err = v.initVaultToken() + err := v.initVaultToken() assert.Nil(t, err) assert.Equal(t, tokenString, v.vaultToken) }) t.Run("read incorrect token", func(t *testing.T) { - dir := os.TempDir() - f, err := os.CreateTemp(dir, "vault-token") - assert.NoError(t, err) - fileName := f.Name() - defer os.Remove(fileName) - - tokenString := "thisisnottheroottoken" - _, err = f.WriteString(tokenString) - assert.NoError(t, err) - v := vaultSecretStore{ - vaultTokenMountPath: f.Name(), + vaultTokenMountPath: tmpFileName, } - err = v.initVaultToken() + + err := v.initVaultToken() assert.Nil(t, err) - assert.NotEqual(t, "thisistheroottoken", v.vaultToken) + assert.NotEqual(t, "ThisIs-NOT-TheRootToken", v.vaultToken) }) t.Run("read token from vaultToken", func(t *testing.T) { @@ -126,6 +130,9 @@ func TestVaultEnginePath(t *testing.T) { } func TestVaultTokenPrefix(t *testing.T) { + expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t) + defer cleanUpFunc() + t.Run("default value of vaultKVUsePrefix is true to emulate previous behaviour", func(t *testing.T) { properties := map[string]string{ componentVaultToken: expectedTok, @@ -140,11 +147,9 @@ func TestVaultTokenPrefix(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI - _ = target.Init(m) + if err := target.Init(m); err != nil { + t.Fatal(err) + } assert.Equal(t, defaultVaultKVPrefix, target.vaultKVPrefix) }) @@ -165,11 +170,9 @@ func TestVaultTokenPrefix(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI - _ = target.Init(m) + if err := target.Init(m); err != nil { + t.Fatal(err) + } assert.Equal(t, "", target.vaultKVPrefix) }) @@ -190,10 +193,6 @@ func TestVaultTokenPrefix(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI err := target.Init(m) assert.NotNil(t, err) @@ -201,6 +200,9 @@ func TestVaultTokenPrefix(t *testing.T) { } func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) { + expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t) + defer cleanUpFunc() + t.Run("without vaultTokenMount or vaultToken", func(t *testing.T) { properties := map[string]string{} @@ -235,13 +237,11 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI - _ = target.Init(m) + if err := target.Init(m); err != nil { + t.Fatal(err) + } - assert.Equal(t, "", target.vaultToken) + assert.Equal(t, expectedTokenMountFileContents, target.vaultToken) assert.Equal(t, expectedTokMountPath, target.vaultTokenMountPath) }) @@ -259,11 +259,9 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI - _ = target.Init(m) + if err := target.Init(m); err != nil { + t.Fatal(err) + } assert.Equal(t, "", target.vaultTokenMountPath) assert.Equal(t, expectedTok, target.vaultToken) @@ -294,9 +292,12 @@ func TestVaultTokenMountPathOrVaultTokenRequired(t *testing.T) { } func TestDefaultVaultAddress(t *testing.T) { + expectedTokMountPath, cleanUpFunc := createTokenMountPathFile(t) + defer cleanUpFunc() + t.Run("with blank vaultAddr", func(t *testing.T) { properties := map[string]string{ - "vaultTokenMountPath": "./vault.txt", + "vaultTokenMountPath": expectedTokMountPath, } m := secretstores.Metadata{ @@ -308,11 +309,9 @@ func TestDefaultVaultAddress(t *testing.T) { logger: nil, } - // This call will throw an error on Windows systems because of the of - // the call x509.SystemCertPool() because system root pool is not - // available on Windows so ignore the error for when the tests are run - // on the Windows platform during CI - _ = target.Init(m) + if err := target.Init(m); err != nil { + t.Fatal(err) + } assert.Equal(t, defaultVaultAddress, target.vaultAddress, "default was not set") }) From 86cf34ef8f5c12c8fab45ad4b3bf8615c3ecdf29 Mon Sep 17 00:00:00 2001 From: Tomasz Pietrek Date: Wed, 30 Nov 2022 19:46:15 +0100 Subject: [PATCH 22/22] Add missing filter subject in Jetstream pubsub (#2312) Signed-off-by: Tomasz Pietrek Signed-off-by: Tomasz Pietrek Co-authored-by: Bernd Verst <4535280+berndverst@users.noreply.github.com> Co-authored-by: Dapr Bot <56698301+dapr-bot@users.noreply.github.com> --- pubsub/jetstream/jetstream.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pubsub/jetstream/jetstream.go b/pubsub/jetstream/jetstream.go index 37e2a610d..65a516760 100644 --- a/pubsub/jetstream/jetstream.go +++ b/pubsub/jetstream/jetstream.go @@ -162,6 +162,7 @@ func (js *jetstreamPubSub) Subscribe(ctx context.Context, req pubsub.SubscribeRe if js.meta.hearbeat != 0 { consumerConfig.Heartbeat = js.meta.hearbeat } + consumerConfig.FilterSubject = req.Topic natsHandler := func(m *nats.Msg) { jsm, err := m.Metadata()