We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
How to Check a Data Source connected to a Resource
**Describe the issue**
I want to check if the attribute "group" of the resource "azuredevops_group_membership" refers to a data source "azuredevops_group" with the attribute "name" = "Build Administrators" for example.

**Examples**
Snippet from [terraform registry](https://registry.terraform.io/providers/microsoft/azuredevops/latest/docs/resources/group_membership)
```terraform
data "azuredevops_group" "example" {
  project_id = azuredevops_project.example.id
  name       = "Build Administrators"
}

resource "azuredevops_group_membership" "example" {
  group = data.azuredevops_group.example.descriptor
  members = [
    azuredevops_user_entitlement.example.descriptor
  ]
}
```
I tryed creating a custom policy in python but I didn't understand how I could make this work, I was only able to create a policy to check if the attribute name of the data azuredevops_group was equal to "Build Administrators":

```python
from typing import Dict, List, Any

from checkov.terraform.checks.data.base_check import BaseDataCheck
from checkov.common.models.enums import CheckResult, CheckCategories

class NoBuildAdministratorCreated(BaseDataCheck):
    def __init__(self) -> None:
        name = 'Ensure no build administrator is created on file'
        id = "CKV_ADO_9000"
        supported_data = ["azuredevops_group"]
        categories = [CheckCategories.GENERAL_SECURITY]
        super().__init__(name=name, id=id, categories=categories, supported_data=supported_data)

    def scan_data_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:

        if (conf.get("name", "Build Administrators")):
            return CheckResult.FAILED
    
        return CheckResult.PASSED

check = NoBuildAdministratorCreated()
```

**Version (please complete the following information):**
 - Checkov Version 2.0.1223

**Additional context**
My goal is to check if people are creating admin groups inside of a terraform file. I'm kinda new to reading documentations and code libraries of open source projects so I'm having a bit of a hard time understanding how to use the checkov python scan functions to create custom policies. So any advice or code example to help me understand better how it works and what is this **conf** would be much appreciated, thanks!


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py`
Content:
```
1 import concurrent.futures
2 import re
3 from typing import List, Tuple, Dict, Any, Optional, Pattern
4 
5 from networkx import DiGraph
6 
7 from checkov.common.graph.checks_infra.enums import SolverType
8 from checkov.common.graph.checks_infra.solvers.base_solver import BaseSolver
9 
10 from concurrent.futures import ThreadPoolExecutor
11 
12 from checkov.common.graph.graph_builder import CustomAttributes
13 from checkov.common.graph.graph_builder.graph_components.block_types import BlockType
14 from checkov.common.util.var_utils import is_terraform_variable_dependent, is_cloudformation_variable_dependent
15 
16 WILDCARD_PATTERN = re.compile(r"(\S+[.][*][.]*)+")
17 
18 
19 class BaseAttributeSolver(BaseSolver):
20     operator = ""
21 
22     def __init__(self, resource_types: List[str], attribute: Optional[str], value: Any) -> None:
23         super().__init__(SolverType.ATTRIBUTE)
24         self.resource_types = resource_types
25         self.attribute = attribute
26         self.value = value
27 
28     def run(self, graph_connector: DiGraph) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
29         executer = ThreadPoolExecutor()
30         jobs = []
31         passed_vertices: List[Dict[str, Any]] = []
32         failed_vertices: List[Dict[str, Any]] = []
33         for _, data in graph_connector.nodes(data=True):
34             if (not self.resource_types or data.get(CustomAttributes.RESOURCE_TYPE) in self.resource_types) \
35                     and data.get(CustomAttributes.BLOCK_TYPE) == BlockType.RESOURCE:
36                 jobs.append(executer.submit(self._process_node, data, passed_vertices, failed_vertices))
37 
38         concurrent.futures.wait(jobs)
39         return passed_vertices, failed_vertices
40 
41     def get_operation(self, vertex: Dict[str, Any]) -> bool:
42         if self.attribute and re.match(WILDCARD_PATTERN, self.attribute):
43             attribute_patterns = self.get_attribute_patterns(self.attribute)
44             attribute_matches = [
45                 attr
46                 for attr in vertex
47                 if any(re.match(re.compile(attribute_pattern), attr) for attribute_pattern in attribute_patterns)
48             ]
49             if attribute_matches:
50                 return self.resource_type_pred(vertex, self.resource_types) and any(
51                     self._get_operation(vertex=vertex, attribute=attr) for attr in attribute_matches
52                 )
53         return self.resource_type_pred(vertex, self.resource_types) and self._get_operation(
54             vertex=vertex, attribute=self.attribute
55         )
56 
57     def _get_operation(self, vertex: Dict[str, Any], attribute: Optional[str]) -> bool:
58         raise NotImplementedError
59 
60     def _process_node(
61         self, data: Dict[str, Any], passed_vartices: List[Dict[str, Any]], failed_vertices: List[Dict[str, Any]]
62     ) -> None:
63         if not self.resource_type_pred(data, self.resource_types):
64             return
65         if self.get_operation(vertex=data):
66             passed_vartices.append(data)
67         else:
68             failed_vertices.append(data)
69 
70     @staticmethod
71     def get_attribute_patterns(attribute: str) -> Tuple[Pattern[str], Pattern[str]]:
72         index_pattern = r"[\d]+"
73         split_by_dots = attribute.split(".")
74 
75         pattern_parts = []
76         pattern_parts_without_index = []
77         for attr_part in split_by_dots:
78             if attr_part == "*":
79                 pattern_parts.append(index_pattern)
80             else:
81                 attr_part_pattern = f"({attr_part})"
82                 pattern_parts.append(attr_part_pattern)
83                 pattern_parts_without_index.append(attr_part_pattern)
84 
85         pattern = "[.]".join(pattern_parts)
86         pattern_with_index = re.compile(pattern)
87 
88         pattern = "[.]".join(pattern_parts_without_index)
89         pattern_without_index = re.compile(pattern)
90 
91         return pattern_with_index, pattern_without_index
92 
93     @staticmethod
94     def _is_variable_dependant(value: Any, source: str) -> bool:
95         if source == 'Terraform' and is_terraform_variable_dependent(value):
96             return True
97         # TODO add logic for CloudFormation
98         # elif source == 'CloudFormation' and is_cloudformation_variable_dependent(value):
99         #     return True
100 
101         return False
102
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py b/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py
--- a/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py
+++ b/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py
@@ -12,7 +12,9 @@
 from checkov.common.graph.graph_builder import CustomAttributes
 from checkov.common.graph.graph_builder.graph_components.block_types import BlockType
 from checkov.common.util.var_utils import is_terraform_variable_dependent, is_cloudformation_variable_dependent
+from checkov.terraform.graph_builder.graph_components.block_types import BlockType as TerraformBlockType
 
+SUPPORTED_BLOCK_TYPES = {BlockType.RESOURCE, TerraformBlockType.DATA}
 WILDCARD_PATTERN = re.compile(r"(\S+[.][*][.]*)+")
 
 
@@ -32,7 +34,7 @@
         failed_vertices: List[Dict[str, Any]] = []
         for _, data in graph_connector.nodes(data=True):
             if (not self.resource_types or data.get(CustomAttributes.RESOURCE_TYPE) in self.resource_types) \
-                    and data.get(CustomAttributes.BLOCK_TYPE) == BlockType.RESOURCE:
+                    and data.get(CustomAttributes.BLOCK_TYPE) in SUPPORTED_BLOCK_TYPES:
                 jobs.append(executer.submit(self._process_node, data, passed_vertices, failed_vertices))
 
         concurrent.futures.wait(jobs)

{"golden_diff": "diff --git a/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py b/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py\n--- a/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py\n+++ b/checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py\n@@ -12,7 +12,9 @@\n from checkov.common.graph.graph_builder import CustomAttributes\n from checkov.common.graph.graph_builder.graph_components.block_types import BlockType\n from checkov.common.util.var_utils import is_terraform_variable_dependent, is_cloudformation_variable_dependent\n+from checkov.terraform.graph_builder.graph_components.block_types import BlockType as TerraformBlockType\n \n+SUPPORTED_BLOCK_TYPES = {BlockType.RESOURCE, TerraformBlockType.DATA}\n WILDCARD_PATTERN = re.compile(r\"(\\S+[.][*][.]*)+\")\n \n \n@@ -32,7 +34,7 @@\n         failed_vertices: List[Dict[str, Any]] = []\n         for _, data in graph_connector.nodes(data=True):\n             if (not self.resource_types or data.get(CustomAttributes.RESOURCE_TYPE) in self.resource_types) \\\n-                    and data.get(CustomAttributes.BLOCK_TYPE) == BlockType.RESOURCE:\n+                    and data.get(CustomAttributes.BLOCK_TYPE) in SUPPORTED_BLOCK_TYPES:\n                 jobs.append(executer.submit(self._process_node, data, passed_vertices, failed_vertices))\n \n         concurrent.futures.wait(jobs)\n", "issue": "How to Check a Data Source connected to a Resource\n**Describe the issue**\r\nI want to check if the attribute \"group\" of the resource \"azuredevops_group_membership\" refers to a data source \"azuredevops_group\" with the attribute \"name\" = \"Build Administrators\" for example.\r\n\r\n**Examples**\r\nSnippet from [terraform registry](https://registry.terraform.io/providers/microsoft/azuredevops/latest/docs/resources/group_membership)\r\n```terraform\r\ndata \"azuredevops_group\" \"example\" {\r\n  project_id = azuredevops_project.example.id\r\n  name       = \"Build Administrators\"\r\n}\r\n\r\nresource \"azuredevops_group_membership\" \"example\" {\r\n  group = data.azuredevops_group.example.descriptor\r\n  members = [\r\n    azuredevops_user_entitlement.example.descriptor\r\n  ]\r\n}\r\n```\r\nI tryed creating a custom policy in python but I didn't understand how I could make this work, I was only able to create a policy to check if the attribute name of the data azuredevops_group was equal to \"Build Administrators\":\r\n\r\n```python\r\nfrom typing import Dict, List, Any\r\n\r\nfrom checkov.terraform.checks.data.base_check import BaseDataCheck\r\nfrom checkov.common.models.enums import CheckResult, CheckCategories\r\n\r\nclass NoBuildAdministratorCreated(BaseDataCheck):\r\n    def __init__(self) -> None:\r\n        name = 'Ensure no build administrator is created on file'\r\n        id = \"CKV_ADO_9000\"\r\n        supported_data = [\"azuredevops_group\"]\r\n        categories = [CheckCategories.GENERAL_SECURITY]\r\n        super().__init__(name=name, id=id, categories=categories, supported_data=supported_data)\r\n\r\n    def scan_data_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:\r\n\r\n        if (conf.get(\"name\", \"Build Administrators\")):\r\n            return CheckResult.FAILED\r\n    \r\n        return CheckResult.PASSED\r\n\r\ncheck = NoBuildAdministratorCreated()\r\n```\r\n\r\n**Version (please complete the following information):**\r\n - Checkov Version 2.0.1223\r\n\r\n**Additional context**\r\nMy goal is to check if people are creating admin groups inside of a terraform file. I'm kinda new to reading documentations and code libraries of open source projects so I'm having a bit of a hard time understanding how to use the checkov python scan functions to create custom policies. So any advice or code example to help me understand better how it works and what is this **conf** would be much appreciated, thanks!\r\n\n", "before_files": [{"content": "import concurrent.futures\nimport re\nfrom typing import List, Tuple, Dict, Any, Optional, Pattern\n\nfrom networkx import DiGraph\n\nfrom checkov.common.graph.checks_infra.enums import SolverType\nfrom checkov.common.graph.checks_infra.solvers.base_solver import BaseSolver\n\nfrom concurrent.futures import ThreadPoolExecutor\n\nfrom checkov.common.graph.graph_builder import CustomAttributes\nfrom checkov.common.graph.graph_builder.graph_components.block_types import BlockType\nfrom checkov.common.util.var_utils import is_terraform_variable_dependent, is_cloudformation_variable_dependent\n\nWILDCARD_PATTERN = re.compile(r\"(\\S+[.][*][.]*)+\")\n\n\nclass BaseAttributeSolver(BaseSolver):\n    operator = \"\"\n\n    def __init__(self, resource_types: List[str], attribute: Optional[str], value: Any) -> None:\n        super().__init__(SolverType.ATTRIBUTE)\n        self.resource_types = resource_types\n        self.attribute = attribute\n        self.value = value\n\n    def run(self, graph_connector: DiGraph) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:\n        executer = ThreadPoolExecutor()\n        jobs = []\n        passed_vertices: List[Dict[str, Any]] = []\n        failed_vertices: List[Dict[str, Any]] = []\n        for _, data in graph_connector.nodes(data=True):\n            if (not self.resource_types or data.get(CustomAttributes.RESOURCE_TYPE) in self.resource_types) \\\n                    and data.get(CustomAttributes.BLOCK_TYPE) == BlockType.RESOURCE:\n                jobs.append(executer.submit(self._process_node, data, passed_vertices, failed_vertices))\n\n        concurrent.futures.wait(jobs)\n        return passed_vertices, failed_vertices\n\n    def get_operation(self, vertex: Dict[str, Any]) -> bool:\n        if self.attribute and re.match(WILDCARD_PATTERN, self.attribute):\n            attribute_patterns = self.get_attribute_patterns(self.attribute)\n            attribute_matches = [\n                attr\n                for attr in vertex\n                if any(re.match(re.compile(attribute_pattern), attr) for attribute_pattern in attribute_patterns)\n            ]\n            if attribute_matches:\n                return self.resource_type_pred(vertex, self.resource_types) and any(\n                    self._get_operation(vertex=vertex, attribute=attr) for attr in attribute_matches\n                )\n        return self.resource_type_pred(vertex, self.resource_types) and self._get_operation(\n            vertex=vertex, attribute=self.attribute\n        )\n\n    def _get_operation(self, vertex: Dict[str, Any], attribute: Optional[str]) -> bool:\n        raise NotImplementedError\n\n    def _process_node(\n        self, data: Dict[str, Any], passed_vartices: List[Dict[str, Any]], failed_vertices: List[Dict[str, Any]]\n    ) -> None:\n        if not self.resource_type_pred(data, self.resource_types):\n            return\n        if self.get_operation(vertex=data):\n            passed_vartices.append(data)\n        else:\n            failed_vertices.append(data)\n\n    @staticmethod\n    def get_attribute_patterns(attribute: str) -> Tuple[Pattern[str], Pattern[str]]:\n        index_pattern = r\"[\\d]+\"\n        split_by_dots = attribute.split(\".\")\n\n        pattern_parts = []\n        pattern_parts_without_index = []\n        for attr_part in split_by_dots:\n            if attr_part == \"*\":\n                pattern_parts.append(index_pattern)\n            else:\n                attr_part_pattern = f\"({attr_part})\"\n                pattern_parts.append(attr_part_pattern)\n                pattern_parts_without_index.append(attr_part_pattern)\n\n        pattern = \"[.]\".join(pattern_parts)\n        pattern_with_index = re.compile(pattern)\n\n        pattern = \"[.]\".join(pattern_parts_without_index)\n        pattern_without_index = re.compile(pattern)\n\n        return pattern_with_index, pattern_without_index\n\n    @staticmethod\n    def _is_variable_dependant(value: Any, source: str) -> bool:\n        if source == 'Terraform' and is_terraform_variable_dependent(value):\n            return True\n        # TODO add logic for CloudFormation\n        # elif source == 'CloudFormation' and is_cloudformation_variable_dependent(value):\n        #     return True\n\n        return False\n", "path": "checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py"}], "after_files": [{"content": "import concurrent.futures\nimport re\nfrom typing import List, Tuple, Dict, Any, Optional, Pattern\n\nfrom networkx import DiGraph\n\nfrom checkov.common.graph.checks_infra.enums import SolverType\nfrom checkov.common.graph.checks_infra.solvers.base_solver import BaseSolver\n\nfrom concurrent.futures import ThreadPoolExecutor\n\nfrom checkov.common.graph.graph_builder import CustomAttributes\nfrom checkov.common.graph.graph_builder.graph_components.block_types import BlockType\nfrom checkov.common.util.var_utils import is_terraform_variable_dependent, is_cloudformation_variable_dependent\nfrom checkov.terraform.graph_builder.graph_components.block_types import BlockType as TerraformBlockType\n\nSUPPORTED_BLOCK_TYPES = {BlockType.RESOURCE, TerraformBlockType.DATA}\nWILDCARD_PATTERN = re.compile(r\"(\\S+[.][*][.]*)+\")\n\n\nclass BaseAttributeSolver(BaseSolver):\n    operator = \"\"\n\n    def __init__(self, resource_types: List[str], attribute: Optional[str], value: Any) -> None:\n        super().__init__(SolverType.ATTRIBUTE)\n        self.resource_types = resource_types\n        self.attribute = attribute\n        self.value = value\n\n    def run(self, graph_connector: DiGraph) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:\n        executer = ThreadPoolExecutor()\n        jobs = []\n        passed_vertices: List[Dict[str, Any]] = []\n        failed_vertices: List[Dict[str, Any]] = []\n        for _, data in graph_connector.nodes(data=True):\n            if (not self.resource_types or data.get(CustomAttributes.RESOURCE_TYPE) in self.resource_types) \\\n                    and data.get(CustomAttributes.BLOCK_TYPE) in SUPPORTED_BLOCK_TYPES:\n                jobs.append(executer.submit(self._process_node, data, passed_vertices, failed_vertices))\n\n        concurrent.futures.wait(jobs)\n        return passed_vertices, failed_vertices\n\n    def get_operation(self, vertex: Dict[str, Any]) -> bool:\n        if self.attribute and re.match(WILDCARD_PATTERN, self.attribute):\n            attribute_patterns = self.get_attribute_patterns(self.attribute)\n            attribute_matches = [\n                attr\n                for attr in vertex\n                if any(re.match(re.compile(attribute_pattern), attr) for attribute_pattern in attribute_patterns)\n            ]\n            if attribute_matches:\n                return self.resource_type_pred(vertex, self.resource_types) and any(\n                    self._get_operation(vertex=vertex, attribute=attr) for attr in attribute_matches\n                )\n        return self.resource_type_pred(vertex, self.resource_types) and self._get_operation(\n            vertex=vertex, attribute=self.attribute\n        )\n\n    def _get_operation(self, vertex: Dict[str, Any], attribute: Optional[str]) -> bool:\n        raise NotImplementedError\n\n    def _process_node(\n        self, data: Dict[str, Any], passed_vartices: List[Dict[str, Any]], failed_vertices: List[Dict[str, Any]]\n    ) -> None:\n        if not self.resource_type_pred(data, self.resource_types):\n            return\n        if self.get_operation(vertex=data):\n            passed_vartices.append(data)\n        else:\n            failed_vertices.append(data)\n\n    @staticmethod\n    def get_attribute_patterns(attribute: str) -> Tuple[Pattern[str], Pattern[str]]:\n        index_pattern = r\"[\\d]+\"\n        split_by_dots = attribute.split(\".\")\n\n        pattern_parts = []\n        pattern_parts_without_index = []\n        for attr_part in split_by_dots:\n            if attr_part == \"*\":\n                pattern_parts.append(index_pattern)\n            else:\n                attr_part_pattern = f\"({attr_part})\"\n                pattern_parts.append(attr_part_pattern)\n                pattern_parts_without_index.append(attr_part_pattern)\n\n        pattern = \"[.]\".join(pattern_parts)\n        pattern_with_index = re.compile(pattern)\n\n        pattern = \"[.]\".join(pattern_parts_without_index)\n        pattern_without_index = re.compile(pattern)\n\n        return pattern_with_index, pattern_without_index\n\n    @staticmethod\n    def _is_variable_dependant(value: Any, source: str) -> bool:\n        if source == 'Terraform' and is_terraform_variable_dependent(value):\n            return True\n        # TODO add logic for CloudFormation\n        # elif source == 'CloudFormation' and is_cloudformation_variable_dependent(value):\n        #     return True\n\n        return False\n", "path": "checkov/common/checks_infra/solvers/attribute_solvers/base_attribute_solver.py"}]}