예제 #1
0
    def test_terragoat_db_app(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_terragoat_db_app')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        self.compare_vertex_attributes(local_graph, expected_terragoat_local_resource_prefix, BlockType.LOCALS.value, 'resource_prefix')
        self.compare_vertex_attributes(local_graph, expected_terragoat_db_instance, BlockType.RESOURCE.value, "aws_db_instance.default")
예제 #2
0
 def test_update_vertices_configs_deep_nesting(self):
     resources_dir = os.path.join(
         TEST_DIRNAME,
         '../resources/variable_rendering/render_deep_nesting')
     graph_manager = GraphManager(NetworkxConnector())
     local_graph, _ = graph_manager.build_graph_from_source_directory(
         resources_dir, render_variables=True)
     expected_config = {
         'aws_s3_bucket': {
             'default': {
                 'server_side_encryption_configuration': [{
                     'rule': [{
                         'apply_server_side_encryption_by_default': [{
                             'sse_algorithm': ['AES256'],
                             'kms_master_key_id': ['']
                         }]
                     }]
                 }]
             }
         }
     }
     actual_config = local_graph.vertices[
         local_graph.vertices_by_block_type.get(
             BlockType.RESOURCE)[0]].config
     self.assertDictEqual(expected_config, actual_config)
     print('')
예제 #3
0
    def test_multiple_breadcrumbs(self):
        resources_dir = os.path.join(TEST_DIRNAME,
                                     '../resources/general_example')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(
            resources_dir, render_variables=True)
        vertices = local_graph.vertices
        s3_vertex = list(
            filter(lambda vertex: vertex.block_type == BlockType.RESOURCE,
                   vertices))[0]
        changed_attributes = list(s3_vertex.changed_attributes.keys())
        self.assertListEqual(changed_attributes, ['region', 'bucket'])

        bucket_vertices_ids_list = s3_vertex.changed_attributes.get('bucket')
        self.assertEqual(2, len(bucket_vertices_ids_list))

        self.assertEqual(BlockType.VARIABLE,
                         vertices[bucket_vertices_ids_list[0]].block_type)
        self.assertEqual('bucket_name',
                         vertices[bucket_vertices_ids_list[0]].name)
        self.assertEqual(vertices[bucket_vertices_ids_list[0]].name,
                         s3_vertex.breadcrumbs['bucket'][0]['name'])

        self.assertEqual(BlockType.LOCALS,
                         vertices[bucket_vertices_ids_list[1]].block_type)
        self.assertEqual('bucket_name',
                         vertices[bucket_vertices_ids_list[1]].name)
        self.assertEqual(vertices[bucket_vertices_ids_list[1]].name,
                         s3_vertex.breadcrumbs['bucket'][1]['name'])
예제 #4
0
 def test_graph_rendering_order(self):
     resource_path = os.path.join(TEST_DIRNAME, "..", "resources",
                                  "module_rendering", "example")
     graph_manager = GraphManager('m', ['m'])
     local_graph, tf_def = graph_manager.build_graph_from_source_directory(
         resource_path, render_variables=True)
     module_vertices = list(
         filter(lambda v: v.block_type == BlockType.MODULE,
                local_graph.vertices))
     existing = set()
     self.assertEqual(6, len(local_graph.edges))
     for e in local_graph.edges:
         if e in existing:
             self.fail(
                 "No 2 edges should be aimed at the same vertex in this example"
             )
         else:
             existing.add(e)
     count = 0
     found = 0
     for v in module_vertices:
         if v.name == 'second-mock':
             found += 1
             if v.attributes['input'] == ['aws_s3_bucket.some-bucket.arn']:
                 count += 1
     self.assertEqual(
         found, count,
         f"Expected all instances to have the same value, found {found} instances but only {count} correct values"
     )
예제 #5
0
    def test_build_graph_with_linked_registry_modules(self):
        resources_dir = os.path.realpath(
            os.path.join(TEST_DIRNAME, '../resources/modules/registry_security_group_inner_module'))

        graph_manager = GraphManager(NetworkxConnector())
        local_graph, tf_definitions = graph_manager.build_graph_from_source_directory(resources_dir,
                                                                                      render_variables=True,
                                                                                      download_external_modules=True)

        outputs_vpcs = self.get_vertex_by_name_and_type(local_graph, BlockType.OUTPUT, 'security_group_vpc_id',
                                                        multiple=True)
        resource_flow_log = self.get_vertex_by_name_and_type(local_graph, BlockType.RESOURCE,
                                                             'aws_flow_log.related_flow_log')
        resource_security_group_this = self.get_vertex_by_name_and_type(local_graph, BlockType.RESOURCE,
                                                                        'aws_security_group.this')
        resource_security_group_this_name_prefix = self.get_vertex_by_name_and_type(local_graph, BlockType.RESOURCE,
                                                                                    'aws_security_group.this_name_prefix')

        output_this_security_group_vpc_id_inner = [o for o in outputs_vpcs if 'http-80' in o.path][0]
        output_this_security_group_vpc_id_outer = [o for o in outputs_vpcs if 'http-80' not in o.path][0]

        self.check_edge(local_graph, node_from=resource_flow_log, node_to=output_this_security_group_vpc_id_inner,
                        expected_label='vpc_id')
        self.check_edge(local_graph, node_from=output_this_security_group_vpc_id_inner,
                        node_to=output_this_security_group_vpc_id_outer, expected_label='value')
        self.check_edge(local_graph, node_from=output_this_security_group_vpc_id_outer,
                        node_to=resource_security_group_this, expected_label='value')
        self.check_edge(local_graph, node_from=output_this_security_group_vpc_id_outer,
                        node_to=resource_security_group_this_name_prefix, expected_label='value')

        # cleanup
        if os.path.exists(os.path.join(resources_dir, external_modules_download_path)):
            shutil.rmtree(os.path.join(resources_dir, external_modules_download_path))
예제 #6
0
    def test_general_example(self):
        resources_dir = os.path.join(TEST_DIRNAME,
                                     '../resources/general_example')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(
            resources_dir, render_variables=True)

        expected_provider = {
            'profile': 'default',
            'region': 'us-east-1',
            'alias': 'east1'
        }
        expected_local = {'bucket_name': {'val': 'MyBucket'}}
        expected_resource = {
            'region': 'us-west-2',
            'bucket': expected_local['bucket_name']
        }

        self.compare_vertex_attributes(local_graph, expected_provider,
                                       BlockType.PROVIDER.value, 'aws.east1')
        self.compare_vertex_attributes(local_graph, expected_local,
                                       BlockType.LOCALS.value, 'bucket_name')
        self.compare_vertex_attributes(local_graph, expected_resource,
                                       BlockType.RESOURCE.value,
                                       'aws_s3_bucket.template_bucket')
예제 #7
0
    def test_render_variable(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_variable')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        expected_resource = {'region': "us-west-2", 'bucket': "test_bucket_name", "acl": "acl", "force_destroy": True}

        self.compare_vertex_attributes(local_graph, expected_resource, BlockType.RESOURCE.value, 'aws_s3_bucket.template_bucket')
예제 #8
0
    def test_render_lambda(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_lambda')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        expected_aws_lambda_permission = {'count': 0, 'statement_id': 'test_statement_id', 'action': 'lambda:InvokeFunction', 'function_name': 'my-func', 'principal': 'dumbeldor', 'resource_type': 'aws_lambda_permission'}

        self.compare_vertex_attributes(local_graph, expected_aws_lambda_permission, BlockType.RESOURCE.value, "aws_lambda_permission.test_lambda_permissions")
예제 #9
0
    def test_render_local_from_variable(self):
        resources_dir = os.path.join(TEST_DIRNAME,
                                     '../resources/variable_rendering/render_local_from_variable')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        expected_local = {'bucket_name': 'test_bucket_name'}

        self.compare_vertex_attributes(local_graph, expected_local, BlockType.LOCALS.value, 'bucket_name')
예제 #10
0
    def test_render_nested_modules(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_nested_modules')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        expected_aws_instance = {"instance_type": "bar"}
        self.compare_vertex_attributes(local_graph, expected_aws_instance, BlockType.RESOURCE, "aws_instance.example")
        expected_output_bucket_acl = {"value": "z"}
        self.compare_vertex_attributes(local_graph, expected_output_bucket_acl, BlockType.OUTPUT,  "bucket_acl")
예제 #11
0
    def test_render_local(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_local')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        expected_local = {'bucket_name': 'test_bucket_name'}
        expected_resource = {'region': 'us-west-2', 'bucket': expected_local['bucket_name']}

        self.compare_vertex_attributes(local_graph, expected_local, BlockType.LOCALS.value, 'bucket_name')
        self.compare_vertex_attributes(local_graph, expected_resource, BlockType.RESOURCE.value, 'aws_s3_bucket.template_bucket')
예제 #12
0
    def test_dict_tfvar(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/variable_rendering/render_dictionary_tfvars')
        graph_manager = GraphManager('d', ['d'])
        local_graph, tf_def = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        for v in local_graph.vertices:
            expected_v = expected_provider.get(v.block_type, {}).get(v.name)
            if expected_v:
                for attribute_key, expected_value in expected_v.items():
                    actual_value = v.attributes.get(attribute_key)
                    self.assertEqual(expected_value, actual_value,
                                     f'error during comparing {v.block_type} in attribute key: {attribute_key}')
예제 #13
0
    def test_build_graph_with_linked_modules(self):
        # see the image to view the expected graph in tests/resources/modules/linked_modules/expected_graph.png
        resources_dir = os.path.realpath(
            os.path.join(TEST_DIRNAME, '../resources/modules/linked_modules'))

        graph_manager = GraphManager(NetworkxConnector())
        local_graph, tf_definitions = graph_manager.build_graph_from_source_directory(
            resources_dir, render_variables=False)

        vertices_by_block_type = local_graph.vertices_by_block_type

        expected_vertices_num_by_type = {
            BlockType.VARIABLE: 5,
            BlockType.RESOURCE: 5,
            BlockType.OUTPUT: 3,
            BlockType.MODULE: 2,
            BlockType.DATA: 1,
        }

        for block_type, count in expected_vertices_num_by_type.items():
            self.assertEqual(count, len(vertices_by_block_type[block_type]))

        output_this_lambda_func_arn = self.get_vertex_by_name_and_type(
            local_graph, BlockType.OUTPUT, 'this_lambda_function_arn')
        output_this_lambda_func_name = self.get_vertex_by_name_and_type(
            local_graph, BlockType.OUTPUT, 'this_lambda_function_name')
        output_this_s3_bucket_id = self.get_vertex_by_name_and_type(
            local_graph, BlockType.OUTPUT, 'this_s3_bucket_id')
        resource_aws_lambda_function = self.get_vertex_by_name_and_type(
            local_graph, BlockType.RESOURCE, 'aws_lambda_function.this')
        resource_aws_s3_bucket_policy = self.get_vertex_by_name_and_type(
            local_graph, BlockType.RESOURCE, 'aws_s3_bucket_policy.this')
        resource_aws_s3_bucket = self.get_vertex_by_name_and_type(
            local_graph, BlockType.RESOURCE, 'aws_s3_bucket.this')

        self.check_edge(local_graph,
                        node_from=output_this_lambda_func_arn,
                        node_to=resource_aws_lambda_function,
                        expected_label='value')
        self.check_edge(local_graph,
                        node_from=output_this_lambda_func_name,
                        node_to=resource_aws_lambda_function,
                        expected_label='value')
        self.check_edge(local_graph,
                        node_from=output_this_s3_bucket_id,
                        node_to=resource_aws_s3_bucket_policy,
                        expected_label='value')
        self.check_edge(local_graph,
                        node_from=output_this_s3_bucket_id,
                        node_to=resource_aws_s3_bucket,
                        expected_label='value')
예제 #14
0
 def test_blocks_from_local_graph_module(self):
     resources_dir = os.path.realpath(os.path.join(TEST_DIRNAME, '../resources/modules/stacks'))
     graph_manager = GraphManager(NetworkxConnector())
     local_graph, tf = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)
     tf, _ = convert_graph_vertices_to_tf_definitions(local_graph.vertices, resources_dir)
     found_results = 0
     for key, value in tf.items():
         if key.startswith(os.path.join(os.path.dirname(resources_dir), 's3_inner_modules', 'inner', 'main.tf')):
             conf = value['resource'][0]['aws_s3_bucket']['inner_s3']
             if 'stage/main' in key or 'prod/main' in key:
                 self.assertTrue(conf['versioning'][0]['enabled'][0])
                 found_results += 1
             elif 'test/main' in key:
                 self.assertFalse(conf['versioning'][0]['enabled'][0])
                 found_results += 1
     self.assertEqual(found_results, 3)
예제 #15
0
    def test_single_edge_with_same_label(self):
        resources_dir = os.path.realpath(
            os.path.join(TEST_DIRNAME, '../resources/k8_service'))

        graph_manager = GraphManager(NetworkxConnector())
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir,
                                                                          render_variables=True)
        edges_hash = []
        for e in local_graph.edges:
            edge_hash = calculate_hash({"origin": e.origin, "dest": e.dest, "label": e.label})
            if edge_hash in edges_hash:
                origin = local_graph.vertices[e.origin]
                dest = local_graph.vertices[e.dest]
                self.fail(f'edge {e} == [{origin} - {e.label} -> {dest}] appears more than once in the graph')
            else:
                edges_hash.append(edge_hash)
예제 #16
0
    def test_build_graph(self):
        resources_dir = os.path.join(TEST_DIRNAME,
                                     '../resources/general_example')

        graph_manager = GraphManager(db_connector=NetworkxConnector())
        graph, tf_definitions = graph_manager.build_graph_from_source_directory(
            resources_dir)

        expected_num_of_var_nodes = 3
        expected_num_of_locals_nodes = 1
        expected_num_of_resources_nodes = 1
        expected_num_of_provider_nodes = 1
        vertices_by_block_type = graph.vertices_by_block_type
        self.assertEqual(expected_num_of_var_nodes,
                         len(vertices_by_block_type[BlockType.VARIABLE]))
        self.assertEqual(expected_num_of_locals_nodes,
                         len(vertices_by_block_type[BlockType.LOCALS]))
        self.assertEqual(expected_num_of_resources_nodes,
                         len(vertices_by_block_type[BlockType.RESOURCE]))
        self.assertEqual(expected_num_of_provider_nodes,
                         len(vertices_by_block_type[BlockType.PROVIDER]))

        provider_node = graph.vertices[vertices_by_block_type[
            BlockType.PROVIDER][0]]
        resource_node = graph.vertices[vertices_by_block_type[
            BlockType.RESOURCE][0]]
        local_node = graph.vertices[vertices_by_block_type[BlockType.LOCALS]
                                    [0]]

        var_bucket_name_node = None
        var_region_node = None
        var_aws_profile_node = None
        for index in vertices_by_block_type[BlockType.VARIABLE]:
            var_node = graph.vertices[index]
            if var_node.name == 'aws_profile':
                var_aws_profile_node = var_node
            if var_node.name == 'bucket_name':
                var_bucket_name_node = var_node
            if var_node.name == 'region':
                var_region_node = var_node

        self.check_edge(graph, resource_node, local_node, 'bucket')
        self.check_edge(graph, resource_node, provider_node, 'provider')
        self.check_edge(graph, resource_node, var_region_node, 'region')
        self.check_edge(graph, provider_node, var_aws_profile_node, 'profile')
        self.check_edge(graph, local_node, var_bucket_name_node, 'bucket_name')
예제 #17
0
    def test_breadcrumbs(self):
        resources_dir = os.path.join(TEST_DIRNAME, '../resources/s3_bucket')
        graph_manager = GraphManager('acme', ['acme'])
        local_graph, _ = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)
        vertices = local_graph.vertices
        s3_vertex = list(filter(lambda vertex:  vertex.block_type == BlockType.RESOURCE, vertices))[0]
        changed_attributes = list(s3_vertex.changed_attributes.keys())
        self.assertListEqual(changed_attributes, ['versioning.enabled', 'acl'])

        for breadcrumbs in s3_vertex.changed_attributes.values():
            self.assertEqual(1, len(breadcrumbs))

        acl_origin_vertex = s3_vertex.changed_attributes.get('acl')[0]
        matching_acl_vertex = vertices[acl_origin_vertex]
        self.assertEqual('acl', matching_acl_vertex.name)

        versioning_origin_vertex = s3_vertex.changed_attributes.get('versioning.enabled')[0]
        matching_versioning_vertex = vertices[versioning_origin_vertex]
        self.assertEqual('is_enabled', matching_versioning_vertex.name)
예제 #18
0
 def __init__(self, parser=Parser(), db_connector=NetworkxConnector(), external_registries=None,
              source="Terraform", graph_class=LocalGraph, graph_manager=None):
     self.external_registries = [] if external_registries is None else external_registries
     self.graph_class = graph_class
     self.parser = parser
     self.tf_definitions = None
     self.definitions_context = None
     self.breadcrumbs = None
     self.definitions_context = {}
     self.evaluations_context: Dict[str, Dict[str, EvaluationContext]] = {}
     self.graph_manager = graph_manager if graph_manager is not None else GraphManager(source=source,
                                                                                       db_connector=db_connector)
예제 #19
0
    def test_build_graph_with_deep_nested_edges(self):
        resources_dir = os.path.realpath(os.path.join(TEST_DIRNAME, '../resources/k8_service'))

        graph_manager = GraphManager(NetworkxConnector())
        local_graph, tf = graph_manager.build_graph_from_source_directory(resources_dir, render_variables=True)

        resource_kubernetes_deployment = self.get_vertex_by_name_and_type(local_graph, BlockType.RESOURCE,
                                                                          'kubernetes_deployment.bazel_remote_cache')
        locals_name = self.get_vertex_by_name_and_type(local_graph, BlockType.LOCALS, 'name')
        locals_labels = self.get_vertex_by_name_and_type(local_graph, BlockType.LOCALS, 'labels')

        self.check_edge(local_graph, node_from=locals_labels, node_to=locals_name,
                        expected_label="labels.app.kubernetes.io/name")
        self.check_edge(local_graph, node_from=resource_kubernetes_deployment, node_to=locals_name,
                        expected_label="metadata.name")
        self.check_edge(local_graph, node_from=resource_kubernetes_deployment, node_to=locals_name,
                        expected_label="spec.template.metadata.name")
        self.check_edge(local_graph, node_from=resource_kubernetes_deployment, node_to=locals_name,
                        expected_label="spec.template.spec.container.name")
        self.check_edge(local_graph, node_from=resource_kubernetes_deployment, node_to=locals_name,
                        expected_label="spec.template.spec.volume.1.config_map.name")
예제 #20
0
    def go(self, dir_name, different_expected=None, replace_expected=False):
        os.environ['RENDER_VARIABLES_ASYNC'] = 'False'
        os.environ['LOG_LEVEL'] = 'INFO'
        different_expected = {} if not different_expected else different_expected
        resources_dir = os.path.realpath(
            os.path.join(
                TEST_DIRNAME,
                '../../../terraform/parser/resources/parser_scenarios',
                dir_name))
        graph_manager = GraphManager(dir_name, [dir_name])
        local_graph, _ = graph_manager.build_graph_from_source_directory(
            resources_dir, render_variables=True)
        got_tf_definitions, _ = convert_graph_vertices_to_tf_definitions(
            local_graph.vertices, resources_dir)
        expected = load_expected(replace_expected, dir_name, resources_dir)

        for expected_file, expected_block_type_dict in expected.items():
            module_removed_path = expected_file
            got_file = got_tf_definitions.get(module_removed_path)
            self.assertIsNotNone(got_file)
            for expected_block_type, expected_block_type_list in expected_block_type_dict.items(
            ):
                got_block_type_list = got_file.get(expected_block_type)
                self.assertIsNotNone(got_block_type_list)
                for expected_block_dict in expected_block_type_list:
                    for expected_block_name, expected_block_val in expected_block_dict.items(
                    ):
                        if expected_block_type != BlockType.RESOURCE:
                            found = self.match_blocks(expected_block_val,
                                                      different_expected,
                                                      got_block_type_list,
                                                      expected_block_name)
                        else:
                            found = self.match_resources(
                                expected_block_val, different_expected,
                                got_block_type_list, expected_block_name)
                        self.assertTrue(
                            found,
                            f"expected to find block {expected_block_dict} from file {expected_file} in graph"
                        )