예제 #1
0
    def _parse_configurations(self):
        '''
        Assigns all configuration related data defined in the terraform plan. This is mostly used for
        resources referencing each other.

        :return: none
        '''

        # Resources
        self.configuration['resources'] = {}

        for findings in seek_key_in_dict(self.raw.get('configuration', {}).get('root_module', {}), 'resources'):
            for resource in findings.get('resources', []):
                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.configuration['resources'][resource['address']] = resource

        # Variables
        self.configuration['variables'] = {}
        for findings in seek_key_in_dict(self.raw.get('configuration', {}).get('root_module', {}), 'variables'):
            self.configuration['variables'] = findings.get('variables')

        # Providers
        self.configuration['providers'] = {}
        for findings in seek_key_in_dict(self.raw.get('configuration', {}), 'provider_config'):
            self.configuration['providers'] = findings.get('provider_config', {})

        # Outputs
        self.configuration['outputs'] = {}
        for findings in seek_key_in_dict(self.raw.get('configuration', {}), 'outputs'):
            for key, value in findings.get('outputs', {}).items():
                tmp_output = dict(address=key, value={})
                if 'expression' in value:
                    if 'references' in value['expression']:
                        tmp_output['value'] = value['expression']['references']
                        tmp_output['type'] = 'object'
                    elif 'constant_value' in value['expression']:
                        tmp_output['value'] = value['expression']['constant_value']

                if 'sensitive' in value:
                    tmp_output['sensitive'] = str(value['sensitive']).lower()
                else:
                    tmp_output['sensitive'] = 'false'

                if 'type' in value:
                    tmp_output['type'] = value['type']
                elif 'type' not in tmp_output:
                    if isinstance(tmp_output['value'], list):
                        tmp_output['type'] = 'list'
                    elif isinstance(tmp_output['value'], dict):
                        tmp_output['type'] = 'map'
                    elif isinstance(tmp_output['value'], str):
                        tmp_output['type'] = 'string'
                    elif isinstance(tmp_output['value'], int):
                        tmp_output['type'] = 'integer'
                    elif isinstance(tmp_output['value'], bool):
                        tmp_output['type'] = 'boolean'

                self.configuration['outputs'][key] = tmp_output
    def _parse_configurations(self):
        '''
        Assigns all configuration related data defined in the terraform plan. This is mostly used for
        resources referencing each other.

        :return: none
        '''

        # Resources
        self.configuration['resources'] = dict()
        for findings in seek_key_in_dict(
                self.raw.get('configuration', {}).get('root_module', {}),
                'resources'):
            for resource in findings.get('resources', []):
                if resource['address'].startswith('data'):
                    self.data[resource['address']] = resource
                else:
                    self.configuration['resources'][
                        resource['address']] = resource

        # Variables
        self.configuration['variables'] = dict()
        for findings in seek_key_in_dict(
                self.raw.get('configuration', {}).get('root_module', {}),
                'variables'):
            self.configuration['variables'] = findings.get('variables', {})

        # Providers
        self.configuration['providers'] = dict()
        for findings in seek_key_in_dict(self.raw.get('configuration', {}),
                                         'provider_config'):
            self.configuration['providers'] = findings.get(
                'provider_config', {})
