We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Some ansible playbooks cause checkov crash
Continuation of #4471 

The following playbook (probably because of missing tasks) still causes checkov to crash:

```yaml
- name: Sample play
  hosts:
    - test
  roles:
    - role: somerole
```

cc @gruebel 

--- 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/ansible/graph_builder/local_graph.py`
Content:
```
1 from __future__ import annotations
2 
3 import logging
4 from copy import deepcopy
5 from pathlib import Path
6 from typing import Any
7 
8 from checkov.common.graph.graph_builder import CustomAttributes
9 from checkov.common.graph.graph_builder.consts import GraphSource, SELF_REFERENCE
10 from checkov.common.graph.graph_builder.graph_components.block_types import BlockType
11 from checkov.common.graph.graph_builder.graph_components.blocks import Block
12 from checkov.common.runners.graph_builder.local_graph import ObjectLocalGraph
13 from checkov.common.util.consts import START_LINE, END_LINE
14 from checkov.ansible.graph_builder.graph_components.resource_types import ResourceType
15 from checkov.ansible.utils import get_scannable_file_paths, TASK_RESERVED_KEYWORDS, parse_file
16 
17 
18 class AnsibleLocalGraph(ObjectLocalGraph):
19     def __init__(self, definitions: dict[str | Path, dict[str, Any] | list[dict[str, Any]]]) -> None:
20         super().__init__(definitions=definitions)
21 
22         self.source = GraphSource.ANSIBLE
23 
24     def _create_vertices(self) -> None:
25         for file_path, definition in self.definitions.items():
26             if not isinstance(definition, list):
27                 logging.debug(f"definition of file {file_path} has the wrong type {type(definition)}")
28                 continue
29 
30             file_path = str(file_path)
31 
32             for code_block in definition:
33                 if ResourceType.TASKS in code_block:
34                     for task in code_block[ResourceType.TASKS]:
35                         self._process_blocks(file_path=file_path, task=task)
36                 else:
37                     self._process_blocks(file_path=file_path, task=code_block)
38 
39     def _process_blocks(self, file_path: str, task: Any, prefix: str = "") -> None:
40         """Checks for possible block usage"""
41 
42         if not task or not isinstance(task, dict):
43             return
44 
45         if "block" in task and isinstance(task["block"], list):
46             prefix += f"{ResourceType.BLOCK}."  # with each nested level an extra block prefix is added
47             self._create_block_vertices(file_path=file_path, block=task, prefix=prefix)
48 
49             for block_task in task["block"]:
50                 self._process_blocks(file_path=file_path, task=block_task, prefix=prefix)
51         else:
52             self._create_tasks_vertices(file_path=file_path, task=task, prefix=prefix)
53 
54     def _create_tasks_vertices(self, file_path: str, task: Any, prefix: str = "") -> None:
55         """Creates tasks vertices"""
56 
57         if not task or not isinstance(task, dict):
58             return
59 
60         # grab the task name at the beginning before trying to find the actual module name
61         task_name = task.get("name") or "unknown"
62 
63         for name, config in task.items():
64             if name in TASK_RESERVED_KEYWORDS:
65                 continue
66             if name in (START_LINE, END_LINE):
67                 continue
68 
69             resource_type = f"{ResourceType.TASKS}.{name}"
70 
71             if isinstance(config, str):
72                 # this happens when modules have no parameters and are directly used with the user input
73                 # ex. ansible.builtin.command: cat /etc/passwd
74                 config = {SELF_REFERENCE: config}
75             elif config is None:
76                 # this happens when modules have no parameters and are passed no value
77                 # ex. amazon.aws.ec2_instance_info:
78                 config = {
79                     START_LINE: task[START_LINE],
80                     END_LINE: task[END_LINE],
81                 }
82 
83             attributes = deepcopy(config)
84             attributes[CustomAttributes.RESOURCE_TYPE] = resource_type
85 
86             # only the module code is relevant for validation,
87             # but in the check result the whole task should be visible
88             attributes[START_LINE] = task[START_LINE]
89             attributes[END_LINE] = task[END_LINE]
90 
91             self.vertices.append(
92                 Block(
93                     name=f"{resource_type}.{task_name}",
94                     config=config,
95                     path=file_path,
96                     block_type=BlockType.RESOURCE,
97                     attributes=attributes,
98                     id=f"{resource_type}.{prefix}{task_name}",
99                     source=self.source,
100                 )
101             )
102 
103             # no need to further check
104             break
105 
106     def _create_block_vertices(self, file_path: str, block: dict[str, Any], prefix: str = "") -> None:
107         """Creates block vertices"""
108 
109         # grab the block name, if it exists
110         block_name = block.get("name") or "unknown"
111 
112         config = block
113         attributes = deepcopy(config)
114         attributes[CustomAttributes.RESOURCE_TYPE] = ResourceType.BLOCK
115         del attributes[ResourceType.BLOCK]  # the real block content are tasks, which have their own vertices
116 
117         self.vertices.append(
118             Block(
119                 name=f"{ResourceType.BLOCK}.{block_name}",
120                 config=config,
121                 path=file_path,
122                 block_type=BlockType.RESOURCE,
123                 attributes=attributes,
124                 id=f"{prefix}{block_name}",
125                 source=self.source,
126             )
127         )
128 
129     def _create_edges(self) -> None:
130         return None
131 
132     @staticmethod
133     def get_files_definitions(root_folder: str | Path) -> dict[str | Path, dict[str, Any] | list[dict[str, Any]]]:
134         definitions: "dict[str | Path, dict[str, Any] | list[dict[str, Any]]]" = {}
135         file_paths = get_scannable_file_paths(root_folder=root_folder)
136 
137         for file_path in file_paths:
138             result = parse_file(f=file_path)
139             if result is not None:
140                 definitions[file_path] = result[0]
141 
142         return definitions
143
```
--- 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/ansible/graph_builder/local_graph.py b/checkov/ansible/graph_builder/local_graph.py
--- a/checkov/ansible/graph_builder/local_graph.py
+++ b/checkov/ansible/graph_builder/local_graph.py
@@ -42,11 +42,11 @@
         if not task or not isinstance(task, dict):
             return
 
-        if "block" in task and isinstance(task["block"], list):
+        if ResourceType.BLOCK in task and isinstance(task[ResourceType.BLOCK], list):
             prefix += f"{ResourceType.BLOCK}."  # with each nested level an extra block prefix is added
             self._create_block_vertices(file_path=file_path, block=task, prefix=prefix)
 
-            for block_task in task["block"]:
+            for block_task in task[ResourceType.BLOCK]:
                 self._process_blocks(file_path=file_path, task=block_task, prefix=prefix)
         else:
             self._create_tasks_vertices(file_path=file_path, task=task, prefix=prefix)
@@ -65,6 +65,9 @@
                 continue
             if name in (START_LINE, END_LINE):
                 continue
+            if isinstance(config, list):
+                # either it is actually not an Ansible file or a playbook without tasks refs
+                continue
 
             resource_type = f"{ResourceType.TASKS}.{name}"

{"golden_diff": "diff --git a/checkov/ansible/graph_builder/local_graph.py b/checkov/ansible/graph_builder/local_graph.py\n--- a/checkov/ansible/graph_builder/local_graph.py\n+++ b/checkov/ansible/graph_builder/local_graph.py\n@@ -42,11 +42,11 @@\n         if not task or not isinstance(task, dict):\n             return\n \n-        if \"block\" in task and isinstance(task[\"block\"], list):\n+        if ResourceType.BLOCK in task and isinstance(task[ResourceType.BLOCK], list):\n             prefix += f\"{ResourceType.BLOCK}.\"  # with each nested level an extra block prefix is added\n             self._create_block_vertices(file_path=file_path, block=task, prefix=prefix)\n \n-            for block_task in task[\"block\"]:\n+            for block_task in task[ResourceType.BLOCK]:\n                 self._process_blocks(file_path=file_path, task=block_task, prefix=prefix)\n         else:\n             self._create_tasks_vertices(file_path=file_path, task=task, prefix=prefix)\n@@ -65,6 +65,9 @@\n                 continue\n             if name in (START_LINE, END_LINE):\n                 continue\n+            if isinstance(config, list):\n+                # either it is actually not an Ansible file or a playbook without tasks refs\n+                continue\n \n             resource_type = f\"{ResourceType.TASKS}.{name}\"\n", "issue": "Some ansible playbooks cause checkov crash\nContinuation of #4471 \r\n\r\nThe following playbook (probably because of missing tasks) still causes checkov to crash:\r\n\r\n```yaml\r\n- name: Sample play\r\n  hosts:\r\n    - test\r\n  roles:\r\n    - role: somerole\r\n```\r\n\r\ncc @gruebel \n", "before_files": [{"content": "from __future__ import annotations\n\nimport logging\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom typing import Any\n\nfrom checkov.common.graph.graph_builder import CustomAttributes\nfrom checkov.common.graph.graph_builder.consts import GraphSource, SELF_REFERENCE\nfrom checkov.common.graph.graph_builder.graph_components.block_types import BlockType\nfrom checkov.common.graph.graph_builder.graph_components.blocks import Block\nfrom checkov.common.runners.graph_builder.local_graph import ObjectLocalGraph\nfrom checkov.common.util.consts import START_LINE, END_LINE\nfrom checkov.ansible.graph_builder.graph_components.resource_types import ResourceType\nfrom checkov.ansible.utils import get_scannable_file_paths, TASK_RESERVED_KEYWORDS, parse_file\n\n\nclass AnsibleLocalGraph(ObjectLocalGraph):\n    def __init__(self, definitions: dict[str | Path, dict[str, Any] | list[dict[str, Any]]]) -> None:\n        super().__init__(definitions=definitions)\n\n        self.source = GraphSource.ANSIBLE\n\n    def _create_vertices(self) -> None:\n        for file_path, definition in self.definitions.items():\n            if not isinstance(definition, list):\n                logging.debug(f\"definition of file {file_path} has the wrong type {type(definition)}\")\n                continue\n\n            file_path = str(file_path)\n\n            for code_block in definition:\n                if ResourceType.TASKS in code_block:\n                    for task in code_block[ResourceType.TASKS]:\n                        self._process_blocks(file_path=file_path, task=task)\n                else:\n                    self._process_blocks(file_path=file_path, task=code_block)\n\n    def _process_blocks(self, file_path: str, task: Any, prefix: str = \"\") -> None:\n        \"\"\"Checks for possible block usage\"\"\"\n\n        if not task or not isinstance(task, dict):\n            return\n\n        if \"block\" in task and isinstance(task[\"block\"], list):\n            prefix += f\"{ResourceType.BLOCK}.\"  # with each nested level an extra block prefix is added\n            self._create_block_vertices(file_path=file_path, block=task, prefix=prefix)\n\n            for block_task in task[\"block\"]:\n                self._process_blocks(file_path=file_path, task=block_task, prefix=prefix)\n        else:\n            self._create_tasks_vertices(file_path=file_path, task=task, prefix=prefix)\n\n    def _create_tasks_vertices(self, file_path: str, task: Any, prefix: str = \"\") -> None:\n        \"\"\"Creates tasks vertices\"\"\"\n\n        if not task or not isinstance(task, dict):\n            return\n\n        # grab the task name at the beginning before trying to find the actual module name\n        task_name = task.get(\"name\") or \"unknown\"\n\n        for name, config in task.items():\n            if name in TASK_RESERVED_KEYWORDS:\n                continue\n            if name in (START_LINE, END_LINE):\n                continue\n\n            resource_type = f\"{ResourceType.TASKS}.{name}\"\n\n            if isinstance(config, str):\n                # this happens when modules have no parameters and are directly used with the user input\n                # ex. ansible.builtin.command: cat /etc/passwd\n                config = {SELF_REFERENCE: config}\n            elif config is None:\n                # this happens when modules have no parameters and are passed no value\n                # ex. amazon.aws.ec2_instance_info:\n                config = {\n                    START_LINE: task[START_LINE],\n                    END_LINE: task[END_LINE],\n                }\n\n            attributes = deepcopy(config)\n            attributes[CustomAttributes.RESOURCE_TYPE] = resource_type\n\n            # only the module code is relevant for validation,\n            # but in the check result the whole task should be visible\n            attributes[START_LINE] = task[START_LINE]\n            attributes[END_LINE] = task[END_LINE]\n\n            self.vertices.append(\n                Block(\n                    name=f\"{resource_type}.{task_name}\",\n                    config=config,\n                    path=file_path,\n                    block_type=BlockType.RESOURCE,\n                    attributes=attributes,\n                    id=f\"{resource_type}.{prefix}{task_name}\",\n                    source=self.source,\n                )\n            )\n\n            # no need to further check\n            break\n\n    def _create_block_vertices(self, file_path: str, block: dict[str, Any], prefix: str = \"\") -> None:\n        \"\"\"Creates block vertices\"\"\"\n\n        # grab the block name, if it exists\n        block_name = block.get(\"name\") or \"unknown\"\n\n        config = block\n        attributes = deepcopy(config)\n        attributes[CustomAttributes.RESOURCE_TYPE] = ResourceType.BLOCK\n        del attributes[ResourceType.BLOCK]  # the real block content are tasks, which have their own vertices\n\n        self.vertices.append(\n            Block(\n                name=f\"{ResourceType.BLOCK}.{block_name}\",\n                config=config,\n                path=file_path,\n                block_type=BlockType.RESOURCE,\n                attributes=attributes,\n                id=f\"{prefix}{block_name}\",\n                source=self.source,\n            )\n        )\n\n    def _create_edges(self) -> None:\n        return None\n\n    @staticmethod\n    def get_files_definitions(root_folder: str | Path) -> dict[str | Path, dict[str, Any] | list[dict[str, Any]]]:\n        definitions: \"dict[str | Path, dict[str, Any] | list[dict[str, Any]]]\" = {}\n        file_paths = get_scannable_file_paths(root_folder=root_folder)\n\n        for file_path in file_paths:\n            result = parse_file(f=file_path)\n            if result is not None:\n                definitions[file_path] = result[0]\n\n        return definitions\n", "path": "checkov/ansible/graph_builder/local_graph.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport logging\nfrom copy import deepcopy\nfrom pathlib import Path\nfrom typing import Any\n\nfrom checkov.common.graph.graph_builder import CustomAttributes\nfrom checkov.common.graph.graph_builder.consts import GraphSource, SELF_REFERENCE\nfrom checkov.common.graph.graph_builder.graph_components.block_types import BlockType\nfrom checkov.common.graph.graph_builder.graph_components.blocks import Block\nfrom checkov.common.runners.graph_builder.local_graph import ObjectLocalGraph\nfrom checkov.common.util.consts import START_LINE, END_LINE\nfrom checkov.ansible.graph_builder.graph_components.resource_types import ResourceType\nfrom checkov.ansible.utils import get_scannable_file_paths, TASK_RESERVED_KEYWORDS, parse_file\n\n\nclass AnsibleLocalGraph(ObjectLocalGraph):\n    def __init__(self, definitions: dict[str | Path, dict[str, Any] | list[dict[str, Any]]]) -> None:\n        super().__init__(definitions=definitions)\n\n        self.source = GraphSource.ANSIBLE\n\n    def _create_vertices(self) -> None:\n        for file_path, definition in self.definitions.items():\n            if not isinstance(definition, list):\n                logging.debug(f\"definition of file {file_path} has the wrong type {type(definition)}\")\n                continue\n\n            file_path = str(file_path)\n\n            for code_block in definition:\n                if ResourceType.TASKS in code_block:\n                    for task in code_block[ResourceType.TASKS]:\n                        self._process_blocks(file_path=file_path, task=task)\n                else:\n                    self._process_blocks(file_path=file_path, task=code_block)\n\n    def _process_blocks(self, file_path: str, task: Any, prefix: str = \"\") -> None:\n        \"\"\"Checks for possible block usage\"\"\"\n\n        if not task or not isinstance(task, dict):\n            return\n\n        if ResourceType.BLOCK in task and isinstance(task[ResourceType.BLOCK], list):\n            prefix += f\"{ResourceType.BLOCK}.\"  # with each nested level an extra block prefix is added\n            self._create_block_vertices(file_path=file_path, block=task, prefix=prefix)\n\n            for block_task in task[ResourceType.BLOCK]:\n                self._process_blocks(file_path=file_path, task=block_task, prefix=prefix)\n        else:\n            self._create_tasks_vertices(file_path=file_path, task=task, prefix=prefix)\n\n    def _create_tasks_vertices(self, file_path: str, task: Any, prefix: str = \"\") -> None:\n        \"\"\"Creates tasks vertices\"\"\"\n\n        if not task or not isinstance(task, dict):\n            return\n\n        # grab the task name at the beginning before trying to find the actual module name\n        task_name = task.get(\"name\") or \"unknown\"\n\n        for name, config in task.items():\n            if name in TASK_RESERVED_KEYWORDS:\n                continue\n            if name in (START_LINE, END_LINE):\n                continue\n            if isinstance(config, list):\n                # either it is actually not an Ansible file or a playbook without tasks refs\n                continue\n\n            resource_type = f\"{ResourceType.TASKS}.{name}\"\n\n            if isinstance(config, str):\n                # this happens when modules have no parameters and are directly used with the user input\n                # ex. ansible.builtin.command: cat /etc/passwd\n                config = {SELF_REFERENCE: config}\n            elif config is None:\n                # this happens when modules have no parameters and are passed no value\n                # ex. amazon.aws.ec2_instance_info:\n                config = {\n                    START_LINE: task[START_LINE],\n                    END_LINE: task[END_LINE],\n                }\n\n            attributes = deepcopy(config)\n            attributes[CustomAttributes.RESOURCE_TYPE] = resource_type\n\n            # only the module code is relevant for validation,\n            # but in the check result the whole task should be visible\n            attributes[START_LINE] = task[START_LINE]\n            attributes[END_LINE] = task[END_LINE]\n\n            self.vertices.append(\n                Block(\n                    name=f\"{resource_type}.{task_name}\",\n                    config=config,\n                    path=file_path,\n                    block_type=BlockType.RESOURCE,\n                    attributes=attributes,\n                    id=f\"{resource_type}.{prefix}{task_name}\",\n                    source=self.source,\n                )\n            )\n\n            # no need to further check\n            break\n\n    def _create_block_vertices(self, file_path: str, block: dict[str, Any], prefix: str = \"\") -> None:\n        \"\"\"Creates block vertices\"\"\"\n\n        # grab the block name, if it exists\n        block_name = block.get(\"name\") or \"unknown\"\n\n        config = block\n        attributes = deepcopy(config)\n        attributes[CustomAttributes.RESOURCE_TYPE] = ResourceType.BLOCK\n        del attributes[ResourceType.BLOCK]  # the real block content are tasks, which have their own vertices\n\n        self.vertices.append(\n            Block(\n                name=f\"{ResourceType.BLOCK}.{block_name}\",\n                config=config,\n                path=file_path,\n                block_type=BlockType.RESOURCE,\n                attributes=attributes,\n                id=f\"{prefix}{block_name}\",\n                source=self.source,\n            )\n        )\n\n    def _create_edges(self) -> None:\n        return None\n\n    @staticmethod\n    def get_files_definitions(root_folder: str | Path) -> dict[str | Path, dict[str, Any] | list[dict[str, Any]]]:\n        definitions: \"dict[str | Path, dict[str, Any] | list[dict[str, Any]]]\" = {}\n        file_paths = get_scannable_file_paths(root_folder=root_folder)\n\n        for file_path in file_paths:\n            result = parse_file(f=file_path)\n            if result is not None:\n                definitions[file_path] = result[0]\n\n        return definitions\n", "path": "checkov/ansible/graph_builder/local_graph.py"}]}