diff --git a/terraform_compliance/common/helper.py b/terraform_compliance/common/helper.py index a9ebac5d..51ab16f6 100644 --- a/terraform_compliance/common/helper.py +++ b/terraform_compliance/common/helper.py @@ -298,3 +298,21 @@ def is_key_exist(key, target_list_of_dict): return True return False + + +def transform_asg_style_tags(resource_list): + if not isinstance(resource_list, list): + return resource_list + + for resource in resource_list: + tag = resource.get('values', {}).get('tag') + + if not resource.get('values', {}).get('tags'): + resource['values']['tags'] = {} + + if tag: + for elem in tag: + if 'key' in elem and 'value' in elem: + resource['values']['tags'][elem['key']] = elem['value'] + + return resource_list diff --git a/terraform_compliance/main.py b/terraform_compliance/main.py index b5f359db..ce93edf1 100644 --- a/terraform_compliance/main.py +++ b/terraform_compliance/main.py @@ -88,15 +88,15 @@ def cli(arghandling=ArgHandling(), argparser=ArgumentParser(prog=__app_name__, if args.exit_on_failure is True: console_write('{} {}\t\t: Scenario executions will stop on first step {}.'.format(Defaults().info_icon, - Defaults().info_colour('INFO'), - Defaults().failure_colour('failure'))) + Defaults().info_colour('INFO'), + Defaults().failure_colour('failure'))) if args.no_failure is True: console_write('{} {}\t: {}ping all {} steps, exit code will always be {}.'.format(Defaults().warning_icon, - Defaults().warning_colour('WARNING'), - Defaults().skip_colour('SKIP'), - Defaults().failure_colour('failure'), - Defaults().info_colour(0))) + Defaults().warning_colour('WARNING'), + Defaults().skip_colour('SKIP'), + Defaults().failure_colour('failure'), + Defaults().info_colour(0))) if Defaults().interactive_mode is False: console_write('{} Running in non-interactive mode.'.format(Defaults().info_icon)) diff --git a/terraform_compliance/steps/steps.py b/terraform_compliance/steps/steps.py index 8284dee6..e810699e 100644 --- a/terraform_compliance/steps/steps.py +++ b/terraform_compliance/steps/steps.py @@ -6,6 +6,7 @@ from terraform_compliance.common.helper import search_regex_in_list, seek_regex_key_in_dict_values, jsonify, Null, EmptyStash from terraform_compliance.common.helper import get_resource_name_from_stash, get_resource_address_list_from_stash from terraform_compliance.common.helper import remove_mounted_resources, search_regex_in_list, seek_value_in_dict +from terraform_compliance.common.helper import transform_asg_style_tags from terraform_compliance.extensions.security_groups import SecurityGroup from terraform_compliance.extensions.ext_radish_bdd import skip_step from terraform_compliance.extensions.ext_radish_bdd import custom_type_any @@ -86,6 +87,7 @@ def i_have_name_section_configured(_step_obj, name, type_name='resource', _terra # We are removing all mounted resources here for future steps, since we don't need them for # tags checking. found_resources = remove_mounted_resources(_terraform_config.config.terraform.find_resources_by_type(resource_type)) + found_resources = transform_asg_style_tags(found_resources) resource_list.extend(found_resources) if resource_list: diff --git a/tests/functional/test_issue-242/.expected b/tests/functional/test_issue-242/.expected new file mode 100644 index 00000000..9ad6b699 --- /dev/null +++ b/tests/functional/test_issue-242/.expected @@ -0,0 +1 @@ +Failure: .* 3 is not equal to 2\. \ No newline at end of file diff --git a/tests/functional/test_issue-242/.failure b/tests/functional/test_issue-242/.failure new file mode 100644 index 00000000..e69de29b diff --git a/tests/functional/test_issue-242/main.tf b/tests/functional/test_issue-242/main.tf new file mode 100644 index 00000000..e3c3fc5d --- /dev/null +++ b/tests/functional/test_issue-242/main.tf @@ -0,0 +1,16 @@ +provider "gsuite" { + oauth_scopes = [ + "https://www.googleapis.com/auth/admin.directory.group", + "https://www.googleapis.com/auth/admin.directory.user" + ] +} + +resource "gsuite_group" "my-group-i" { + email = "my-group-i@mydomain.com" + name = "My Group I" +} + +resource "gsuite_group" "my-group-ii" { + email = "my-group-ii@mydomain.com" + name = "My Group II" +} \ No newline at end of file diff --git a/tests/functional/test_issue-242/plan.out.json b/tests/functional/test_issue-242/plan.out.json new file mode 100644 index 00000000..8965469c --- /dev/null +++ b/tests/functional/test_issue-242/plan.out.json @@ -0,0 +1,623 @@ +{ + "configuration": { + "provider_config": { + "gsuite": { + "expressions": { + "oauth_scopes": { + "constant_value": [ + "https://www.googleapis.com/auth/admin.directory.group", + "https://www.googleapis.com/auth/admin.directory.user" + ] + } + }, + "name": "gsuite" + } + }, + "root_module": { + "module_calls": { + "team_myteam": { + "expressions": { + "team": { + "constant_value": "myteam" + } + }, + "module": { + "outputs": { + "email_level_i": { + "description": "The email created for level I access", + "expression": { + "references": [ + "gsuite_group.gcp-level-i" + ] + } + }, + "email_level_ii": { + "description": "The email created for level II access", + "expression": { + "references": [ + "gsuite_group.gcp-level-ii" + ] + } + }, + "email_level_iii": { + "description": "The email created for level III access", + "expression": { + "references": [ + "gsuite_group.gcp-level-iii" + ] + } + } + }, + "resources": [ + { + "address": "gsuite_group.gcp-level-i", + "expressions": { + "email": { + "references": [ + "var.team" + ] + }, + "name": { + "references": [ + "var.team" + ] + } + }, + "mode": "managed", + "name": "gcp-level-i", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group" + }, + { + "address": "gsuite_group.gcp-level-ii", + "expressions": { + "email": { + "references": [ + "var.team" + ] + }, + "name": { + "references": [ + "var.team" + ] + } + }, + "mode": "managed", + "name": "gcp-level-ii", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group" + }, + { + "address": "gsuite_group.gcp-level-iii", + "expressions": { + "email": { + "references": [ + "var.team" + ] + }, + "name": { + "references": [ + "var.team" + ] + } + }, + "mode": "managed", + "name": "gcp-level-iii", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group" + }, + { + "address": "gsuite_group_members.gcp-level-i", + "expressions": { + "group_email": { + "references": [ + "gsuite_group.gcp-level-i" + ] + } + }, + "mode": "managed", + "name": "gcp-level-i", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group_members" + }, + { + "address": "gsuite_group_members.gcp-level-ii", + "expressions": { + "group_email": { + "references": [ + "gsuite_group.gcp-level-ii" + ] + } + }, + "mode": "managed", + "name": "gcp-level-ii", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group_members" + }, + { + "address": "gsuite_group_members.gcp-level-iii", + "expressions": { + "group_email": { + "references": [ + "gsuite_group.gcp-level-iii" + ] + } + }, + "mode": "managed", + "name": "gcp-level-iii", + "provider_config_key": "team_myteam:gsuite", + "schema_version": 0, + "type": "gsuite_group_members" + } + ], + "variables": { + "team": { + "description": "The name of the team" + } + } + }, + "source": "./team" + } + }, + "outputs": { + "emails": { + "expression": { + "references": [ + "module.team_myteam.email_level_i", + "module.team_myteam.email_level_ii", + "module.team_myteam.email_level_iii" + ] + } + } + }, + "resources": [], + "variables": {} + } + }, + "format_version": "0.1", + "output_changes": { + "emails": { + "actions": [ + "create" + ], + "after": { + "myteam": { + "level-i": "myteam.i@my-company.com.br", + "level-ii": "myteam.ii@my-company.com.br", + "level-iii": "myteam.iii@my-company.com.br" + } + }, + "after_unknown": false, + "before": null + } + }, + "planned_values": { + "outputs": { + "emails": { + "sensitive": false, + "value": { + "myteam": { + "level-i": "myteam.i@my-company.com.br", + "level-ii": "myteam.ii@my-company.com.br", + "level-iii": "myteam.iii@my-company.com.br" + } + } + } + }, + "root_module": { + "child_modules": [ + { + "address": "module.team_myteam", + "resources": [ + { + "address": "module.team_myteam.gsuite_group.gcp-level-i", + "mode": "managed", + "name": "gcp-level-i", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 5, + "email": "myteam.i@my-company.com.br", + "id": "", + "name": "GCP myteam I", + "non_editable_aliases": [] + } + }, + { + "address": "module.team_myteam.gsuite_group.gcp-level-ii", + "mode": "managed", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 2, + "email": "myteam.ii@my-company.com.br", + "id": "", + "name": "GCP myteam II", + "non_editable_aliases": [] + } + }, + { + "address": "module.team_myteam.gsuite_group.gcp-level-iii", + "mode": "managed", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 1, + "email": "myteam.iii@my-company.com.br", + "id": "", + "name": "GCP myteam III", + "non_editable_aliases": [] + } + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-i", + "mode": "managed", + "name": "gcp-level-i", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.i@my-company.com.br", + "id": "", + "member": [] + } + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-ii", + "mode": "managed", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.ii@my-company.com.br", + "id": "", + "member": [] + } + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-iii", + "mode": "managed", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.iii@my-company.com.br", + "id": "", + "member": [] + } + } + ] + } + ], + "resources": [] + } + }, + "prior_state": { + "format_version": "0.1", + "terraform_version": "0.12.24", + "values": { + "outputs": { + "emails": { + "sensitive": false, + "value": { + "myteam": { + "level-i": "myteam.i@my-company.com.br", + "level-ii": "myteam.ii@my-company.com.br", + "level-iii": "myteam.iii@my-company.com.br" + } + } + } + }, + "root_module": { + "child_modules": [ + { + "address": "module.team_myteam", + "resources": [ + { + "address": "gsuite_group.gcp-level-i", + "mode": "managed", + "name": "gcp-level-i", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 5, + "email": "myteam.i@my-company.com.br", + "id": "", + "name": "GCP myteam I", + "non_editable_aliases": [] + } + }, + { + "address": "gsuite_group.gcp-level-ii", + "mode": "managed", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 2, + "email": "myteam.ii@my-company.com.br", + "id": "", + "name": "GCP myteam II", + "non_editable_aliases": [] + } + }, + { + "address": "gsuite_group.gcp-level-iii", + "mode": "managed", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group", + "values": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 1, + "email": "myteam.iii@my-company.com.br", + "id": "", + "name": "GCP myteam III", + "non_editable_aliases": [] + } + }, + { + "address": "gsuite_group_members.gcp-level-i", + "depends_on": [ + "module.team_myteam.gsuite_group.gcp-level-i" + ], + "mode": "managed", + "name": "gcp-level-i", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.i@my-company.com.br", + "id": "", + "member": [] + } + }, + { + "address": "gsuite_group_members.gcp-level-ii", + "depends_on": [ + "module.team_myteam.gsuite_group.gcp-level-ii" + ], + "mode": "managed", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.ii@my-company.com.br", + "id": "", + "member": [] + } + }, + { + "address": "gsuite_group_members.gcp-level-iii", + "depends_on": [ + "module.team_myteam.gsuite_group.gcp-level-iii" + ], + "mode": "managed", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "schema_version": 0, + "type": "gsuite_group_members", + "values": { + "group_email": "myteam.iii@my-company.com.br", + "id": "", + "member": [] + } + } + ] + } + ] + } + } + }, + "resource_changes": [ + { + "address": "module.team_myteam.gsuite_group.gcp-level-i", + "change": { + "actions": [ + "no-op" + ], + "after": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 5, + "email": "myteam.i@my-company.com.br", + "id": "", + "name": "GCP myteam I", + "non_editable_aliases": [] + }, + "after_unknown": {}, + "before": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 5, + "email": "myteam.i@my-company.com.br", + "id": "", + "name": "GCP myteam I", + "non_editable_aliases": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-i", + "provider_name": "gsuite", + "type": "gsuite_group" + }, + { + "address": "module.team_myteam.gsuite_group.gcp-level-ii", + "change": { + "actions": [ + "no-op" + ], + "after": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 2, + "email": "myteam.ii@my-company.com.br", + "id": "", + "name": "GCP myteam II", + "non_editable_aliases": [] + }, + "after_unknown": {}, + "before": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 2, + "email": "myteam.ii@my-company.com.br", + "id": "", + "name": "GCP myteam II", + "non_editable_aliases": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "type": "gsuite_group" + }, + { + "address": "module.team_myteam.gsuite_group.gcp-level-iii", + "change": { + "actions": [ + "no-op" + ], + "after": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 1, + "email": "myteam.iii@my-company.com.br", + "id": "", + "name": "GCP myteam III", + "non_editable_aliases": [] + }, + "after_unknown": {}, + "before": { + "admin_created": true, + "aliases": [], + "description": "", + "direct_members_count": 1, + "email": "myteam.iii@my-company.com.br", + "id": "", + "name": "GCP myteam III", + "non_editable_aliases": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "type": "gsuite_group" + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-i", + "change": { + "actions": [ + "no-op" + ], + "after": { + "group_email": "myteam.i@my-company.com.br", + "id": "", + "member": [] + }, + "after_unknown": {}, + "before": { + "group_email": "myteam.i@my-company.com.br", + "id": "", + "member": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-i", + "provider_name": "gsuite", + "type": "gsuite_group_members" + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-ii", + "change": { + "actions": [ + "no-op" + ], + "after": { + "group_email": "myteam.ii@my-company.com.br", + "id": "", + "member": [] + }, + "after_unknown": {}, + "before": { + "group_email": "myteam.ii@my-company.com.br", + "id": "", + "member": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-ii", + "provider_name": "gsuite", + "type": "gsuite_group_members" + }, + { + "address": "module.team_myteam.gsuite_group_members.gcp-level-iii", + "change": { + "actions": [ + "no-op" + ], + "after": { + "group_email": "myteam.iii@my-company.com.br", + "id": "", + "member": [] + }, + "after_unknown": {}, + "before": { + "group_email": "myteam.iii@my-company.com.br", + "id": "", + "member": [] + } + }, + "mode": "managed", + "module_address": "module.team_myteam", + "name": "gcp-level-iii", + "provider_name": "gsuite", + "type": "gsuite_group_members" + } + ], + "terraform_version": "0.12.24", + "variables": {} +} diff --git a/tests/functional/test_issue-242/test.feature b/tests/functional/test_issue-242/test.feature new file mode 100644 index 00000000..a6dcc576 --- /dev/null +++ b/tests/functional/test_issue-242/test.feature @@ -0,0 +1,7 @@ +Feature: test + + Scenario: Ensure I have all groups + Given I have gsuite_group defined + When it contains email + And I count them + Then its value must be equal to 2 diff --git a/tests/functional/test_issue-243/.expected b/tests/functional/test_issue-243/.expected new file mode 100644 index 00000000..cbb724a2 --- /dev/null +++ b/tests/functional/test_issue-243/.expected @@ -0,0 +1 @@ +Failure: .* does not have service property \ No newline at end of file diff --git a/tests/functional/test_issue-243/.failure b/tests/functional/test_issue-243/.failure new file mode 100644 index 00000000..e69de29b diff --git a/tests/functional/test_issue-243/main.tf b/tests/functional/test_issue-243/main.tf new file mode 100644 index 00000000..c8798a06 --- /dev/null +++ b/tests/functional/test_issue-243/main.tf @@ -0,0 +1,111 @@ +resource "aws_s3_bucket" "success" { + bucket = "succeeded-bucket" + + tags = { + environment = "live" + service = "some service" + } +} + +resource "aws_s3_bucket" "skip" { + bucket = "skipped-bucket" + + tags = { + something = "something else" + } +} + +resource "aws_s3_bucket" "another_skip" { + bucket = "skipped-bucket-2" + + tags = { + environment = "dead" + something = "something else" + } +} + +resource "aws_s3_bucket" "failure" { + bucket = "failed-bucket" + + tags = { + environment = "live" + some_other_tag = "something" + } +} + +resource "aws_s3_bucket" "another_failure" { + bucket = var.bucket_name + + tags = { + environment = "live" + service = "" + } +} + + +variable "bucket_name" { + default = "test" +} + +resource "aws_autoscaling_group" "success" { + name = "test" + min_size = 1 + max_size = 1 + + tag { + key = "environment" + value = "live" + propagate_at_launch = true + } + tag { + key = "service" + value = "some_service" + propagate_at_launch = true + } +} + +resource "aws_autoscaling_group" "skipped" { + name = "test" + min_size = 1 + max_size = 1 + + tag { + key = "environment" + value = "dead" + propagate_at_launch = true + } + tag { + key = "service" + value = "some_service" + propagate_at_launch = true + } +} + +resource "aws_autoscaling_group" "failure_1" { + name = "test_1" + min_size = 1 + max_size = 1 + + tag { + key = "environment" + value = "live" + propagate_at_launch = true + } +} + +resource "aws_autoscaling_group" "failure_2" { + name = "test_2" + min_size = 1 + max_size = 1 + + tag { + key = "environment" + value = "live" + propagate_at_launch = true + } + tag { + key = "service" + value = "" + propagate_at_launch = true + } +} \ No newline at end of file diff --git a/tests/functional/test_issue-243/plan.out.json b/tests/functional/test_issue-243/plan.out.json new file mode 100644 index 00000000..01b93114 --- /dev/null +++ b/tests/functional/test_issue-243/plan.out.json @@ -0,0 +1 @@ +{"format_version":"0.1","terraform_version":"0.12.24","variables":{"bucket_name":{"value":"test"}},"planned_values":{"root_module":{"resources":[{"address":"aws_autoscaling_group.failure_1","mode":"managed","type":"aws_autoscaling_group","name":"failure_1","provider_name":"aws","schema_version":0,"values":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test_1","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null}},{"address":"aws_autoscaling_group.failure_2","mode":"managed","type":"aws_autoscaling_group","name":"failure_2","provider_name":"aws","schema_version":0,"values":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test_2","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"},{"key":"service","propagate_at_launch":true,"value":""}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null}},{"address":"aws_autoscaling_group.skipped","mode":"managed","type":"aws_autoscaling_group","name":"skipped","provider_name":"aws","schema_version":0,"values":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"dead"},{"key":"service","propagate_at_launch":true,"value":"some_service"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null}},{"address":"aws_autoscaling_group.success","mode":"managed","type":"aws_autoscaling_group","name":"success","provider_name":"aws","schema_version":0,"values":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"},{"key":"service","propagate_at_launch":true,"value":"some_service"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null}},{"address":"aws_s3_bucket.another_failure","mode":"managed","type":"aws_s3_bucket","name":"another_failure","provider_name":"aws","schema_version":0,"values":{"acl":"private","bucket":"test","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","service":""},"website":[]}},{"address":"aws_s3_bucket.another_skip","mode":"managed","type":"aws_s3_bucket","name":"another_skip","provider_name":"aws","schema_version":0,"values":{"acl":"private","bucket":"skipped-bucket-2","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"dead","something":"something else"},"website":[]}},{"address":"aws_s3_bucket.failure","mode":"managed","type":"aws_s3_bucket","name":"failure","provider_name":"aws","schema_version":0,"values":{"acl":"private","bucket":"failed-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","some_other_tag":"something"},"website":[]}},{"address":"aws_s3_bucket.skip","mode":"managed","type":"aws_s3_bucket","name":"skip","provider_name":"aws","schema_version":0,"values":{"acl":"private","bucket":"skipped-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"something":"something else"},"website":[]}},{"address":"aws_s3_bucket.success","mode":"managed","type":"aws_s3_bucket","name":"success","provider_name":"aws","schema_version":0,"values":{"acl":"private","bucket":"succeeded-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","service":"some service"},"website":[]}}]}},"resource_changes":[{"address":"aws_autoscaling_group.failure_1","mode":"managed","type":"aws_autoscaling_group","name":"failure_1","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test_1","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null},"after_unknown":{"arn":true,"availability_zones":true,"default_cooldown":true,"desired_capacity":true,"health_check_type":true,"id":true,"initial_lifecycle_hook":[],"launch_template":[],"load_balancers":true,"mixed_instances_policy":[],"service_linked_role_arn":true,"tag":[{}],"target_group_arns":true,"vpc_zone_identifier":true}}},{"address":"aws_autoscaling_group.failure_2","mode":"managed","type":"aws_autoscaling_group","name":"failure_2","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test_2","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"},{"key":"service","propagate_at_launch":true,"value":""}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null},"after_unknown":{"arn":true,"availability_zones":true,"default_cooldown":true,"desired_capacity":true,"health_check_type":true,"id":true,"initial_lifecycle_hook":[],"launch_template":[],"load_balancers":true,"mixed_instances_policy":[],"service_linked_role_arn":true,"tag":[{},{}],"target_group_arns":true,"vpc_zone_identifier":true}}},{"address":"aws_autoscaling_group.skipped","mode":"managed","type":"aws_autoscaling_group","name":"skipped","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"dead"},{"key":"service","propagate_at_launch":true,"value":"some_service"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null},"after_unknown":{"arn":true,"availability_zones":true,"default_cooldown":true,"desired_capacity":true,"health_check_type":true,"id":true,"initial_lifecycle_hook":[],"launch_template":[],"load_balancers":true,"mixed_instances_policy":[],"service_linked_role_arn":true,"tag":[{},{}],"target_group_arns":true,"vpc_zone_identifier":true}}},{"address":"aws_autoscaling_group.success","mode":"managed","type":"aws_autoscaling_group","name":"success","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"enabled_metrics":null,"force_delete":false,"health_check_grace_period":300,"initial_lifecycle_hook":[],"launch_configuration":null,"launch_template":[],"max_instance_lifetime":null,"max_size":1,"metrics_granularity":"1Minute","min_elb_capacity":null,"min_size":1,"mixed_instances_policy":[],"name":"test","name_prefix":null,"placement_group":null,"protect_from_scale_in":false,"suspended_processes":null,"tag":[{"key":"environment","propagate_at_launch":true,"value":"live"},{"key":"service","propagate_at_launch":true,"value":"some_service"}],"tags":null,"termination_policies":null,"timeouts":null,"wait_for_capacity_timeout":"10m","wait_for_elb_capacity":null},"after_unknown":{"arn":true,"availability_zones":true,"default_cooldown":true,"desired_capacity":true,"health_check_type":true,"id":true,"initial_lifecycle_hook":[],"launch_template":[],"load_balancers":true,"mixed_instances_policy":[],"service_linked_role_arn":true,"tag":[{},{}],"target_group_arns":true,"vpc_zone_identifier":true}}},{"address":"aws_s3_bucket.another_failure","mode":"managed","type":"aws_s3_bucket","name":"another_failure","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"acl":"private","bucket":"test","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","service":""},"website":[]},"after_unknown":{"acceleration_status":true,"arn":true,"bucket_domain_name":true,"bucket_regional_domain_name":true,"cors_rule":[],"grant":[],"hosted_zone_id":true,"id":true,"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"region":true,"replication_configuration":[],"request_payer":true,"server_side_encryption_configuration":[],"tags":{},"versioning":true,"website":[],"website_domain":true,"website_endpoint":true}}},{"address":"aws_s3_bucket.another_skip","mode":"managed","type":"aws_s3_bucket","name":"another_skip","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"acl":"private","bucket":"skipped-bucket-2","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"dead","something":"something else"},"website":[]},"after_unknown":{"acceleration_status":true,"arn":true,"bucket_domain_name":true,"bucket_regional_domain_name":true,"cors_rule":[],"grant":[],"hosted_zone_id":true,"id":true,"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"region":true,"replication_configuration":[],"request_payer":true,"server_side_encryption_configuration":[],"tags":{},"versioning":true,"website":[],"website_domain":true,"website_endpoint":true}}},{"address":"aws_s3_bucket.failure","mode":"managed","type":"aws_s3_bucket","name":"failure","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"acl":"private","bucket":"failed-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","some_other_tag":"something"},"website":[]},"after_unknown":{"acceleration_status":true,"arn":true,"bucket_domain_name":true,"bucket_regional_domain_name":true,"cors_rule":[],"grant":[],"hosted_zone_id":true,"id":true,"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"region":true,"replication_configuration":[],"request_payer":true,"server_side_encryption_configuration":[],"tags":{},"versioning":true,"website":[],"website_domain":true,"website_endpoint":true}}},{"address":"aws_s3_bucket.skip","mode":"managed","type":"aws_s3_bucket","name":"skip","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"acl":"private","bucket":"skipped-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"something":"something else"},"website":[]},"after_unknown":{"acceleration_status":true,"arn":true,"bucket_domain_name":true,"bucket_regional_domain_name":true,"cors_rule":[],"grant":[],"hosted_zone_id":true,"id":true,"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"region":true,"replication_configuration":[],"request_payer":true,"server_side_encryption_configuration":[],"tags":{},"versioning":true,"website":[],"website_domain":true,"website_endpoint":true}}},{"address":"aws_s3_bucket.success","mode":"managed","type":"aws_s3_bucket","name":"success","provider_name":"aws","change":{"actions":["create"],"before":null,"after":{"acl":"private","bucket":"succeeded-bucket","bucket_prefix":null,"cors_rule":[],"force_destroy":false,"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"policy":null,"replication_configuration":[],"server_side_encryption_configuration":[],"tags":{"environment":"live","service":"some service"},"website":[]},"after_unknown":{"acceleration_status":true,"arn":true,"bucket_domain_name":true,"bucket_regional_domain_name":true,"cors_rule":[],"grant":[],"hosted_zone_id":true,"id":true,"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"region":true,"replication_configuration":[],"request_payer":true,"server_side_encryption_configuration":[],"tags":{},"versioning":true,"website":[],"website_domain":true,"website_endpoint":true}}}],"configuration":{"root_module":{"resources":[{"address":"aws_autoscaling_group.failure_1","mode":"managed","type":"aws_autoscaling_group","name":"failure_1","provider_config_key":"aws","expressions":{"max_size":{"constant_value":1},"min_size":{"constant_value":1},"name":{"constant_value":"test_1"},"tag":[{"key":{"constant_value":"environment"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"live"}}]},"schema_version":0},{"address":"aws_autoscaling_group.failure_2","mode":"managed","type":"aws_autoscaling_group","name":"failure_2","provider_config_key":"aws","expressions":{"max_size":{"constant_value":1},"min_size":{"constant_value":1},"name":{"constant_value":"test_2"},"tag":[{"key":{"constant_value":"environment"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"live"}},{"key":{"constant_value":"service"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":""}}]},"schema_version":0},{"address":"aws_autoscaling_group.skipped","mode":"managed","type":"aws_autoscaling_group","name":"skipped","provider_config_key":"aws","expressions":{"max_size":{"constant_value":1},"min_size":{"constant_value":1},"name":{"constant_value":"test"},"tag":[{"key":{"constant_value":"environment"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"dead"}},{"key":{"constant_value":"service"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"some_service"}}]},"schema_version":0},{"address":"aws_autoscaling_group.success","mode":"managed","type":"aws_autoscaling_group","name":"success","provider_config_key":"aws","expressions":{"max_size":{"constant_value":1},"min_size":{"constant_value":1},"name":{"constant_value":"test"},"tag":[{"key":{"constant_value":"environment"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"live"}},{"key":{"constant_value":"service"},"propagate_at_launch":{"constant_value":true},"value":{"constant_value":"some_service"}}]},"schema_version":0},{"address":"aws_s3_bucket.another_failure","mode":"managed","type":"aws_s3_bucket","name":"another_failure","provider_config_key":"aws","expressions":{"bucket":{"references":["var.bucket_name"]},"tags":{"constant_value":{"environment":"live","service":""}}},"schema_version":0},{"address":"aws_s3_bucket.another_skip","mode":"managed","type":"aws_s3_bucket","name":"another_skip","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"skipped-bucket-2"},"tags":{"constant_value":{"environment":"dead","something":"something else"}}},"schema_version":0},{"address":"aws_s3_bucket.failure","mode":"managed","type":"aws_s3_bucket","name":"failure","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"failed-bucket"},"tags":{"constant_value":{"environment":"live","some_other_tag":"something"}}},"schema_version":0},{"address":"aws_s3_bucket.skip","mode":"managed","type":"aws_s3_bucket","name":"skip","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"skipped-bucket"},"tags":{"constant_value":{"something":"something else"}}},"schema_version":0},{"address":"aws_s3_bucket.success","mode":"managed","type":"aws_s3_bucket","name":"success","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"succeeded-bucket"},"tags":{"constant_value":{"environment":"live","service":"some service"}}},"schema_version":0}],"variables":{"bucket_name":{"default":"test"}}}}} diff --git a/tests/functional/test_issue-243/plan.out.textClipping b/tests/functional/test_issue-243/plan.out.textClipping new file mode 100644 index 00000000..a6869300 Binary files /dev/null and b/tests/functional/test_issue-243/plan.out.textClipping differ diff --git a/tests/functional/test_issue-243/test.feature b/tests/functional/test_issue-243/test.feature new file mode 100644 index 00000000..1f675b11 --- /dev/null +++ b/tests/functional/test_issue-243/test.feature @@ -0,0 +1,10 @@ +Feature: test + + Scenario: Ensure we have service tag for live environments + Given I have resource that supports tags defined +# When its type is not aws_autoscaling_group + When it contains tags + And its environment is live + Then it must contain service + And its value must not be null + diff --git a/tests/terraform_compliance/common/test_helper.py b/tests/terraform_compliance/common/test_helper.py index 0914276b..0bb8d85d 100644 --- a/tests/terraform_compliance/common/test_helper.py +++ b/tests/terraform_compliance/common/test_helper.py @@ -13,7 +13,8 @@ get_resource_name_from_stash, dict_merge, is_list_of_dict, - is_key_exist + is_key_exist, + transform_asg_style_tags ) @@ -245,3 +246,26 @@ def test_is_key_exist_successes(self): self.assertTrue(is_key_exist('key', [{'key': 'something'}])) self.assertTrue(is_key_exist('key', [{'something': True}, 2, 3, 4, {'key': True}])) self.assertTrue(is_key_exist('key', [{'something': True}, {'key': True}])) + + def test_transform_asg_style_tags_success(self): + resource_list = { + 'address': 'aws_subnet.test', + 'type': 'aws_subnet', + 'name': 'test', + 'values': { + 'tags': None, + 'tag': [ + { + 'key': 'some_key', + 'value': 'some_value' + } + ], + } + } + output = transform_asg_style_tags([resource_list]) + self.assertEqual(output[0]['values']['tags']['some_key'], 'some_value') + + def test_transform_asg_style_tags_return_directly(self): + resource_list = 'abc' + output = transform_asg_style_tags(resource_list) + self.assertEqual(output, 'abc')