Skip to content

Commit

Permalink
fix(tests): update imagetrust tests to use mock service
Browse files Browse the repository at this point in the history
- use secretsManagerMock and secretsManagerCacheMock to avoid failing
because of "already exists" error when running multiple times
image_trust_test on the same localstack instance

Signed-off-by: Andreea-Lupu <[email protected]>
  • Loading branch information
Andreea-Lupu committed Oct 17, 2023
1 parent 7f6534a commit 65f8da2
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 78 deletions.
6 changes: 3 additions & 3 deletions pkg/extensions/imagetrust/cosign.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ func (cloud *PublicKeyAWSStorage) StorePublicKey(name godigest.Digest, publicKey
}

_, err := cloud.secretsManagerClient.CreateSecret(context.Background(), secretInputParam)
if err != nil {
return err
if err != nil && IsResourceExistsException(err) {
return nil

Check warning on line 260 in pkg/extensions/imagetrust/cosign.go

View check run for this annotation

Codecov / codecov/patch

pkg/extensions/imagetrust/cosign.go#L260

Added line #L260 was not covered by tests
}

return nil
return err
}

func validatePublicKey(publicKeyContent []byte) (bool, error) {
Expand Down
17 changes: 17 additions & 0 deletions pkg/extensions/imagetrust/image_trust.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import (
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/transport/http"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager/types"
aws1 "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/session"
smanager "github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/aws/aws-secretsmanager-caching-go/secretcache"
smithy "github.com/aws/smithy-go"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"

Expand Down Expand Up @@ -140,6 +143,20 @@ func GetSecretsManagerRetrieval(region, endpoint string) *secretcache.Cache {
return cache
}

func IsResourceExistsException(err error) bool {
if opErr, ok := err.(*smithy.OperationError); ok { //nolint: errorlint
if resErr, ok := opErr.Err.(*http.ResponseError); ok { //nolint: errorlint
if _, ok := resErr.Err.(*types.ResourceExistsException); ok { //nolint: errorlint
return true
}
}

return false
}

return false
}

func (imgTrustStore *ImageTrustStore) VerifySignature(
signatureType string, rawSignature []byte, sigKey string, manifestDigest godigest.Digest, manifestContent []byte,
repo string,
Expand Down
198 changes: 124 additions & 74 deletions pkg/extensions/imagetrust/image_trust_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ import (
"testing"
"time"

awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager/types"
smithy "github.com/aws/smithy-go"
smithyhttp "github.com/aws/smithy-go/transport/http"
guuid "github.com/gofrs/uuid"
"github.com/notaryproject/notation-go"
notreg "github.com/notaryproject/notation-go/registry"
Expand Down Expand Up @@ -661,30 +664,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),
Expand All @@ -694,20 +680,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{}, getResourceExistsException()
},
}

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{
Expand All @@ -719,43 +710,77 @@ 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),
) (*secretsmanager.DeleteSecretOutput, error) {
go func() {
time.Sleep(3 * time.Second)

smanager.DeleteSecret(ctx, params, optFns...) //nolint:errcheck
errVal <- true
}()

return &secretsmanager.DeleteSecretOutput{}, nil
},
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{}, getResourceExistsException()
}
},
}

_, 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"

smCache := imagetrust.GetSecretsManagerRetrieval("us-east-2", os.Getenv("DYNAMODBMOCK_ENDPOINT"))
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: &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", "")
Expand All @@ -766,44 +791,56 @@ 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) {
return &secretsmanager.ListSecretsOutput{}, errUnexpectedError
},
}

notationStorage, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, smCache)
notationStorage, err = imagetrust.NewCertificateAWSStorage(secretsManagerMock, secretsManagerCacheMock)
So(err, ShouldBeNil)

_, err = notationStorage.GetCertificates(context.Background(), "ca", "newtest")
Expand All @@ -817,7 +854,7 @@ func TestAWSTrustStore(t *testing.T) {
},
}

secretsManagerCacheMock := mocks.SecretsManagerCacheMock{
secretsManagerCacheMock = mocks.SecretsManagerCacheMock{
GetSecretStringFn: func(secretID string) (string, error) {
return "", errUnexpectedError
},
Expand All @@ -831,42 +868,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)
Expand Down Expand Up @@ -1337,3 +1373,17 @@ func RunVerificationTests(t *testing.T, dbDriverParams map[string]interface{}) {
})
})
}

func getResourceExistsException() error {
errAlreadyExists := "the secret trustpolicy already exists"

return &smithy.OperationError{
Err: &awshttp.ResponseError{
ResponseError: &smithyhttp.ResponseError{
Err: &types.ResourceExistsException{
Message: &errAlreadyExists,
},
},
},
}
}
Loading

0 comments on commit 65f8da2

Please sign in to comment.