package sdk import ( "context" "encoding/gob" "fmt" "strings" "github.com/BishopFox/cloudfox/internal" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ecr" ecrTypes "github.com/aws/aws-sdk-go-v2/service/ecr/types" "github.com/patrickmn/go-cache" ) type AWSECRClientInterface interface { DescribeRepositories(ctx context.Context, params *ecr.DescribeRepositoriesInput, optFns ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) DescribeImages(ctx context.Context, params *ecr.DescribeImagesInput, optFns ...func(*ecr.Options)) (*ecr.DescribeImagesOutput, error) GetRepositoryPolicy(ctx context.Context, params *ecr.GetRepositoryPolicyInput, optFns ...func(*ecr.Options)) (*ecr.GetRepositoryPolicyOutput, error) } func init() { gob.Register([]ecrTypes.Repository{}) gob.Register([]ecrTypes.ImageDetail{}) gob.Register(ecrTypes.Repository{}) } // create a CachedECRDescribeRepositories function that uses go-cache line the other Cached* functions. It should accept a ecr client, account id, and region. Make sure it handles the region option and pagination if needed func CachedECRDescribeRepositories(ECRClient AWSECRClientInterface, accountID string, region string) ([]ecrTypes.Repository, error) { var PaginationControl *string var repositories []ecrTypes.Repository cacheKey := fmt.Sprintf("%s-ecr-DescribeRepositories-%s", accountID, region) cached, found := internal.Cache.Get(cacheKey) if found { sharedLogger.Debug("Using cached ECR repositories data") return cached.([]ecrTypes.Repository), nil } for { DescribeRepositories, err := ECRClient.DescribeRepositories( context.TODO(), &ecr.DescribeRepositoriesInput{ NextToken: PaginationControl, }, func(o *ecr.Options) { o.Region = region }, ) if err != nil { sharedLogger.Error(err.Error()) break } repositories = append(repositories, DescribeRepositories.Repositories...) // Pagination control. if DescribeRepositories.NextToken != nil { PaginationControl = DescribeRepositories.NextToken } else { PaginationControl = nil break } } internal.Cache.Set(cacheKey, repositories, cache.DefaultExpiration) return repositories, nil } // create a CachedECRDescribeImages function that uses go-cache line the other Cached* functions. It should accept a ecr client, account id, and region. Make sure it handles the region option and pagination if needed func CachedECRDescribeImages(ECRClient AWSECRClientInterface, accountID string, region string, repositoryName string) ([]ecrTypes.ImageDetail, error) { var PaginationControl *string var images []ecrTypes.ImageDetail cacheKey := fmt.Sprintf("%s-ecr-DescribeImages-%s-%s", accountID, region, strings.ReplaceAll(repositoryName, "/", "-")) cached, found := internal.Cache.Get(cacheKey) if found { sharedLogger.Debug("Using cached Images data") return cached.([]ecrTypes.ImageDetail), nil } for { DescribeImages, err := ECRClient.DescribeImages( context.TODO(), &ecr.DescribeImagesInput{ NextToken: PaginationControl, RepositoryName: &repositoryName, }, func(o *ecr.Options) { o.Region = region }, ) if err != nil { sharedLogger.Error(err.Error()) break } images = append(images, DescribeImages.ImageDetails...) // Pagination control. if DescribeImages.NextToken != nil { PaginationControl = DescribeImages.NextToken } else { PaginationControl = nil break } } internal.Cache.Set(cacheKey, images, cache.DefaultExpiration) return images, nil } // create a CachedECRGetRepositoryPolicy function that uses go-cache line the other Cached* functions. It should accept a ecr client, account id, and region. Make sure it handles the region option and pagination if needed func CachedECRGetRepositoryPolicy(ECRClient AWSECRClientInterface, accountID string, region string, repositoryName string) (string, error) { // in repositoryName, replace "/" with "-" cacheKey := fmt.Sprintf("%s-ecr-GetRepositoryPolicy-%s-%s", accountID, region, strings.ReplaceAll(repositoryName, "/", "-")) cached, found := internal.Cache.Get(cacheKey) if found { sharedLogger.Debug("Using cached ECR repository policy data") return cached.(string), nil } GetRepositoryPolicy, err := ECRClient.GetRepositoryPolicy( context.TODO(), &ecr.GetRepositoryPolicyInput{ RepositoryName: &repositoryName, }, func(o *ecr.Options) { o.Region = region }, ) if err != nil { sharedLogger.Error(err.Error()) return "", err } PolicyText := aws.ToString(GetRepositoryPolicy.PolicyText) internal.Cache.Set(cacheKey, PolicyText, cache.DefaultExpiration) return PolicyText, nil }