diff --git a/pkg/extensions/imagetrust/cosign.go b/pkg/extensions/imagetrust/cosign.go index 41b9935c7b..bbf02c569b 100644 --- a/pkg/extensions/imagetrust/cosign.go +++ b/pkg/extensions/imagetrust/cosign.go @@ -12,6 +12,7 @@ import ( "io" "os" "path" + "strings" "github.com/aws/aws-sdk-go-v2/service/secretsmanager" "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types" @@ -256,11 +257,11 @@ func (cloud *PublicKeyAWSStorage) StorePublicKey(name godigest.Digest, publicKey } _, err := cloud.secretsManagerClient.CreateSecret(context.Background(), secretInputParam) - if err != nil { - return err + if err != nil && strings.Contains(err.Error(), "already exists") { + return nil } - return nil + return err } func validatePublicKey(publicKeyContent []byte) (bool, error) { diff --git a/pkg/extensions/imagetrust/image_trust_test.go b/pkg/extensions/imagetrust/image_trust_test.go index d7bd53a299..7c3f8649c8 100644 --- a/pkg/extensions/imagetrust/image_trust_test.go +++ b/pkg/extensions/imagetrust/image_trust_test.go @@ -45,8 +45,9 @@ import ( ) var ( - errExpiryError = errors.New("expiry err") - errUnexpectedError = errors.New("unexpected err") + errExpiryError = errors.New("expiry err") + errUnexpectedError = errors.New("unexpected err") + errAlreadyExistsError = errors.New("the secret trustpolicy already exists") ) func TestInitCosignAndNotationDirs(t *testing.T) { @@ -661,30 +662,13 @@ func TestLocalTrustStore(t *testing.T) { func TestAWSTrustStore(t *testing.T) { tskip.SkipDynamo(t) - trustpolicy := "trustpolicy" - Convey("NewAWSImageTrustStore error", t, func() { _, err := imagetrust.NewAWSImageTrustStore("us-east-2", "wrong;endpoint") So(err, ShouldNotBeNil) }) Convey("InitTrustpolicy retry", t, func() { - smanager, err := imagetrust.GetSecretsManagerClient("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) - So(err, ShouldBeNil) - - smCache := imagetrust.GetSecretsManagerRetrieval("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) - - description := "notation trustpolicy file" content := "trustpolicy content" - - _, err = smanager.CreateSecret(context.Background(), - &secretsmanager.CreateSecretInput{ - Name: &trustpolicy, - Description: &description, - SecretString: &content, - }) - So(err, ShouldBeNil) - secretsManagerMock := mocks.SecretsManagerMock{ DeleteSecretFn: func(ctx context.Context, params *secretsmanager.DeleteSecretInput, optFns ...func(*secretsmanager.Options), @@ -694,20 +678,25 @@ func TestAWSTrustStore(t *testing.T) { CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, optFns ...func(*secretsmanager.Options), ) (*secretsmanager.CreateSecretOutput, error) { - return smanager.CreateSecret(ctx, params, optFns...) + return &secretsmanager.CreateSecretOutput{}, errAlreadyExistsError }, } - secretsManagerCacheMock := mocks.SecretsManagerCacheMock{ GetSecretStringFn: func(secretID string) (string, error) { return "", errUnexpectedError }, } - _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) + _, err := imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldNotBeNil) - _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, smCache) + secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return content, nil + }, + } + + _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldNotBeNil) secretsManagerMock = mocks.SecretsManagerMock{ @@ -719,13 +708,15 @@ func TestAWSTrustStore(t *testing.T) { CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, optFns ...func(*secretsmanager.Options), ) (*secretsmanager.CreateSecretOutput, error) { - return smanager.CreateSecret(ctx, params, optFns...) + return &secretsmanager.CreateSecretOutput{}, errUnexpectedError }, } - _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, smCache) + _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldNotBeNil) + errVal := make(chan bool) + secretsManagerMock = mocks.SecretsManagerMock{ DeleteSecretFn: func(ctx context.Context, params *secretsmanager.DeleteSecretInput, optFns ...func(*secretsmanager.Options), @@ -733,7 +724,7 @@ func TestAWSTrustStore(t *testing.T) { go func() { time.Sleep(3 * time.Second) - smanager.DeleteSecret(ctx, params, optFns...) //nolint:errcheck + errVal <- true }() return &secretsmanager.DeleteSecretOutput{}, nil @@ -741,21 +732,53 @@ func TestAWSTrustStore(t *testing.T) { CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, optFns ...func(*secretsmanager.Options), ) (*secretsmanager.CreateSecretOutput, error) { - return smanager.CreateSecret(ctx, params, optFns...) + select { + case <-errVal: + return &secretsmanager.CreateSecretOutput{}, nil + default: + return &secretsmanager.CreateSecretOutput{}, errAlreadyExistsError + } }, } - _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, smCache) + _, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldBeNil) }) Convey("GetCertificates errors", t, func() { - smanager, err := imagetrust.GetSecretsManagerClient("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) - So(err, ShouldBeNil) + name := "ca/test/digest" + content := "invalid certificate content" + + secretsManagerMock := mocks.SecretsManagerMock{ + DeleteSecretFn: func(ctx context.Context, params *secretsmanager.DeleteSecretInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.DeleteSecretOutput, error) { + return &secretsmanager.DeleteSecretOutput{}, nil + }, + CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.CreateSecretOutput, error) { + if *params.Name == "trustpolicy" { + return &secretsmanager.CreateSecretOutput{}, nil + } - smCache := imagetrust.GetSecretsManagerRetrieval("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) + return &secretsmanager.CreateSecretOutput{}, errUnexpectedError + }, + ListSecretsFn: func(ctx context.Context, params *secretsmanager.ListSecretsInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.ListSecretsOutput, error) { + return &secretsmanager.ListSecretsOutput{ + SecretList: []types.SecretListEntry{{Name: &name}}, + }, nil + }, + } + secretsManagerCacheMock := mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return content, nil + }, + } - notationStorage, err := imagetrust.NewCertificateAWSStorage(smanager, smCache) + notationStorage, err := imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldBeNil) _, err = notationStorage.GetCertificates(context.Background(), "wrongType", "") @@ -766,36 +789,48 @@ func TestAWSTrustStore(t *testing.T) { So(err, ShouldNotBeNil) So(err, ShouldEqual, zerr.ErrInvalidTruststoreName) - name := "ca/test/digest" - description := "notation certificate" - content := "invalid certificate content" - - _, err = smanager.CreateSecret(context.Background(), - &secretsmanager.CreateSecretInput{ - Name: &name, - Description: &description, - SecretString: &content, - }) - So(err, ShouldBeNil) - _, err = notationStorage.GetCertificates(context.Background(), "ca", "test") So(err, ShouldNotBeNil) newName := "ca/newtest/digest" newSecret := base64.StdEncoding.EncodeToString([]byte(content)) - _, err = smanager.CreateSecret(context.Background(), - &secretsmanager.CreateSecretInput{ - Name: &newName, - Description: &description, - SecretString: &newSecret, - }) + secretsManagerMock = mocks.SecretsManagerMock{ + DeleteSecretFn: func(ctx context.Context, params *secretsmanager.DeleteSecretInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.DeleteSecretOutput, error) { + return &secretsmanager.DeleteSecretOutput{}, nil + }, + CreateSecretFn: func(ctx context.Context, params *secretsmanager.CreateSecretInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.CreateSecretOutput, error) { + if *params.Name == "trustpolicy" { + return &secretsmanager.CreateSecretOutput{}, nil + } + + return &secretsmanager.CreateSecretOutput{}, errUnexpectedError + }, + ListSecretsFn: func(ctx context.Context, params *secretsmanager.ListSecretsInput, + optFns ...func(*secretsmanager.Options), + ) (*secretsmanager.ListSecretsOutput, error) { + return &secretsmanager.ListSecretsOutput{ + SecretList: []types.SecretListEntry{{Name: &newName}}, + }, nil + }, + } + secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return newSecret, nil + }, + } + + notationStorage, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldBeNil) _, err = notationStorage.GetCertificates(context.Background(), "ca", "newtest") So(err, ShouldNotBeNil) - secretsManagerMock := mocks.SecretsManagerMock{ + secretsManagerMock = mocks.SecretsManagerMock{ ListSecretsFn: func(ctx context.Context, params *secretsmanager.ListSecretsInput, optFns ...func(*secretsmanager.Options), ) (*secretsmanager.ListSecretsOutput, error) { @@ -803,7 +838,7 @@ func TestAWSTrustStore(t *testing.T) { }, } - notationStorage, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, smCache) + notationStorage, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock) So(err, ShouldBeNil) _, err = notationStorage.GetCertificates(context.Background(), "ca", "newtest") @@ -817,7 +852,7 @@ func TestAWSTrustStore(t *testing.T) { }, } - secretsManagerCacheMock := mocks.SecretsManagerCacheMock{ + secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ GetSecretStringFn: func(secretID string) (string, error) { return "", errUnexpectedError }, @@ -831,42 +866,41 @@ func TestAWSTrustStore(t *testing.T) { }) Convey("GetPublicKeyVerifier errors", t, func() { - smanager, err := imagetrust.GetSecretsManagerClient("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) - So(err, ShouldBeNil) - - smCache := imagetrust.GetSecretsManagerRetrieval("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT")) + secretsManagerMock := mocks.SecretsManagerMock{} + secretsManagerCacheMock := mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return "", errUnexpectedError + }, + } - cosignStorage := imagetrust.NewPublicKeyAWSStorage(smanager, smCache) + cosignStorage := imagetrust.NewPublicKeyAWSStorage(secretsManagerMock, secretsManagerCacheMock) - _, _, err = cosignStorage.GetPublicKeyVerifier("badsecret") + _, _, err := cosignStorage.GetPublicKeyVerifier("badsecret") So(err, ShouldNotBeNil) secretName := "digest" - description := "cosign public key" secret := "invalid public key content" - _, err = smanager.CreateSecret(context.Background(), - &secretsmanager.CreateSecretInput{ - Name: &secretName, - Description: &description, - SecretString: &secret, - }) - So(err, ShouldBeNil) + secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return secret, nil + }, + } + + cosignStorage = imagetrust.NewPublicKeyAWSStorage(secretsManagerMock, secretsManagerCacheMock) _, _, err = cosignStorage.GetPublicKeyVerifier(secretName) So(err, ShouldNotBeNil) - secretName = "newdigest" - newSecret := base64.StdEncoding.EncodeToString([]byte(secret)) - _, err = smanager.CreateSecret(context.Background(), - &secretsmanager.CreateSecretInput{ - Name: &secretName, - Description: &description, - SecretString: &newSecret, - }) - So(err, ShouldBeNil) + secretsManagerCacheMock = mocks.SecretsManagerCacheMock{ + GetSecretStringFn: func(secretID string) (string, error) { + return newSecret, nil + }, + } + + cosignStorage = imagetrust.NewPublicKeyAWSStorage(secretsManagerMock, secretsManagerCacheMock) _, _, err = cosignStorage.GetPublicKeyVerifier(secretName) So(err, ShouldNotBeNil) diff --git a/pkg/extensions/imagetrust/notation.go b/pkg/extensions/imagetrust/notation.go index 22de1eb20e..d5d5c2ae6c 100644 --- a/pkg/extensions/imagetrust/notation.go +++ b/pkg/extensions/imagetrust/notation.go @@ -170,7 +170,7 @@ func (cloud *CertificateAWSStorage) InitTrustpolicy(trustpolicy []byte) error { } _, err := cloud.secretsManagerClient.CreateSecret(context.Background(), secretInputParam) - if err != nil && strings.Contains(err.Error(), "the secret trustpolicy already exists.") { + if err != nil && strings.Contains(err.Error(), "the secret trustpolicy already exists") { trustpolicyContent, err := cloud.secretsManagerCache.GetSecretString(name) if err != nil { return err @@ -495,6 +495,10 @@ func (cloud *CertificateAWSStorage) StoreCertificate( _, err := cloud.secretsManagerClient.CreateSecret(context.Background(), secretInputParam) + if err != nil && strings.Contains(err.Error(), "already exists") { + return nil + } + return err }