Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix its key condition be value #300

Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased
* Fixed faulty over restriction in [Then its singular value condition match the "search_regex" regex](https://terraform-compliance.com/pages/bdd-references/then.html#then-its-singular-value-condition-match-the-search-regex-regex).
- its_key_condition_be_value now abides the two rules: drills down to the value and fails if any resource fails. This could introduce slight backwards incompatibility, but in essence this is a bugfix and not a change.
- Note: (don't put this line into the release) Release with @noskip.

## 1.2.6 (2020-06-12)
* Fixed a bug where failures would break --junit-xml dump. ([#271](https://github.com/eerkunt/terraform-compliance/issues/271))
Expand Down
49 changes: 30 additions & 19 deletions terraform_compliance/steps/then/its_key_condition_be_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
def its_key_condition_be_value(_step_obj, key, condition, value, stash=Null, depth=0):
if condition not in ('must', 'must not'):
raise TerraformComplianceNotImplemented('This step only accepts "must" and "must not" as a condition.')
condition = condition == 'must'

if stash is Null:
stash = _step_obj.context.stash
Expand All @@ -19,32 +20,42 @@ def its_key_condition_be_value(_step_obj, key, condition, value, stash=Null, dep
Error(_step_obj, 'No entities found for this step to process. Check your filtering steps in this scenario.')
return False

obj_address = _step_obj.context.name
if hasattr(_step_obj.context, 'address'):
obj_address = _step_obj.context.address
elif hasattr(_step_obj.context, 'addresses'):
obj_address = ', '.join(_step_obj.context.addresses)

found_values = []
for entity in stash:
if isinstance(entity, dict):
found_values.extend(seek_regex_key_in_dict_values(entity, key, value))
found_value = seek_regex_key_in_dict_values(entity, key, value)
if not found_value and condition:
Error(_step_obj, 'Can not find {} in {} property of {}.'.format(value, key, entity.get('address', obj_address)))
Error(_step_obj, 'Can not find {} in {} property of {}.'.format(value, key, obj_address)) # legacy error message
elif found_value and not condition:
Error(_step_obj, 'Found {}({}) in {} property of {}.'.format(value, ', '.join(found_values), key, obj_address))

found_values.extend(found_value)

elif isinstance(entity, list):
for element in entity:
found_values.extend(its_key_condition_be_value(_step_obj, key, condition, element, entity, depth+1))
elif isinstance(entity ,(str, int, bool)) and (str(entity).lower == key.lower or str(entity) == value.lower):
found_values.append(entity)
dict_entity = {f'not_{str(key)}': entity}
found_value = seek_regex_key_in_dict_values(dict_entity, key, value)
if not found_value and condition:
Error(_step_obj, 'Can not find {} in {} property of {}.'.format(value, key, obj_address))
elif found_value and not condition:
Error(_step_obj, 'Found {}({}) in {} property of {}.'.format(value, ', '.join(found_values), key, obj_address))

# Return the values to the parent call.
if depth > 0:
return found_values
found_values.extend(found_value)

condition = condition == 'must'
found_values = [values for values in found_values if values is not None]
elif isinstance(entity ,(str, int, bool)):
# raise error because you don't have a {key: value}
if (str(entity).lower == key.lower or str(entity) == value.lower) and condition:
Error(_step_obj, 'Value {} found in {} property of {}, but is not in {{key: value}} format.'.format(value, key, obj_address))
if condition:
Error(_step_obj, 'Can not find {} in {} property of {}.'.format(value, key, obj_address))

obj_address = _step_obj.context.name
if hasattr(_step_obj.context, 'address'):
obj_address = _step_obj.context.address
elif hasattr(_step_obj.context, 'addresses'):
obj_address = ', '.join(_step_obj.context.addresses)

if found_values and not condition:
Error(_step_obj, 'Found {}({}) in {} property of {}.'.format(value, ', '.join(found_values), key, obj_address))
elif not found_values and condition:
Error(_step_obj, 'Can not find {} in {} property of {}.'.format(value, key, obj_address))
_step_obj.context.stash = found_values

return True
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Failure: Can not find azurerm_postgresql_configuration in type property of azurerm_postgresql_server.example.
Empty file.
65 changes: 65 additions & 0 deletions tests/functional/test-its_key_condition_be_value-fail/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
resource "azurerm_resource_group" "example" {
name = "testingtfc-rg"
location = "northeurope"
}

resource "azurerm_postgresql_server" "example" {
name = "tfcpostgresql1111"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
sku_name = "B_Gen5_2"
storage_mb = 5120
backup_retention_days = 7
geo_redundant_backup_enabled = false
auto_grow_enabled = true
administrator_login = "admin"
administrator_login_password = "password"
version = "9.5"
ssl_enforcement_enabled = true
}

resource "azurerm_postgresql_configuration" "log_checkpoints" {
name = "log_checkpoints"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "on"
}

resource "azurerm_postgresql_configuration" "log_connections" {
name = "log_connections"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "on"
}

resource "azurerm_postgresql_configuration" "log_disconnections" {
name = "log_disconnections"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "on"
}

resource "azurerm_postgresql_configuration" "log_duration" {
name = "log_duration"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "on"
}

resource "azurerm_postgresql_configuration" "connection_throttling" {
name = "connection_throttling"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "on"
}

resource "azurerm_postgresql_configuration" "log_retention_days" {
name = "log_retention_days"
resource_group_name = azurerm_resource_group.example.name
server_name = azurerm_postgresql_server.example.name
value = "4"
}

provider "azurerm" {
features {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"format_version":"0.1","terraform_version":"0.12.25","planned_values":{"root_module":{"resources":[{"address":"azurerm_postgresql_configuration.connection_throttling","mode":"managed","type":"azurerm_postgresql_configuration","name":"connection_throttling","provider_name":"azurerm","schema_version":0,"values":{"name":"connection_throttling","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"}},{"address":"azurerm_postgresql_configuration.log_checkpoints","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_checkpoints","provider_name":"azurerm","schema_version":0,"values":{"name":"log_checkpoints","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"}},{"address":"azurerm_postgresql_configuration.log_connections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_connections","provider_name":"azurerm","schema_version":0,"values":{"name":"log_connections","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"}},{"address":"azurerm_postgresql_configuration.log_disconnections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_disconnections","provider_name":"azurerm","schema_version":0,"values":{"name":"log_disconnections","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"}},{"address":"azurerm_postgresql_configuration.log_duration","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_duration","provider_name":"azurerm","schema_version":0,"values":{"name":"log_duration","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"}},{"address":"azurerm_postgresql_configuration.log_retention_days","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_retention_days","provider_name":"azurerm","schema_version":0,"values":{"name":"log_retention_days","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"4"}},{"address":"azurerm_postgresql_server.example","mode":"managed","type":"azurerm_postgresql_server","name":"example","provider_name":"azurerm","schema_version":0,"values":{"administrator_login":"admin","administrator_login_password":"password","auto_grow_enabled":true,"backup_retention_days":7,"create_mode":"Default","creation_source_server_id":null,"geo_redundant_backup_enabled":false,"infrastructure_encryption_enabled":null,"location":"northeurope","name":"tfcpostgresql1111","public_network_access_enabled":true,"resource_group_name":"testingtfc-rg","restore_point_in_time":null,"sku_name":"B_Gen5_2","ssl_enforcement_enabled":true,"ssl_minimal_tls_version_enforced":"TLSEnforcementDisabled","storage_mb":5120,"tags":null,"threat_detection_policy":[],"timeouts":null,"version":"9.5"}},{"address":"azurerm_resource_group.example","mode":"managed","type":"azurerm_resource_group","name":"example","provider_name":"azurerm","schema_version":0,"values":{"location":"northeurope","name":"testingtfc-rg","tags":null,"timeouts":null}}]}},"resource_changes":[{"address":"azurerm_postgresql_configuration.connection_throttling","mode":"managed","type":"azurerm_postgresql_configuration","name":"connection_throttling","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"connection_throttling","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_configuration.log_checkpoints","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_checkpoints","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"log_checkpoints","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_configuration.log_connections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_connections","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"log_connections","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_configuration.log_disconnections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_disconnections","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"log_disconnections","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_configuration.log_duration","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_duration","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"log_duration","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"on"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_configuration.log_retention_days","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_retention_days","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"name":"log_retention_days","resource_group_name":"testingtfc-rg","server_name":"tfcpostgresql1111","timeouts":null,"value":"4"},"after_unknown":{"id":true}}},{"address":"azurerm_postgresql_server.example","mode":"managed","type":"azurerm_postgresql_server","name":"example","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"administrator_login":"admin","administrator_login_password":"password","auto_grow_enabled":true,"backup_retention_days":7,"create_mode":"Default","creation_source_server_id":null,"geo_redundant_backup_enabled":false,"infrastructure_encryption_enabled":null,"location":"northeurope","name":"tfcpostgresql1111","public_network_access_enabled":true,"resource_group_name":"testingtfc-rg","restore_point_in_time":null,"sku_name":"B_Gen5_2","ssl_enforcement_enabled":true,"ssl_minimal_tls_version_enforced":"TLSEnforcementDisabled","storage_mb":5120,"tags":null,"threat_detection_policy":[],"timeouts":null,"version":"9.5"},"after_unknown":{"fqdn":true,"id":true,"ssl_enforcement":true,"storage_profile":true,"threat_detection_policy":[]}}},{"address":"azurerm_resource_group.example","mode":"managed","type":"azurerm_resource_group","name":"example","provider_name":"azurerm","change":{"actions":["create"],"before":null,"after":{"location":"northeurope","name":"testingtfc-rg","tags":null,"timeouts":null},"after_unknown":{"id":true}}}],"configuration":{"provider_config":{"azurerm":{"name":"azurerm","expressions":{"features":[{}]}}},"root_module":{"resources":[{"address":"azurerm_postgresql_configuration.connection_throttling","mode":"managed","type":"azurerm_postgresql_configuration","name":"connection_throttling","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"connection_throttling"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"on"}},"schema_version":0},{"address":"azurerm_postgresql_configuration.log_checkpoints","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_checkpoints","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"log_checkpoints"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"on"}},"schema_version":0},{"address":"azurerm_postgresql_configuration.log_connections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_connections","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"log_connections"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"on"}},"schema_version":0},{"address":"azurerm_postgresql_configuration.log_disconnections","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_disconnections","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"log_disconnections"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"on"}},"schema_version":0},{"address":"azurerm_postgresql_configuration.log_duration","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_duration","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"log_duration"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"on"}},"schema_version":0},{"address":"azurerm_postgresql_configuration.log_retention_days","mode":"managed","type":"azurerm_postgresql_configuration","name":"log_retention_days","provider_config_key":"azurerm","expressions":{"name":{"constant_value":"log_retention_days"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"server_name":{"references":["azurerm_postgresql_server.example"]},"value":{"constant_value":"4"}},"schema_version":0},{"address":"azurerm_postgresql_server.example","mode":"managed","type":"azurerm_postgresql_server","name":"example","provider_config_key":"azurerm","expressions":{"administrator_login":{"constant_value":"admin"},"administrator_login_password":{"constant_value":"password"},"auto_grow_enabled":{"constant_value":true},"backup_retention_days":{"constant_value":7},"geo_redundant_backup_enabled":{"constant_value":false},"location":{"references":["azurerm_resource_group.example"]},"name":{"constant_value":"tfcpostgresql1111"},"resource_group_name":{"references":["azurerm_resource_group.example"]},"sku_name":{"constant_value":"B_Gen5_2"},"ssl_enforcement_enabled":{"constant_value":true},"storage_mb":{"constant_value":5120},"version":{"constant_value":"9.5"}},"schema_version":0},{"address":"azurerm_resource_group.example","mode":"managed","type":"azurerm_resource_group","name":"example","provider_config_key":"azurerm","expressions":{"location":{"constant_value":"northeurope"},"name":{"constant_value":"testingtfc-rg"}},"schema_version":0}]}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature: Feature for #291 continued
Shoul fail, because not every resources type is azurerm_postgresql_configuration

Scenario: Scenario for issue #291
Given I have any resource defined
Then its type must be azurerm_postgresql_configuration
20 changes: 20 additions & 0 deletions tests/functional/test_issue-234-egress/test.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Feature: test egress

Background: Application load balancer security group allows load balancer to communicate with itself
Given I have aws_security_group_rule defined
When its security_group_id reference is aws_security_group.alb
And its type is egress

Scenario: Success #0
Then its protocol must be tcp

Scenario: Success #1
Then its from_port must be 0

Scenario: Success #2
Then its to_port must be 65535

Scenario: Success #3
Then it must contain self
Then its value must be true

45 changes: 45 additions & 0 deletions tests/functional/test_issue-234-ingress/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
resource "aws_security_group" "alb" {
name = "alb-sg"
description = "Act as identifier of this ALB to be used as source security group in other rules. Allows outbound traffic back to origin network"
vpc_id = var.vpc_id
}

resource "aws_security_group_rule" "alb_ingress_self" {
type = "ingress"
description = "Allow ALB to communicate with itself (ingress)"
security_group_id = aws_security_group.alb.id
protocol = "tcp"
from_port = 0
to_port = 65535
self = true
}

resource "aws_security_group_rule" "alb_egress_self" {
type = "egress"
description = "Allow ALB to communicate with itself (egress)"
security_group_id = aws_security_group.alb.id
protocol = "tcp"
from_port = 0
to_port = 65535
self = true
}

resource "aws_security_group" "alb_ecs" {
name = "alb-ecs-access"
description = "Allow ALB access to ECS task(s)"
vpc_id = var.vpc_id
}

resource "aws_security_group_rule" "alb_ecs_ingress" {
type = "ingress"
description = "Allow ALB to communicate with ECS tasks on port 8080"
security_group_id = aws_security_group.alb_ecs.id
protocol = "tcp"
from_port = 8080
to_port = 8080
source_security_group_id = aws_security_group.alb.id
}

variable "vpc_id" {
default = "test_vpc"
}
Loading