예제 #3
0
    def _parse_resources(self):
        '''
        Assigns all resources defined in the terraform plan

        :return: none
        '''

        # Resources ( exists in Plan )
        for findings in seek_key_in_dict(self.raw.get('planned_values', {}).get('root_module', {}), 'resources'):
            for resource in findings.get('resources', []):
                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Resources ( exists in State )
        for findings in seek_key_in_dict(self.raw.get('values', {}).get('root_module', {}), 'resources'):
            for resource in findings.get('resources', []):
                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Resources ( exists in Prior State )
        for findings in seek_key_in_dict(self.raw.get('prior_state', {}).get('values', {}).get('root_module', {}).get('resources', {}), 'resource'):
            for resource in findings.get('resources', []):
                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Child Modules Resources ( exists in State )
        for findings in seek_key_in_dict(self.raw.get('values', {}).get('root_module', {}), 'child_modules'):
            for resource in findings.get('resources', []):
                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Resource Changes ( exists in Plan )
        for finding in self.raw.get('resource_changes', {}):
            resource = deepcopy(finding)
            change = resource.get('change', {})
            actions = change.get('actions', [])
            if actions != ['delete']:
                resource['values'] = dict_merge(change.get('after', {}), change.get('after_unknown', {}))
                if 'change' in resource:
                    del resource['change']

                if self.is_type(resource, 'data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource
예제 #4
0
    def _parse_resources(self):
        '''
        Assigns all resources defined in the terraform plan

        :return: none
        '''

        #TODO: Consider about using 'resource_changes' instead of 'resources'

        # Resources ( exists in Plan )
        for findings in seek_key_in_dict(
                self.raw.get('planned_values', {}).get('root_module', {}),
                'resources'):
            for resource in findings.get('resources', []):
                if resource['address'].startswith('data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Resources ( exists in State )
        for findings in seek_key_in_dict(
                self.raw.get('values', {}).get('root_module', {}),
                'resources'):
            for resource in findings.get('resources', []):
                if resource['address'].startswith('data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Resources ( exists in Prior State )
        for findings in seek_key_in_dict(
                self.raw.get('prior_state',
                             {}).get('values',
                                     {}).get('root_module',
                                             {}).get('resources', {}),
                'resource'):
            for resource in findings.get('resources', []):
                if resource['address'].startswith('data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource

        # Child Modules Resources ( exists in State )
        for findings in seek_key_in_dict(
                self.raw.get('values', {}).get('root_module', {}),
                'child_modules'):
            for resource in findings.get('resources', []):
                if resource['address'].startswith('data'):
                    self.data[resource['address']] = resource
                else:
                    self.resources[resource['address']] = resource
예제 #5
0
def encryption_is_enabled(_step_obj):
    for resource in _step_obj.context.stash:
        if type(resource) is dict:
            prop = encryption_property.get(resource['type'], None)

            if not prop:
                raise TerraformComplianceNotImplemented(
                    'Encryption property for {} '
                    'is not implemented yet.'.format(resource['type']))

            encryption_value = seek_key_in_dict(
                resource.get('values', {}),
                encryption_property[resource['type']])

            if len(encryption_value):
                encryption_value = encryption_value[0]

                if type(encryption_value) is dict:
                    encryption_value = encryption_value[encryption_property[
                        resource['type']]]

            if not encryption_value:
                raise Failure(
                    'Resource {} does not have encryption enabled ({}={}).'.
                    format(resource['address'], prop, encryption_value))

    return True
예제 #6
0
def i_action_them(_step_obj, action_type):
    if action_type == "count":
        # WARNING: Only case where we set stash as a dictionary, instead of a list.
        if isinstance(_step_obj.context.stash, list):

            # This means we are directly started counting without drilling down any property
            # Thus, our target for the count is stash itself.
            if _step_obj.context.property_name in types_list:
                _step_obj.context.stash = dict(
                    values=len(_step_obj.context.stash))

            else:
                if isinstance(_step_obj.context.stash[0], dict):
                    if _step_obj.context.stash[0].get('values'):
                        _step_obj.context.stash = seek_key_in_dict(
                            _step_obj.context.stash, 'values')
                        count = 0
                        for result in _step_obj.context.stash:
                            count += len(result.get(
                                'values', {})) if result.get('values') else 1

                        _step_obj.context.stash = dict(values=count)

                else:
                    _step_obj.context.stash = dict(
                        values=len(_step_obj.context.stash))
    else:
        raise TerraformComplianceNotImplemented(
            'Invalid action_type in the scenario: {}'.format(action_type))
예제 #7
0
    def test_seek_in_dict_for_root_and_non_root_values(self):
        dictionary = dict(a=dict(b=dict(something=dict(test=[]))),
                          something=["b"])
        search_key = "something"
        expected = [{'something': {'test': []}}, {'something': ['b']}]

        self.assertEqual(seek_key_in_dict(dictionary, search_key), expected)
예제 #8
0
    def test_seek_in_dict_finding_multiple_keys_in_nested_dict(self):
        dictionary = dict(search_key=dict(
            something=dict(something_else=None, something=['something_else'])),
                          something=[])
        search_key = 'something'
        expected = [{
            'something': {
                'something_else': None,
                'something': ['something_else']
            }
        }, {
            'something': []
        }]

        self.assertEqual(seek_key_in_dict(dictionary, search_key), expected)
예제 #9
0
def i_action_them(_step_obj, action_type):
    if action_type == "count":
        # WARNING: Only case where we set stash as a dictionary, instead of a list.
        if type(_step_obj.context.stash) is list:
            if type(_step_obj.context.stash[0]) is dict():
                if _step_obj.context.stash.get('values'):
                    _step_obj.context.stash = seek_key_in_dict(_step_obj.context.stash, 'values')
                    count = 0
                    for result in _step_obj.context.stash:
                        count += len(result.get('values', {})) if result.get('values') else 1

                    _step_obj.context.stash = {'values': count}
            else:
                _step_obj.context.stash = {'values': len(_step_obj.context.stash)}
    else:
        raise TerraformComplianceNotImplemented('Invalid action_type in the scenario: {}'.format(action_type))
예제 #10
0
def property_is_enabled(_step_obj, something):
    for resource in _step_obj.context.stash:
        if type(resource) is dict:
            if something in property_match_list:
                something = property_match_list[something].get(resource['type'], something)

            property_value = seek_key_in_dict(resource.get('values', {}), something)

            if len(property_value):
                property_value = property_value[0]

                if type(property_value) is dict:
                    property_value = property_value.get(something, Null)

            if not property_value:
                raise Failure('Resource {} does not have {} property enabled ({}={}).'.format(resource.get('address', "resource"),
                                                                                              something,
                                                                                              something,
                                                                                              property_value))
    return True
예제 #11
0
파일: terraform.py 프로젝트: sleightsec/cli
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var.', 'each.')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = {}
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    references = seek_key_in_dict(
                        value, 'references') if isinstance(
                            value, (dict, list)) else []

                    valid_references = []
                    for ref in references:
                        if isinstance(ref, dict) and ref.get('references'):
                            valid_references = [
                                r for r in ref['references']
                                if not r.startswith(invalid_references)
                            ]

                    for ref in valid_references:
                        if key not in ref_list:
                            ref_list[key] = self._find_resource_from_name(ref)
                        else:
                            ref_list[key].extend(
                                self._find_resource_from_name(ref))

                    # This is where we synchronise constant_value in the configuration section with the resource
                    # for filling up the missing elements that hasn't been defined in the resource due to provider
                    # implementation.
                    target_resource = [
                        t for t in
                        [self.resources.get(resource, {}).get('address')]
                        if t is not None
                    ]
                    if not target_resource:
                        target_resource = [
                            k for k in self.resources.keys()
                            if k.startswith(resource)
                        ]

                    for t_r in target_resource:
                        if type(value) is type(
                                self.resources[t_r]['values'].get(key)
                        ) and self.resources[t_r]['values'].get(key) != value:
                            if isinstance(value, (list, dict)):
                                merge_dicts(self.resources[t_r]['values'][key],
                                            value)

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type', {})

                    if 'references' in ref_type:
                        ref_type = resource.split('.')[0]

                    if not ref_type and not self.is_type(resource, 'data'):
                        resource_type, resource_id = resource.split('.')
                        ref_type = resource_type

                    for k, v in ref_list.items():
                        v = flatten_list(v)

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source=source_resources,
                                          target=ref_list,
                                          ref_type=ref_type)

                    # Mounting B->A
                    for parameter, target_resources in ref_list.items():
                        for target_resource in target_resources:
                            if not self.is_type(
                                    resource, 'data') and not self.is_type(
                                        resource, 'var') and not self.is_type(
                                            resource, 'provider'):
                                ref_type = target_resource.split('.',
                                                                 maxsplit=1)[0]

                                self._mount_resources(
                                    source=[target_resource],
                                    target={parameter: source_resources},
                                    ref_type=ref_type)
    def _mount_references(self):
        '''
        Find the references that is defined in self.configuration
        :return:
        '''
        self.resources_raw = deepcopy(self.resources)
        invalid_references = ('var.', 'each.')

        # This section will link resources found in configuration part of the plan output.
        # The reference should be on both ways (A->B, B->A) since terraform sometimes report these references
        # in opposite ways, depending on the provider structure.
        for resource in self.configuration['resources']:
            if 'expressions' in self.configuration['resources'][resource]:
                ref_list = {}
                for key, value in self.configuration['resources'][resource][
                        'expressions'].items():
                    references = seek_key_in_dict(
                        value, 'references') if isinstance(
                            value, (dict, list)) else []

                    valid_references = []
                    for ref in references:
                        if isinstance(ref, dict) and ref.get('references'):
                            valid_references = [
                                r for r in ref['references']
                                if not r.startswith(invalid_references)
                            ]

                    for ref in valid_references:
                        # if ref is not in the correct format, handle it
                        if len(ref.split('.')) < 3 and ref.startswith(
                                'module'):

                            # Using for_each and modules together may introduce an issue where the plan.out.json won't include the necessary third part of the reference
                            # It is partially resolved by mounting the reference to all instances belonging to the module
                            if 'for_each_expression' in self.configuration[
                                    'resources'][resource]:

                                # extract source resources
                                assumed_source_resources = [
                                    k for k in self.resources.keys()
                                    if k.startswith(resource)
                                ]
                                # extract for_each keys
                                assumed_for_each_keys = [
                                    k[len(resource):].split('.')[0]
                                    for k in assumed_source_resources
                                ]
                                # combine ref with for each keys
                                assumed_refs = [
                                    '{}{}'.format(ref, key)
                                    for key in assumed_for_each_keys
                                ]
                                # get all the resources that start with updated ref
                                ambigious_references = []
                                for r in self.resources.keys():
                                    for assumed_ref in assumed_refs:
                                        if r.startswith(assumed_ref):
                                            if key in ref_list:
                                                ref_list[key].append(r)
                                            else:
                                                ref_list[key] = [r]

                                            ambigious_references.append(r)

                                # throw a warning
                                defaults = Defaults()
                                console_write('{} {}: {}'.format(
                                    defaults.warning_icon,
                                    defaults.warning_colour(
                                        'WARNING (Mounting)'),
                                    defaults.info_colour(
                                        'The reference "{}" in resource {} is ambigious.'
                                        ' It will be mounted to the following resources:'
                                    ).format(ref, resource)))
                                for i, r in enumerate(ambigious_references, 1):
                                    console_write(
                                        defaults.info_colour('{}. {}'.format(
                                            i, r)))

                            # if the reference can not be resolved, warn the user and continue.
                            else:
                                console_write('{} {}: {}'.format(
                                    Defaults().warning_icon,
                                    Defaults().warning_colour(
                                        'WARNING (Mounting)'),
                                    Defaults().info_colour(
                                        'The reference "{}" in resource {} is ambigious. It will not be mounted.'
                                        .format(ref, resource))))
                                continue
                        elif key not in ref_list:
                            ref_list[key] = self._find_resource_from_name(ref)
                        else:
                            ref_list[key].extend(
                                self._find_resource_from_name(ref))

                    # This is where we synchronise constant_value in the configuration section with the resource
                    # for filling up the missing elements that hasn't been defined in the resource due to provider
                    # implementation.
                    target_resource = [
                        t for t in
                        [self.resources.get(resource, {}).get('address')]
                        if t is not None
                    ]
                    if not target_resource:
                        target_resource = [
                            k for k in self.resources.keys()
                            if k.startswith(resource)
                        ]

                    for t_r in target_resource:
                        if type(value) is type(
                                self.resources[t_r]['values'].get(key)
                        ) and self.resources[t_r]['values'].get(key) != value:
                            if isinstance(value, (list, dict)):
                                merge_dicts(self.resources[t_r]['values'][key],
                                            value)

                if ref_list:
                    ref_type = self.configuration['resources'][resource][
                        'expressions'].get('type', {})

                    if 'references' in ref_type:
                        ref_type = resource.split('.')[0]

                    if not ref_type and not self.is_type(resource, 'data'):
                        ref_type = self.extract_resource_type_from_address(
                            resource)

                    for k, v in ref_list.items():
                        v = flatten_list(v)

                    # Mounting A->B
                    source_resources = self._find_resource_from_name(
                        self.configuration['resources'][resource]['address'])
                    self._mount_resources(source=source_resources,
                                          target=ref_list,
                                          ref_type=ref_type)

                    # Mounting B->A
                    for parameter, target_resources in ref_list.items():
                        for target_resource in target_resources:
                            if not self.is_type(
                                    resource, 'data') and not self.is_type(
                                        resource, 'var') and not self.is_type(
                                            resource, 'provider'):
                                ref_type = self.extract_resource_type_from_address(
                                    target_resource)

                                self._mount_resources(
                                    source=[target_resource],
                                    target={parameter: source_resources},
                                    ref_type=ref_type)
예제 #13
0
def it_condition_contain_something(_step_obj, something):
    prop_list = []

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if type(resource) is not dict:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            values = resource.get('values', resource.get('expressions', {}))

            found_value = Null
            found_key = Null
            if type(values) is dict:
                found_key = values.get(something,
                                       seek_key_in_dict(values, something))
                if type(found_key) is not list:
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(
                        found_key) == 1 else found_key

                    if type(found_key) is dict:
                        found_value = jsonify(
                            found_key.get(something, found_key))
                    else:
                        found_value = found_key
            elif type(values) is list:
                found_value = []

                for value in values:

                    if type(value) is dict:
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(
                            found_key) == 1 else found_key

                        if type(found_key) is dict:
                            found_value.append(
                                jsonify(found_key.get(something, found_key)))

            if type(found_value) is dict and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value is not Null and found_value != [] and found_value != '' and found_value != {}:
                prop_list.append({
                    'address': resource['address'],
                    'values': found_value,
                    'type': _step_obj.context.name
                })

            elif 'must' in _step_obj.context_sensitive_sentence:
                raise Failure('{} ({}) does not have {} property.'.format(
                    resource['address'], resource.get('type', ''), something))

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something
            return True

        skip_step(_step_obj,
                  resource=_step_obj.context.name,
                  message='Can not find any {} property for {} resource in '
                  'terraform plan.'.format(something, _step_obj.context.name))

    elif _step_obj.context.type == 'provider':
        values = seek_key_in_dict(_step_obj.context.stash, something)

        if values:
            _step_obj.context.stash = values
            _step_obj.context.property_name = something
            return True

    skip_step(
        _step_obj,
        resource=_step_obj.context.name,
        message='Skipping the step since {} type does not have {} property.'.
        format(_step_obj.context.type, something))
예제 #14
0
def it_must_contain_something(_step_obj, something, inherited_values=Null):
    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = values.get(something,
                                       seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(
                        found_key
                    ) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = jsonify(
                            found_key.get(something, found_key))
                        found_value = found_value if found_value not in (
                            [], '') else found_key
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break
                    elif isinstance(value, list):
                        found_key, found_value = it_must_contain_something(
                            _step_obj, something, value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(
                            found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(
                                jsonify(found_key.get(something, found_key)))

            if isinstance(found_value,
                          dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value is not Null and found_value != [] and found_value != '' and found_value != {}:
                prop_list.append({
                    'address': resource['address'],
                    'values': found_value,
                    'type': _step_obj.context.name
                })

            else:
                Error(
                    _step_obj, '{} ({}) does not have {} property.'.format(
                        resource['address'], resource.get('type', ''),
                        something))

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something
            return something, prop_list

    elif _step_obj.context.type == 'provider':
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                _step_obj.context.stash = values
                _step_obj.context.property_name = something
                _step_obj.context.address = '{}.{}'.format(
                    provider_data.get('name', _step_obj.context.addresses),
                    provider_data.get('alias', "\b"))
                return True
            else:
                Error(
                    _step_obj, '{} {} does not have {} property.'.format(
                        _step_obj.context.addresses, _step_obj.context.type,
                        something))

        Error(
            _step_obj, '{} {} does not have {} property.'.format(
                _step_obj.context.addresses, _step_obj.context.type,
                something))
예제 #15
0
def it_condition_contain_something(_step_obj, something):
    prop_list = []

    if _step_obj.context.type == 'resource':
        for resource in _step_obj.context.stash:
            if type(resource) is not dict:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            values = resource.get('values', {})

            found_value = None
            found_key = None
            if type(values) is dict:
                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])
            elif type(values) is list:
                for value in values:

                    if type(value) is dict:
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break
                    else:
                        raise TerraformComplianceInternalFailure(
                            'Unexpected value type {}. {}'.format(
                                type(value), value))

            if found_key:
                prop_list.append({
                    'address': resource['address'],
                    'values': found_value,
                    'type': _step_obj.context.name
                })

            elif 'must' in _step_obj.context_sensitive_sentence:
                raise Failure('{} ({}) does not have {} property.'.format(
                    resource['address'], resource.get('type', ''), something))

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something
            return True

        skip_step(_step_obj,
                  resource=_step_obj.context.name,
                  message='Can not find any {} property for {} resource in '
                  'terraform plan.'.format(something, _step_obj.context.name))

    elif _step_obj.context.type == 'provider':
        values = seek_key_in_dict(_step_obj.context.stash, something)

        if values:
            _step_obj.context.stash = values
            _step_obj.context.property_name = something
            return True

    skip_step(
        _step_obj,
        resource=_step_obj.context.name,
        message='Skipping the step since {} type does not have {} property.'.
        format(_step_obj.context.type, something))
def it_must_contain_something(_step_obj, something, inherited_values=Null):
    match = _step_obj.context.match
    seek_key_in_dict, seek_regex_key_in_dict_values = match.seek_key_in_dict, match.seek_regex_key_in_dict_values

    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            # not going to use match.get here because the following line is an edge case
            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = match.get(values, something,
                                      seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(
                        found_key
                    ) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = match.get(found_key, something,
                                                found_key)
                        found_value = found_value if found_value not in (
                            [], '') else found_key
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                # not going to use match.get here because the following line is an edge case
                                found_value.extend(value.get('value'))
                                break
                    elif isinstance(value, list):
                        found_key, temp_found_value = it_must_contain_something(
                            _step_obj, something, value)
                        found_value.extend(temp_found_value)

                    elif isinstance(value, (str, bool, int, float)):
                        if match.equals(value, something):
                            found_value.append(value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(
                            found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(
                                found_key.get(something, found_key))

            if isinstance(found_value,
                          dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value not in (Null, [], '', {}):
                prop_list.append({
                    'address': resource['address'],
                    'values': found_value,
                    'type': _step_obj.context.name
                })

            else:
                Error(
                    _step_obj, '{} ({}) does not have {} property.'.format(
                        resource['address'], resource.get('type', ''),
                        something))

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something
            return something, prop_list

    elif _step_obj.context.type == 'provider':
        _step_obj.context.stash = []
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                _step_obj.context.stash.append(values)
                _step_obj.context.property_name = something
                _step_obj.context.address = '{}.{}'.format(
                    provider_data.get('name', _step_obj.context.addresses),
                    provider_data.get('alias', "\b"))
                return True
            else:
                Error(
                    _step_obj, '{} {} does not have {} property.'.format(
                        _step_obj.context.addresses, _step_obj.context.type,
                        something))

        Error(
            _step_obj, '{} {} does not have {} property.'.format(
                _step_obj.context.addresses, _step_obj.context.type,
                something))
예제 #17
0
    def test_seek_in_dict_finding_a_key_in_nested_dict(self):
        dictionary = dict(search_key=dict(something=dict(something_else=None)))
        search_key = 'something'
        expected = [{'something': {'something_else': None}}]

        self.assertEqual(seek_key_in_dict(dictionary, search_key), expected)
예제 #18
0
    def test_seek_in_dict_finding_values_in_non_dicts_on_root(self):
        dictionary = 'something_else'
        search_key = 'something_else'
        expected = []

        self.assertEqual(seek_key_in_dict(dictionary, search_key), expected)
def it_has_something(_step_obj, something, inherited_values=Null):
    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {'values': resource,
                            'address': resource,
                            'type': _step_obj.context.name}

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = values.get(something, seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(found_key) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = jsonify(found_key.get(something, found_key))
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break
                    elif isinstance(value, list):
                        found_key, found_value = it_has_something(_step_obj, something, value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(jsonify(found_key.get(something, found_key)))

            if isinstance(found_value, dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value not in (Null, [], '', {}):
                prop_list.append(resource)

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something

            return something, prop_list

        if _step_obj.state != Step.State.FAILED:
            skip_step(_step_obj,
                      resource=_step_obj.context.name,
                      message='Can not find any {} property for {} resource in '
                              'terraform plan.'.format(something, _step_obj.context.name))

    elif _step_obj.context.type == 'provider':
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                _step_obj.context.stash = provider_data
                _step_obj.context.property_name = something
                _step_obj.context.address = '{}.{}'.format(provider_data.get('name', _step_obj.context.addresses),
                                                           provider_data.get('alias', "\b"))
                return True

    if _step_obj.state != Step.State.FAILED:
        skip_step(_step_obj,
                  resource=_step_obj.context.name,
                  message='Skipping the step since {} type does not have {} property.'.format(_step_obj.context.type,
                                                                                              something))
예제 #20
0
    def test_seek_in_dict_finding_a_key_in_root(self):
        dictionary = dict(search_key=dict(something=[]))
        search_key = 'search_key'
        expected = [{'search_key': {'something': []}}]

        self.assertEqual(seek_key_in_dict(dictionary, search_key), expected)
def it_contains_something_old(_step_obj, something, inherited_values=Null):
    console_write("\t{} {}: {}".format(Defaults().warning_icon,
                                       Defaults().warning_colour('WARNING'),
                                       Defaults().info_colour('"When it contains {}" step functionality will be changed'
                                                              ' on future versions and the functionality will be same '
                                                              'as "When it has {}" step. Please use the '
                                                              'latter.'.format(something, something))))
    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {'values': resource,
                            'address': resource,
                            'type': _step_obj.context.name}

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = values.get(something, seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(found_key) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = jsonify(found_key.get(something, found_key))
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break
                    elif isinstance(value, list):
                        found_key, found_value = it_contains_something_old(_step_obj, something, value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(jsonify(found_key.get(something, found_key)))

            if isinstance(found_value, dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value is not Null and found_value != [] and found_value != '' and found_value != {}:
                prop_list.append({'address': resource['address'],
                                  'values': found_value,
                                  'type': _step_obj.context.name})

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something

            return something, prop_list

        if _step_obj.state != Step.State.FAILED:
            skip_step(_step_obj,
                      resource=_step_obj.context.name,
                      message='Can not find any {} property for {} resource in '
                              'terraform plan.'.format(something, _step_obj.context.name))

    elif _step_obj.context.type == 'provider':
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                _step_obj.context.stash = values
                _step_obj.context.property_name = something
                _step_obj.context.address = '{}.{}'.format(provider_data.get('name', _step_obj.context.addresses),
                                                           provider_data.get('alias', "\b"))
                return True

    if _step_obj.state != Step.State.FAILED:
        skip_step(_step_obj,
                  resource=_step_obj.context.name,
                  message='Skipping the step since {} type does not have {} property.'.format(_step_obj.context.type,
                                                                                              something))
def it_must_not_contain_something(_step_obj, something, inherited_values=Null):
    match = _step_obj.context.match
    seek_key_in_dict, seek_regex_key_in_dict_values = match.seek_key_in_dict, match.seek_regex_key_in_dict_values

    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = match.get(values, something,
                                      seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(
                        found_key
                    ) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = match.get(found_key, something,
                                                found_key)
                        found_value = found_value if found_value not in (
                            [], '') else found_key
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value.append(value.get('value'))
                                break
                    elif isinstance(value, list):
                        found_key, temp_found_value = it_must_contain_something(
                            _step_obj, something, value)
                        found_value.extend(temp_found_value)

                    elif isinstance(value, (str, bool, int, float)):
                        if match.equals(value, something):
                            found_value.append(value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(
                            found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(
                                found_key.get(something, found_key))

            if isinstance(found_value,
                          dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            # if found_value is not Null and found_value != [] and found_value != '' and found_value != {}:
            if found_value not in (Null, [], '', {}):
                Error(
                    _step_obj, '{} property exists in {} ({}).'.format(
                        something, resource['address'],
                        resource.get('type', '')))

    elif _step_obj.context.type == 'provider':
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                Error(
                    _step_obj, '{} {} does not have {} property.'.format(
                        _step_obj.context.addresses, _step_obj.context.type,
                        something))
def it_does_not_have_something(_step_obj, something, inherited_values=Null):
    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {'values': resource,
                            'address': resource,
                            'type': _step_obj.context.name}

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_value = Null
            found_key = Null
            if isinstance(values, dict):
                found_key = values.get(something, seek_key_in_dict(values, something))
                if not isinstance(found_key, list):
                    found_key = [{something: found_key}]

                if len(found_key):
                    found_key = found_key[0] if len(found_key) == 1 and something in found_key[0] else found_key

                    if isinstance(found_key, dict):
                        found_value = jsonify(found_key.get(something, found_key))
                    else:
                        found_value = found_key
            elif isinstance(values, list):
                found_value = []

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_value = value.get('value')
                                break
                    elif isinstance(value, list):
                        found_key, found_value = it_has_something(_step_obj, something, value)

                    if found_key is not Null and len(found_key):
                        found_key = found_key[0] if len(found_key) == 1 else found_key

                        if isinstance(found_key, dict):
                            found_value.append(jsonify(found_key.get(something, found_key)))

            if isinstance(found_value, dict) and 'constant_value' in found_value:
                found_value = found_value['constant_value']

            if found_value is not Null and found_value != [] and found_value != '' and found_value != {}:
                prop_list.append(resource['address'])


        prop_list = [resource for resource in _step_obj.context.stash if resource['address'] not in prop_list]
        _step_obj.context.property_name = something

        if prop_list:
            _step_obj.context.stash = prop_list
            return something, prop_list

        if _step_obj.state != Step.State.FAILED:
            skip_step(_step_obj,
                      resource=_step_obj.context.name,
                      message='All objects ({}) coming from previous step has {} '
                              'property.'.format(_step_obj.context.name, something))

    elif _step_obj.context.type == 'provider':
        stash = []
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                return False
            else:
                stash.append(provider_data)

        if stash:
            _step_obj.context.stash = stash
            _step_obj.context.property_name = something
            return True


    return True
예제 #24
0
def it_must_contain_something(_step_obj,
                              something,
                              inherited_values=Null,
                              child=False):
    match = _step_obj.context.match
    seek_key_in_dict, seek_regex_key_in_dict_values = match.seek_key_in_dict, match.seek_regex_key_in_dict_values

    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            # not going to use match.get here because the following line is an edge case
            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_values = []
            found_key = Null  # this could also become a list
            resource_passed = False
            # set this to True if you get anything from the resource, don't set it to False if you get empty values as there could be other values as well
            if isinstance(values, dict):

                found_key = match.get(values, something, Null)
                if found_key is not Null:
                    found_key = [{something: found_key}]
                else:
                    found_key = seek_key_in_dict(values, something)

                for kv_pair in found_key:
                    # kv_pair must be in {something: found_key} format.
                    if not isinstance(kv_pair, dict):
                        continue  # should raise exception
                    # ignore the values that correspond to Null
                    # Following line could be problematic, how to determine if something is set to be empty or not set? Behavior is provider dependent.
                    # For now, allow '' and don't allow [] as per user cases.
                    if match.get(kv_pair, something) not in ([], ):
                        found_values.append(match.get(kv_pair, something))
                        resource_passed = True

            elif isinstance(values, list):

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # The following is an edge case that covers things like aws asg tags (https://www.terraform.io/docs/providers/aws/r/autoscaling_group.html)
                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                # not going to use match.get here because the following line is an edge case
                                found_values.extend(value.get('value'))
                                resource_passed = True
                                continue
                    elif isinstance(value, list):
                        _, temp_found_values = it_must_contain_something(
                            _step_obj, something, value, child=True)
                        prop_list.extend(temp_found_values)
                        found_values.append('added_to_proplist')
                        resource_passed = True

                    elif isinstance(value, (str, bool, int, float)):
                        if match.equals(value, something):
                            found_values.append(value)

                    if found_key is not Null and len(found_key):

                        for found_key_instance in found_key:
                            if isinstance(found_key_instance, dict):
                                if match.get(
                                        found_key_instance, something,
                                        Null) not in (Null, [], '', {},
                                                      'added_to_proplist'):
                                    found_values.append(
                                        match.get(found_key_instance,
                                                  something))
                                    resource_passed = True

            for i, found_val in enumerate(found_values):
                if isinstance(found_val,
                              dict) and 'constant_value' in found_val:
                    found_values[i] = found_val['constant_value']

            for found_val in found_values:
                if found_val not in (
                        Null, [], '', {},
                        'added_to_proplist'):  # slightly redundant now.
                    prop_list.append({
                        'address': resource['address'],
                        'values': found_val,
                        'type': _step_obj.context.name
                    })

            # do not check prop list here because every resource should contain it.
            if not resource_passed and not child:  # if nothing was found in this resource, don't error if you're a child
                Error(
                    _step_obj, '{} ({}) does not have {} property.'.format(
                        resource['address'], resource.get('type', ''),
                        something))

        if prop_list:
            _step_obj.context.stash = prop_list
            _step_obj.context.property_name = something
            return something, prop_list

    elif _step_obj.context.type == 'provider':
        _step_obj.context.stash = []
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                _step_obj.context.stash.append(values)
                _step_obj.context.property_name = something
                _step_obj.context.address = '{}.{}'.format(
                    provider_data.get('name', _step_obj.context.addresses),
                    provider_data.get('alias', "\b"))
                return True
            else:
                Error(
                    _step_obj, '{} {} does not have {} property.'.format(
                        _step_obj.context.addresses, _step_obj.context.type,
                        something))

        Error(
            _step_obj, '{} {} does not have {} property.'.format(
                _step_obj.context.addresses, _step_obj.context.type,
                something))
예제 #25
0
def it_must_not_contain_something(_step_obj, something, inherited_values=Null):
    match = _step_obj.context.match
    seek_key_in_dict, seek_regex_key_in_dict_values = match.seek_key_in_dict, match.seek_regex_key_in_dict_values

    prop_list = []

    _step_obj.context.stash = inherited_values if inherited_values is not Null else _step_obj.context.stash

    if _step_obj.context.type in ('resource', 'data'):
        for resource in _step_obj.context.stash:
            if not isinstance(resource, dict) \
                    or 'values' not in resource \
                    or 'address' not in resource \
                    or 'type' not in resource:
                resource = {
                    'values': resource,
                    'address': resource,
                    'type': _step_obj.context.name
                }

            values = resource.get('values', resource.get('expressions', {}))
            if not values:
                values = seek_key_in_dict(resource, something)

            found_values = []
            found_key = Null
            resource_passed = False
            # set this to True if you get anything from the resource, don't set it to False if you get empty values as there could be other values as well
            if isinstance(values, dict):

                found_key = match.get(values, something, Null)
                if found_key is not Null:
                    found_key = [{something: found_key}]
                else:
                    found_key = seek_key_in_dict(values, something)

                for kv_pair in found_key:
                    # kv_pair must be in {something: found_key} format.
                    if not isinstance(kv_pair, dict):
                        continue  # could raise an exception
                    # ignore the values that correspond to Null
                    # Following line could be problematic, how to determine if something is set to be empty or not set? Behavior is provider dependent.
                    # For now, allow '' and don't allow [] as per user cases.
                    if match.get(kv_pair, something) not in ([], ):
                        found_values.append(match.get(kv_pair, something))
                        resource_passed = True

            elif isinstance(values, list):

                for value in values:

                    if isinstance(value, dict):
                        # First search in the keys
                        found_key = seek_key_in_dict(value, something)

                        # Then search in the values with 'key'
                        if not found_key:
                            found_key = seek_regex_key_in_dict_values(
                                value, 'key', something)

                            if found_key:
                                found_key = found_key[0]
                                found_values.extend(value.get('value'))
                                resource_passed = True
                                continue
                    elif isinstance(value, list):
                        _, temp_found_values = it_must_contain_something(
                            _step_obj, something, value, child=True)
                        prop_list.extend(temp_found_values)
                        found_values.append('added_to_proplist')
                        resource_passed = True

                    elif isinstance(value, (str, bool, int, float)):
                        if match.equals(value, something):
                            found_values.append(value)

                    if found_key is not Null and len(found_key):

                        for found_key_instance in found_key:
                            if isinstance(found_key_instance, dict):
                                if match.get(
                                        found_key_instance, something,
                                        Null) not in (Null, [], '', {},
                                                      'added_to_proplist'):
                                    found_values.append(
                                        match.get(found_key_instance,
                                                  something))
                                    resource_passed = True

            for i, found_val in enumerate(found_values):
                if isinstance(found_val,
                              dict) and 'constant_value' in found_val:
                    found_values[i] = found_val['constant_value']

            if resource_passed:
                Error(
                    _step_obj, '{} property exists in {} ({}).'.format(
                        something, resource['address'],
                        resource.get('type', '')))

    elif _step_obj.context.type == 'provider':
        for provider_data in _step_obj.context.stash:
            values = seek_key_in_dict(provider_data, something)

            if values:
                Error(
                    _step_obj, '{} {} does not have {} property.'.format(
                        _step_obj.context.addresses, _step_obj.context.type,
                        something))