prompt: 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()
  
  ```
  
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
  --- 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)
  
verification_info: {"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"}]}