Skip to content

Commit

Permalink
Merge pull request #103 from eerkunt/feature/improved-regex-matching
Browse files Browse the repository at this point in the history
Feature/improved regex matching
  • Loading branch information
eerkunt authored Jun 25, 2019
2 parents b1f397e + 234d056 commit 5bd3e7f
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 19 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

### 1.6.0 (2019-06-25)
* Improved 'contains' and 'regex' matching steps.

### 1.0.5 (2019-06-24)
* Added basic heredoc support for json strings. ([#90](https://github.com/eerkunt/terraform-compliance/issues/90))
* Added encryption property for (at rest) aws_emr_security_configuration
Expand All @@ -18,7 +21,7 @@
* Fixed an issue where `filetype` module could not be found. ([#97](https://github.com/eerkunt/terraform-compliance/issues/97))
* Upgraded python in Docker image from 3.6.8 to 3.7.3

## 1.0.0 (2019-06-20)
# 1.0.0 (2019-06-20)
**_BREAKING BACKWARD COMPATIBILITY_** for `terraform-compliance` since the parameters has changed. This is a MAJOR upgrade and a re-design of the tool.
* This version only supports `terraform` 0.12.0 and 0.12.1.
* Removed `-t` parameter.
Expand Down
2 changes: 1 addition & 1 deletion example/example_01/aws/naming_standards.feature
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Feature: Resources should have a proper naming standard
| AWS EC2 instance | name |
| AWS ELB resource | name |
| AWS RDS instance | name |
| AWS S3 Bucket | name |
| AWS S3 Bucket | bucket |
| AWS EBS volume | name |
| AWS Auto-Scaling Group | name |
| aws_key_pair | key_name |
Expand Down
2 changes: 1 addition & 1 deletion example/example_01/aws/s3_public_access_block.feature
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature: All AWS environments that has S3 Bucket Public Access Block
Scenario Outline: AWS Credentials should not be hardcoded
Given I have aws_s3_bucket_public_access_block resource configured
Then it must contain <key>
And its value must not match the "true" regex
And its value must match the "true" regex

Examples:
| key |
Expand Down
2 changes: 1 addition & 1 deletion terraform_compliance/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
reinstall_radish()

__app_name__ = "terraform-compliance"
__version__ = "1.0.5"
__version__ = "1.0.6"

print('{} v{} initiated\n'.format(__app_name__, __version__))

Expand Down
47 changes: 32 additions & 15 deletions terraform_compliance/steps/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
import re
from terraform_compliance.common.exceptions import Failure, TerraformComplianceNotImplemented

#TODO: Figure out how the IAM policies/statements shown in the plan.out
#TODO: Implement an IAM Compliance via https://github.com/Netflix-Skunkworks/policyuniverse

# TODO: Figure out how the IAM policies/statements shown in the plan.out
# TODO: Implement an IAM Compliance via https://github.com/Netflix-Skunkworks/policyuniverse


@given(u'I have {name:ANY} defined')
Expand Down Expand Up @@ -78,6 +79,7 @@ def i_have_name_section_configured(_step_obj, name, type_name='resource', _terra

skip_step(_step_obj, name)


@when(u'it contain {something:ANY}')
@when(u'they have {something:ANY}')
@when(u'it has {something:ANY}')
Expand All @@ -96,10 +98,16 @@ def it_condition_contain_something(_step_obj, something):
values = resource.get('values', {})

found_value = None
found_key = None
if type(values) is dict:
found_value = jsonify(values.get(something, None))
found_key = seek_key_in_dict(values, something)
if len(found_key):
found_key = found_key[0]

if type(found_key) is dict:
found_value = jsonify(found_key[something])

if found_value:
if found_key:
prop_list.append({'address': resource['address'],
'values': found_value,
'type': _step_obj.context.name})
Expand Down Expand Up @@ -132,6 +140,7 @@ def it_condition_contain_something(_step_obj, something):
message='Skipping the step since {} type does not have {} property.'.format(_step_obj.context.type,
something))


@then(u'encryption is enabled')
@then(u'encryption must be enabled')
def encryption_is_enabled(_step_obj):
Expand All @@ -158,6 +167,7 @@ def encryption_is_enabled(_step_obj):

return True


@then(u'it must {condition:ANY} have {proto:ANY} protocol and port {port} for {cidr:ANY}')
def it_condition_have_proto_protocol_and_port_port_for_cidr(_step_obj, condition, proto, port, cidr):
proto = str(proto)
Expand Down Expand Up @@ -212,6 +222,7 @@ def i_action_them(_step_obj, action_type):
else:
raise TerraformComplianceNotImplemented("Invalid action_type in the scenario: {}".format(action_type))


@then(u'I expect the result is {operator:ANY} than {number:d}')
def i_expect_the_result_is_operator_than_number(_step_obj, operator, number):
# TODO: Maybe iterate over the stash if it is a list and do the execution per each member ?
Expand All @@ -228,24 +239,24 @@ def i_expect_the_result_is_operator_than_number(_step_obj, operator, number):
else:
raise TerraformComplianceNotImplemented('Invalid operator: {}'.format(operator))


@step(u'its value {condition:ANY} match the "{search_regex}" regex')
def its_value_condition_match_the_search_regex_regex(_step_obj, condition, search_regex, _stash=None):

def fail(condition):
text = 'matches' if condition == 'must not' else 'does not match'
raise Failure('{} property in {} {} {} with {} regex. '
'It is set to {}.'.format(_step_obj.context.property_name,
_step_obj.context.name,
_step_obj.context.type,
text,
regex,
values))
_step_obj.context.name,
_step_obj.context.type,
text,
regex,
values))

regex = r'{}'.format(search_regex)
values = _step_obj.context.stash if _stash is None else _stash

if type(values) is str or type(values) is int:
matches = re.match(regex, values)
if type(values) is str or type(values) is int or type(values) is bool:
matches = re.match(regex, str(values), flags=re.IGNORECASE)

if (condition == 'must' and matches is None) or (condition == "must not" and matches is not None):
fail(condition)
Expand All @@ -255,7 +266,13 @@ def fail(condition):
its_value_condition_match_the_search_regex_regex(_step_obj, condition, search_regex, value)

elif type(values) is dict:
values = seek_regex_key_in_dict_values(values, _step_obj.context.property_name, search_regex)

if (condition == 'must' and values is None) or (condition == "must not" and values is not None):
if values.get('values') is not None:
values = its_value_condition_match_the_search_regex_regex(_step_obj,
condition,
search_regex,
values['values'])
else:
values = seek_regex_key_in_dict_values(values, _step_obj.context.property_name, search_regex)

if (condition == 'must' and values == []) or (condition == "must not" and values != []):
fail(condition)

0 comments on commit 5bd3e7f

Please sign in to comment.