diff --git a/cmd/drone-ecr/main.go b/cmd/drone-ecr/main.go index ae268299..956f1f55 100644 --- a/cmd/drone-ecr/main.go +++ b/cmd/drone-ecr/main.go @@ -42,6 +42,7 @@ func main() { assumeRole = getenv("PLUGIN_ASSUME_ROLE") externalId = getenv("PLUGIN_EXTERNAL_ID") scanOnPush = parseBoolOrDefault(false, getenv("PLUGIN_SCAN_ON_PUSH")) + tagImmutable = parseBoolOrDefault(false, getenv("PLUGIN_TAG_IMMUTABLE")) idToken = os.Getenv("PLUGIN_OIDC_TOKEN_ID") ) @@ -78,7 +79,7 @@ func main() { } if create { - err = ensureRepoExists(svc, trimHostname(repo, registry), scanOnPush) + err = ensureRepoExists(svc, trimHostname(repo, registry), scanOnPush, getTagMutabilityString(tagImmutable)) if err != nil { log.Fatal(fmt.Sprintf("error creating ECR repo: %v", err)) } @@ -86,6 +87,10 @@ func main() { if err != nil { log.Fatal(fmt.Sprintf("error updating scan on push for ECR repo: %v", err)) } + err = updateImageTagMutabilityConfig(svc, trimHostname(repo, registry), getTagMutabilityString(tagImmutable)) + if err != nil { + log.Fatal(fmt.Sprintf("error updating tag mutability for ECR repo: %v", err)) + } } if lifecyclePolicy != "" { @@ -129,10 +134,11 @@ func trimHostname(repo, registry string) string { return repo } -func ensureRepoExists(svc *ecr.ECR, name string, scanOnPush bool) (err error) { +func ensureRepoExists(svc *ecr.ECR, name string, scanOnPush bool, tagMutabilityOption string) (err error) { input := &ecr.CreateRepositoryInput{} input.SetRepositoryName(name) input.SetImageScanningConfiguration(&ecr.ImageScanningConfiguration{ScanOnPush: &scanOnPush}) + input.SetImageTagMutability(tagMutabilityOption) _, err = svc.CreateRepository(input) if err != nil { if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ecr.ErrCodeRepositoryAlreadyExistsException { @@ -153,6 +159,15 @@ func updateImageScannningConfig(svc *ecr.ECR, name string, scanOnPush bool) (err return err } +func updateImageTagMutabilityConfig(svc *ecr.ECR, name string, tagMutabilityOption string) (err error) { + input := &ecr.PutImageTagMutabilityInput{} + input.SetRepositoryName(name) + input.SetImageTagMutability(tagMutabilityOption) + _, err = svc.PutImageTagMutability(input) + + return err +} + func uploadLifeCyclePolicy(svc *ecr.ECR, lifecyclePolicy string, name string) (err error) { input := &ecr.PutLifecyclePolicyInput{} input.SetLifecyclePolicyText(lifecyclePolicy) @@ -204,6 +219,14 @@ func parseBoolOrDefault(defaultValue bool, s string) (result bool) { return } +func getTagMutabilityString(tagImmutable bool) string { + immutableTagInput := ecr.ImageTagMutabilityMutable + if tagImmutable { + immutableTagInput = ecr.ImageTagMutabilityImmutable + } + return immutableTagInput +} + func getenv(key ...string) (s string) { for _, k := range key { s = os.Getenv(k) diff --git a/cmd/drone-ecr/main_test.go b/cmd/drone-ecr/main_test.go index 5c50ba55..6cd19af2 100644 --- a/cmd/drone-ecr/main_test.go +++ b/cmd/drone-ecr/main_test.go @@ -1,6 +1,10 @@ package main -import "testing" +import ( + "testing" + + "github.com/aws/aws-sdk-go/service/ecr" +) func TestTrimHostname(t *testing.T) { registry := "000000000000.dkr.ecr.us-east-1.amazonaws.com" @@ -18,3 +22,31 @@ func TestTrimHostname(t *testing.T) { } } } + +func TestGetTagMutabilityString(t *testing.T) { + testCases := []struct { + name string + tagImmutable bool + expected string + }{ + { + name: "mutable", + tagImmutable: false, + expected: ecr.ImageTagMutabilityMutable, + }, + { + name: "immutable", + tagImmutable: true, + expected: ecr.ImageTagMutabilityImmutable, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := getTagMutabilityString(tc.tagImmutable) + if actual != tc.expected { + t.Errorf("expected: %s, actual: %s", tc.expected, actual) + } + }) + } +}