Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ usage: |-
typically provisioned via the stack for the "artifact" account (typically `auto`, `artifact`, or `corp`) in the primary
region.

```yaml
components:
terraform:
ecr:
Expand All @@ -39,7 +38,14 @@ usage: |-
scan_images_on_push: true
protected_tags:
- prod
image_tag_mutability: MUTABLE
# Tag mutability supports: MUTABLE, IMMUTABLE, IMMUTABLE_WITH_EXCLUSION, MUTABLE_WITH_EXCLUSION
image_tag_mutability: IMMUTABLE_WITH_EXCLUSION
# When using *_WITH_EXCLUSION, specify exclusions to allow certain tags to be mutable
image_tag_mutability_exclusion_filter:
- filter: "latest"
filter_type: "WILDCARD"
- filter: "dev-"
filter_type: "WILDCARD"

images:
- infrastructure
Expand Down
29 changes: 15 additions & 14 deletions src/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,22 @@ locals {

module "ecr" {
source = "cloudposse/ecr/aws"
version = "0.44.0"
version = "1.0.0"

protected_tags = var.protected_tags
protected_tags_keep_count = var.protected_tags_keep_count
enable_lifecycle_policy = var.enable_lifecycle_policy
default_lifecycle_rules_settings = var.default_lifecycle_rules_settings
image_names = var.images
image_tag_mutability = var.image_tag_mutability
max_image_count = var.max_image_count
principals_full_access = compact(concat(module.full_access.principals, [local.ecr_user_arn]))
principals_readonly_access = module.readonly_access.principals
principals_lambda = var.principals_lambda
scan_images_on_push = var.scan_images_on_push
use_fullname = false
replication_configurations = var.replication_configurations
protected_tags = var.protected_tags
protected_tags_keep_count = var.protected_tags_keep_count
enable_lifecycle_policy = var.enable_lifecycle_policy
default_lifecycle_rules_settings = var.default_lifecycle_rules_settings
image_names = var.images
image_tag_mutability = var.image_tag_mutability
image_tag_mutability_exclusion_filter = var.image_tag_mutability_exclusion_filter
max_image_count = var.max_image_count
principals_full_access = compact(concat(module.full_access.principals, [local.ecr_user_arn]))
principals_readonly_access = module.readonly_access.principals
principals_lambda = var.principals_lambda
scan_images_on_push = var.scan_images_on_push
use_fullname = false
replication_configurations = var.replication_configurations

custom_lifecycle_rules = var.custom_lifecycle_rules

Expand Down
27 changes: 26 additions & 1 deletion src/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,35 @@ variable "images" {

variable "image_tag_mutability" {
type = string
description = "The tag mutability setting for the repository. Must be one of: `MUTABLE` or `IMMUTABLE`"
description = "The tag mutability setting for the repository. Must be one of: `MUTABLE`, `IMMUTABLE`, `IMMUTABLE_WITH_EXCLUSION`, or `MUTABLE_WITH_EXCLUSION`"
default = "MUTABLE"
}

variable "image_tag_mutability_exclusion_filter" {
type = list(object({
filter = string
filter_type = optional(string, "WILDCARD")
}))
default = []
description = "List of exclusion filters for image tag mutability. Each filter object must contain 'filter' and 'filter_type' attributes. Requires AWS provider >= 6.8.0"

validation {
condition = alltrue([
for filter in var.image_tag_mutability_exclusion_filter :
contains(["WILDCARD"], filter.filter_type)
])
error_message = "filter_type must be `WILDCARD`"
}

validation {
condition = alltrue([
for filter in var.image_tag_mutability_exclusion_filter :
length(trimspace(filter.filter)) > 0
])
error_message = "filter value cannot be empty or contain only whitespace."
}
}

variable "max_image_count" {
type = number
description = "Max number of images to store. Old ones will be deleted to make room for new ones."
Expand Down
2 changes: 1 addition & 1 deletion src/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.9.0, < 6.0.0"
version = ">= 6.8.0, < 7.0.0"
}
}
}
34 changes: 34 additions & 0 deletions test/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,40 @@ type LifecyclePolicyRuleSelection struct {
CountNumber int `json:"countNumber"`
}

func (s *ComponentSuite) TestImmutabilityExclusions() {
const component = "ecr/immutability-exclusions"
const stack = "default-test"
const awsRegion = "us-east-2"

suffix := strings.ToLower(random.UniqueId())

inputs := map[string]interface{}{
"images": []string{
fmt.Sprintf("infrastructure-%s", suffix),
fmt.Sprintf("microservice-a-%s", suffix),
fmt.Sprintf("microservice-b-%s", suffix),
fmt.Sprintf("microservice-c-%s", suffix),
},
}

defer s.DestroyAtmosComponent(s.T(), component, stack, &inputs)
options, _ := s.DeployAtmosComponent(s.T(), component, stack, &inputs)
assert.NotNil(s.T(), options)

arnMaps := map[string]string{}
atmos.OutputStruct(s.T(), options, "ecr_repo_arn_map", &arnMaps)

for name := range arnMaps {
repository := aws.GetECRRepo(s.T(), awsRegion, name)
// Assert new image tag mutability mode is applied
assert.EqualValues(s.T(), "IMMUTABLE_WITH_EXCLUSION", repository.ImageTagMutability)
// Existing expectations remain
assert.True(s.T(), repository.ImageScanningConfiguration.ScanOnPush)
}

s.DriftTest(component, stack, &inputs)
}

type LifecyclePolicyRule struct {
RulePriority int `json:"rulePriority"`
Description string `json:"description"`
Expand Down
25 changes: 25 additions & 0 deletions test/fixtures/stacks/catalog/usecase/immutability-exclusions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
components:
terraform:
ecr/immutability-exclusions:
metadata:
component: target
vars:
ecr_user_enabled: false
enable_lifecycle_policy: true
max_image_count: 500
scan_images_on_push: true
protected_tags:
- prod
image_tag_mutability: IMMUTABLE_WITH_EXCLUSION
image_tag_mutability_exclusion_filter:
- filter: "latest"
filter_type: "WILDCARD"
- filter: "dev-"
filter_type: "WILDCARD"
images:
- infrastructure
- microservice-a
- microservice-b
- microservice-c
read_write_account_role_map: {}
read_only_account_role_map: {}
1 change: 1 addition & 0 deletions test/fixtures/stacks/orgs/default/test/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ import:
- orgs/default/test/_defaults
- catalog/usecase/basic
- catalog/usecase/disabled
- catalog/usecase/immutability-exclusions
Loading