We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add --compact behaviour to json output
**Describe the issue**

For the json output, it would be nice to have the possibility of using the '--compact' option as for the CLI.

As for the CLI, maybe we only want to know the "file_path" and the "file_line_range" without having the code itself.
The "code_block" in the json is really hard to read because it creates a field per line with the line number.
Checkov will copy that block for each check and makes the json really long if the block is long (e.g. kubernetes cluster description) and it has several vulnerabilities in it.
So it would be nice to be able to not include it in the json output.
Thanks in advance.

code_block example (for a GCP subnet) :
```
"code_block": [
	[
		24,
		"resource \"google_compute_subnetwork\" \"dummy\" {\n"
	],
	[
		25,
		"  name          = \"${var.name_root}-${random_pet.subnet.id}\"\n"
	],
	[
		26,
		"  region        = var.region\n"
	],
	[
		27,
		"  network       = google_compute_network.dummy.name\n"
	],
	[
		28,
		"  ip_cidr_range = \"10.40.1.0/24\"\n"
	],
	[
		29,
		"}\n"
	]
]

```
**Additional context**
Add any other context about the problem here.


--- 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/runners/runner_registry.py`
Content:
```
1 import argparse
2 import itertools
3 import json
4 import re
5 from collections import defaultdict
6 from json import dumps
7 import logging
8 import os
9 from abc import abstractmethod
10 from typing import List, Union, Dict, Any, Tuple, Optional
11 
12 from typing_extensions import Literal
13 
14 from checkov.common.bridgecrew.integration_features.integration_feature_registry import integration_feature_registry
15 from checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import integration as metadata_integration
16 from checkov.common.output.baseline import Baseline
17 from checkov.common.output.report import Report
18 from checkov.common.runners.base_runner import BaseRunner
19 from checkov.common.util import data_structures_utils
20 from checkov.common.util.json_utils import CustomJSONEncoder
21 from checkov.runner_filter import RunnerFilter
22 from checkov.terraform.context_parsers.registry import parser_registry
23 from checkov.terraform.runner import Runner as tf_runner
24 from checkov.terraform.parser import Parser
25 from checkov.common.parallelizer.parallel_runner import parallel_runner
26 from checkov.common.util.ext_cyclonedx_xml import ExtXml
27 from checkov.common.util.banner import tool as tool_name
28 
29 CHECK_BLOCK_TYPES = frozenset(["resource", "data", "provider", "module"])
30 OUTPUT_CHOICES = ["cli", "cyclonedx", "json", "junitxml", "github_failed_only", "sarif"]
31 OUTPUT_DELIMITER = "\n--- OUTPUT DELIMITER ---\n"
32 
33 
34 class RunnerRegistry:
35     runners: List[BaseRunner] = []
36     scan_reports: List[Report] = []
37     banner = ""
38 
39     def __init__(self, banner: str, runner_filter: RunnerFilter, *runners: BaseRunner) -> None:
40         self.logger = logging.getLogger(__name__)
41         self.runner_filter = runner_filter
42         self.runners = list(runners)
43         self.banner = banner
44         self.scan_reports = []
45         self.filter_runner_framework()
46         self.tool = tool_name
47 
48     @abstractmethod
49     def extract_entity_details(self, entity: Dict[str, Any]) -> Tuple[str, str, Dict[str, Any]]:
50         raise NotImplementedError()
51 
52     def run(
53         self,
54         root_folder: Optional[str] = None,
55         external_checks_dir: Optional[List[str]] = None,
56         files: Optional[List[str]] = None,
57         collect_skip_comments: bool = True,
58         repo_root_for_plan_enrichment: Optional[List[Union[str, os.PathLike]]] = None,
59     ) -> List[Report]:
60         integration_feature_registry.run_pre_runner()
61         if len(self.runners) == 1:
62             reports = [self.runners[0].run(root_folder, external_checks_dir=external_checks_dir, files=files,
63                                            runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments)]
64         else:
65             reports = parallel_runner.run_function(
66                 lambda runner: runner.run(root_folder, external_checks_dir=external_checks_dir, files=files,
67                                           runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments),
68                 self.runners, 1)
69 
70         for scan_report in reports:
71             self._handle_report(scan_report, repo_root_for_plan_enrichment)
72         return self.scan_reports
73 
74     def _handle_report(self, scan_report, repo_root_for_plan_enrichment):
75         integration_feature_registry.run_post_runner(scan_report)
76         if metadata_integration.check_metadata:
77             RunnerRegistry.enrich_report_with_guidelines(scan_report)
78         if repo_root_for_plan_enrichment:
79             enriched_resources = RunnerRegistry.get_enriched_resources(repo_root_for_plan_enrichment)
80             scan_report = Report("terraform_plan").enrich_plan_report(scan_report, enriched_resources)
81             scan_report = Report("terraform_plan").handle_skipped_checks(scan_report, enriched_resources)
82         self.scan_reports.append(scan_report)
83 
84     def save_output_to_file(self, file_name: str, data: str, data_format: str) -> None:
85         try:
86             with open(file_name, 'w') as f:
87                 f.write(data)
88             logging.info(f"\nWrote output in {data_format} format to the file '{file_name}')")
89         except EnvironmentError:
90             logging.error(f"\nAn error occurred while writing {data_format} results to file: {file_name}", exc_info=True)
91 
92     def print_reports(
93         self,
94         scan_reports: List[Report],
95         config: argparse.Namespace,
96         url: Optional[str] = None,
97         created_baseline_path: Optional[str] = None,
98         baseline: Optional[Baseline] = None,
99     ) -> Literal[0, 1]:
100         output_formats = set(config.output)
101 
102         if "cli" in config.output and not config.quiet:
103             print(f"{self.banner}\n")
104         exit_codes = []
105         cli_reports = []
106         report_jsons = []
107         sarif_reports = []
108         junit_reports = []
109         cyclonedx_reports = []
110         data_outputs = defaultdict(str)
111         for report in scan_reports:
112             if not report.is_empty():
113                 if "json" in config.output:
114                     report_jsons.append(report.get_dict(is_quiet=config.quiet, url=url))
115                 if "junitxml" in config.output:
116                     junit_reports.append(report)
117                 if "github_failed_only" in config.output:
118                     data_outputs["github_failed_only"] += report.print_failed_github_md(use_bc_ids=config.output_bc_ids)
119                 if "sarif" in config.output:
120                     sarif_reports.append(report)
121                 if "cli" in config.output:
122                     cli_reports.append(report)
123                 if "cyclonedx" in config.output:
124                     cyclonedx_reports.append(report)
125             logging.debug(f'Getting exit code for report {report.check_type}')
126             exit_codes.append(report.get_exit_code(config.soft_fail, config.soft_fail_on, config.hard_fail_on))
127 
128         if "cli" in config.output:
129             cli_output = ''
130             for report in cli_reports:
131                 cli_output += report.print_console(
132                     is_quiet=config.quiet,
133                     is_compact=config.compact,
134                     created_baseline_path=created_baseline_path,
135                     baseline=baseline,
136                     use_bc_ids=config.output_bc_ids,
137                 )
138             print(cli_output)
139             # Remove colors from the cli output
140             ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
141             data_outputs['cli'] = ansi_escape.sub('', cli_output)
142             if url:
143                 print("More details: {}".format(url))
144             output_formats.remove("cli")
145             if output_formats:
146                 print(OUTPUT_DELIMITER)
147         if "sarif" in config.output:
148             master_report = Report("merged")
149             print(self.banner)
150             for report in sarif_reports:
151                 print(report.print_console(
152                         is_quiet=config.quiet,
153                         is_compact=config.compact,
154                         created_baseline_path=created_baseline_path,
155                         baseline=baseline,
156                         use_bc_ids=config.output_bc_ids,
157                 ))
158                 master_report.failed_checks += report.failed_checks
159                 master_report.skipped_checks += report.skipped_checks
160             if url:
161                 print("More details: {}".format(url))
162             master_report.write_sarif_output(self.tool)
163             data_outputs['sarif'] = json.dumps(master_report.get_sarif_json(self.tool), cls=CustomJSONEncoder)
164             output_formats.remove("sarif")
165             if output_formats:
166                 print(OUTPUT_DELIMITER)
167         if "json" in config.output:
168             if not report_jsons:
169                 print(dumps(Report(None).get_summary(), indent=4, cls=CustomJSONEncoder))
170                 data_outputs['json'] = json.dumps(Report(None).get_summary(), cls=CustomJSONEncoder)
171             elif len(report_jsons) == 1:
172                 print(dumps(report_jsons[0], indent=4, cls=CustomJSONEncoder))
173                 data_outputs['json'] = json.dumps(report_jsons[0], cls=CustomJSONEncoder)
174             else:
175                 print(dumps(report_jsons, indent=4, cls=CustomJSONEncoder))
176                 data_outputs['json'] = json.dumps(report_jsons, cls=CustomJSONEncoder)
177             output_formats.remove("json")
178             if output_formats:
179                 print(OUTPUT_DELIMITER)
180         if "junitxml" in config.output:
181             properties = Report.create_test_suite_properties_block(config)
182 
183             if junit_reports:
184                 test_suites = [
185                     report.get_test_suite(properties=properties, use_bc_ids=config.output_bc_ids)
186                     for report in junit_reports
187                 ]
188             else:
189                 test_suites = [Report(None).get_test_suite(properties=properties)]
190 
191             data_outputs['junitxml'] = Report.get_junit_xml_string(test_suites)
192             print(data_outputs['junitxml'])
193 
194             output_formats.remove("junitxml")
195             if output_formats:
196                 print(OUTPUT_DELIMITER)
197         if "cyclonedx" in config.output:
198             if cyclonedx_reports:
199                 # More than one Report - combine Reports first
200                 report = Report(None)
201                 for r in cyclonedx_reports:
202                     report.passed_checks += r.passed_checks
203                     report.skipped_checks += r.skipped_checks
204                     report.failed_checks += r.failed_checks
205             else:
206                 report = cyclonedx_reports[0]
207             cyclonedx_output = ExtXml(bom=report.get_cyclonedx_bom())
208             print(cyclonedx_output.output_as_string())
209             data_outputs['cyclonedx'] = cyclonedx_output.output_as_string()
210             output_formats.remove("cyclonedx")
211             if output_formats:
212                 print(OUTPUT_DELIMITER)
213 
214         # Save output to file
215         file_names = {'cli': 'results_cli.txt', 'github_failed_only': 'results_github_failed_only.txt', 'sarif': 'results_sarif.sarif',
216                       'json': 'results_json.json', 'junitxml': 'results_junitxml.xml', 'cyclonedx': 'results_cyclonedx.xml'}
217         if config.output_file_path:
218             for output in config.output:
219                 self.save_output_to_file(file_name=f'{config.output_file_path}/{file_names[output]}', data=data_outputs[output],
220                                      data_format=output)
221         exit_code = 1 if 1 in exit_codes else 0
222         return exit_code
223 
224     def filter_runner_framework(self) -> None:
225         if not self.runner_filter:
226             return
227         if not self.runner_filter.framework:
228             return
229         if "all" in self.runner_filter.framework:
230             return
231         self.runners = [runner for runner in self.runners if runner.check_type in self.runner_filter.framework]
232 
233     def remove_runner(self, runner: BaseRunner) -> None:
234         if runner in self.runners:
235             self.runners.remove(runner)
236 
237     @staticmethod
238     def enrich_report_with_guidelines(scan_report: Report) -> None:
239         for record in itertools.chain(scan_report.failed_checks, scan_report.passed_checks, scan_report.skipped_checks):
240             guideline = metadata_integration.get_guideline(record.check_id)
241             if guideline:
242                 record.set_guideline(guideline)
243 
244     @staticmethod
245     def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[str, Dict[str, Any]]:
246         repo_definitions = {}
247         for repo_root in repo_roots:
248             tf_definitions = {}
249             parsing_errors = {}
250             Parser().parse_directory(
251                 directory=repo_root,  # assume plan file is in the repo-root
252                 out_definitions=tf_definitions,
253                 out_parsing_errors=parsing_errors,
254             )
255             repo_definitions[repo_root] = {'tf_definitions': tf_definitions, 'parsing_errors': parsing_errors}
256 
257         enriched_resources = {}
258         for repo_root, parse_results in repo_definitions.items():
259             for full_file_path, definition in parse_results['tf_definitions'].items():
260                 definitions_context = parser_registry.enrich_definitions_context((full_file_path, definition))
261                 abs_scanned_file, _ = tf_runner._strip_module_referrer(full_file_path)
262                 scanned_file = os.path.relpath(abs_scanned_file, repo_root)
263                 for block_type, block_value in definition.items():
264                     if block_type in CHECK_BLOCK_TYPES:
265                         for entity in block_value:
266                             context_parser = parser_registry.context_parsers[block_type]
267                             definition_path = context_parser.get_entity_context_path(entity)
268                             entity_id = ".".join(definition_path)
269                             entity_context_path = [block_type] + definition_path
270                             entity_context = data_structures_utils.get_inner_dict(
271                                 definitions_context[full_file_path], entity_context_path
272                             )
273                             entity_lines_range = [
274                                 entity_context.get("start_line"),
275                                 entity_context.get("end_line"),
276                             ]
277                             entity_code_lines = entity_context.get("code_lines")
278                             skipped_checks = entity_context.get("skipped_checks")
279                             enriched_resources[entity_id] = {
280                                 "entity_code_lines": entity_code_lines,
281                                 "entity_lines_range": entity_lines_range,
282                                 "scanned_file": scanned_file,
283                                 "skipped_checks": skipped_checks,
284                             }
285         return enriched_resources
286
```
--- 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/runners/runner_registry.py b/checkov/common/runners/runner_registry.py
--- a/checkov/common/runners/runner_registry.py
+++ b/checkov/common/runners/runner_registry.py
@@ -165,6 +165,8 @@
             if output_formats:
                 print(OUTPUT_DELIMITER)
         if "json" in config.output:
+            if config.compact and report_jsons:
+                self.strip_code_blocks_from_json(report_jsons)
             if not report_jsons:
                 print(dumps(Report(None).get_summary(), indent=4, cls=CustomJSONEncoder))
                 data_outputs['json'] = json.dumps(Report(None).get_summary(), cls=CustomJSONEncoder)
@@ -283,3 +285,12 @@
                                 "skipped_checks": skipped_checks,
                             }
         return enriched_resources
+
+    @staticmethod
+    def strip_code_blocks_from_json(report_jsons: List[Dict[str, Any]]) -> None:
+        for report in report_jsons:
+            results = report.get('results', {})
+            for key, result in results.items():
+                for result_dict in result:
+                    result_dict.pop('code_block', None)
+                    result_dict.pop('connected_node', None)

{"golden_diff": "diff --git a/checkov/common/runners/runner_registry.py b/checkov/common/runners/runner_registry.py\n--- a/checkov/common/runners/runner_registry.py\n+++ b/checkov/common/runners/runner_registry.py\n@@ -165,6 +165,8 @@\n             if output_formats:\n                 print(OUTPUT_DELIMITER)\n         if \"json\" in config.output:\n+            if config.compact and report_jsons:\n+                self.strip_code_blocks_from_json(report_jsons)\n             if not report_jsons:\n                 print(dumps(Report(None).get_summary(), indent=4, cls=CustomJSONEncoder))\n                 data_outputs['json'] = json.dumps(Report(None).get_summary(), cls=CustomJSONEncoder)\n@@ -283,3 +285,12 @@\n                                 \"skipped_checks\": skipped_checks,\n                             }\n         return enriched_resources\n+\n+    @staticmethod\n+    def strip_code_blocks_from_json(report_jsons: List[Dict[str, Any]]) -> None:\n+        for report in report_jsons:\n+            results = report.get('results', {})\n+            for key, result in results.items():\n+                for result_dict in result:\n+                    result_dict.pop('code_block', None)\n+                    result_dict.pop('connected_node', None)\n", "issue": "Add --compact behaviour to json output\n**Describe the issue**\r\n\r\nFor the json output, it would be nice to have the possibility of using the '--compact' option as for the CLI.\r\n\r\nAs for the CLI, maybe we only want to know the \"file_path\" and the \"file_line_range\" without having the code itself.\r\nThe \"code_block\" in the json is really hard to read because it creates a field per line with the line number.\r\nCheckov will copy that block for each check and makes the json really long if the block is long (e.g. kubernetes cluster description) and it has several vulnerabilities in it.\r\nSo it would be nice to be able to not include it in the json output.\r\nThanks in advance.\r\n\r\ncode_block example (for a GCP subnet) :\r\n```\r\n\"code_block\": [\r\n\t[\r\n\t\t24,\r\n\t\t\"resource \\\"google_compute_subnetwork\\\" \\\"dummy\\\" {\\n\"\r\n\t],\r\n\t[\r\n\t\t25,\r\n\t\t\"  name          = \\\"${var.name_root}-${random_pet.subnet.id}\\\"\\n\"\r\n\t],\r\n\t[\r\n\t\t26,\r\n\t\t\"  region        = var.region\\n\"\r\n\t],\r\n\t[\r\n\t\t27,\r\n\t\t\"  network       = google_compute_network.dummy.name\\n\"\r\n\t],\r\n\t[\r\n\t\t28,\r\n\t\t\"  ip_cidr_range = \\\"10.40.1.0/24\\\"\\n\"\r\n\t],\r\n\t[\r\n\t\t29,\r\n\t\t\"}\\n\"\r\n\t]\r\n]\r\n\r\n```\r\n**Additional context**\r\nAdd any other context about the problem here.\r\n\n", "before_files": [{"content": "import argparse\nimport itertools\nimport json\nimport re\nfrom collections import defaultdict\nfrom json import dumps\nimport logging\nimport os\nfrom abc import abstractmethod\nfrom typing import List, Union, Dict, Any, Tuple, Optional\n\nfrom typing_extensions import Literal\n\nfrom checkov.common.bridgecrew.integration_features.integration_feature_registry import integration_feature_registry\nfrom checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import integration as metadata_integration\nfrom checkov.common.output.baseline import Baseline\nfrom checkov.common.output.report import Report\nfrom checkov.common.runners.base_runner import BaseRunner\nfrom checkov.common.util import data_structures_utils\nfrom checkov.common.util.json_utils import CustomJSONEncoder\nfrom checkov.runner_filter import RunnerFilter\nfrom checkov.terraform.context_parsers.registry import parser_registry\nfrom checkov.terraform.runner import Runner as tf_runner\nfrom checkov.terraform.parser import Parser\nfrom checkov.common.parallelizer.parallel_runner import parallel_runner\nfrom checkov.common.util.ext_cyclonedx_xml import ExtXml\nfrom checkov.common.util.banner import tool as tool_name\n\nCHECK_BLOCK_TYPES = frozenset([\"resource\", \"data\", \"provider\", \"module\"])\nOUTPUT_CHOICES = [\"cli\", \"cyclonedx\", \"json\", \"junitxml\", \"github_failed_only\", \"sarif\"]\nOUTPUT_DELIMITER = \"\\n--- OUTPUT DELIMITER ---\\n\"\n\n\nclass RunnerRegistry:\n    runners: List[BaseRunner] = []\n    scan_reports: List[Report] = []\n    banner = \"\"\n\n    def __init__(self, banner: str, runner_filter: RunnerFilter, *runners: BaseRunner) -> None:\n        self.logger = logging.getLogger(__name__)\n        self.runner_filter = runner_filter\n        self.runners = list(runners)\n        self.banner = banner\n        self.scan_reports = []\n        self.filter_runner_framework()\n        self.tool = tool_name\n\n    @abstractmethod\n    def extract_entity_details(self, entity: Dict[str, Any]) -> Tuple[str, str, Dict[str, Any]]:\n        raise NotImplementedError()\n\n    def run(\n        self,\n        root_folder: Optional[str] = None,\n        external_checks_dir: Optional[List[str]] = None,\n        files: Optional[List[str]] = None,\n        collect_skip_comments: bool = True,\n        repo_root_for_plan_enrichment: Optional[List[Union[str, os.PathLike]]] = None,\n    ) -> List[Report]:\n        integration_feature_registry.run_pre_runner()\n        if len(self.runners) == 1:\n            reports = [self.runners[0].run(root_folder, external_checks_dir=external_checks_dir, files=files,\n                                           runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments)]\n        else:\n            reports = parallel_runner.run_function(\n                lambda runner: runner.run(root_folder, external_checks_dir=external_checks_dir, files=files,\n                                          runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments),\n                self.runners, 1)\n\n        for scan_report in reports:\n            self._handle_report(scan_report, repo_root_for_plan_enrichment)\n        return self.scan_reports\n\n    def _handle_report(self, scan_report, repo_root_for_plan_enrichment):\n        integration_feature_registry.run_post_runner(scan_report)\n        if metadata_integration.check_metadata:\n            RunnerRegistry.enrich_report_with_guidelines(scan_report)\n        if repo_root_for_plan_enrichment:\n            enriched_resources = RunnerRegistry.get_enriched_resources(repo_root_for_plan_enrichment)\n            scan_report = Report(\"terraform_plan\").enrich_plan_report(scan_report, enriched_resources)\n            scan_report = Report(\"terraform_plan\").handle_skipped_checks(scan_report, enriched_resources)\n        self.scan_reports.append(scan_report)\n\n    def save_output_to_file(self, file_name: str, data: str, data_format: str) -> None:\n        try:\n            with open(file_name, 'w') as f:\n                f.write(data)\n            logging.info(f\"\\nWrote output in {data_format} format to the file '{file_name}')\")\n        except EnvironmentError:\n            logging.error(f\"\\nAn error occurred while writing {data_format} results to file: {file_name}\", exc_info=True)\n\n    def print_reports(\n        self,\n        scan_reports: List[Report],\n        config: argparse.Namespace,\n        url: Optional[str] = None,\n        created_baseline_path: Optional[str] = None,\n        baseline: Optional[Baseline] = None,\n    ) -> Literal[0, 1]:\n        output_formats = set(config.output)\n\n        if \"cli\" in config.output and not config.quiet:\n            print(f\"{self.banner}\\n\")\n        exit_codes = []\n        cli_reports = []\n        report_jsons = []\n        sarif_reports = []\n        junit_reports = []\n        cyclonedx_reports = []\n        data_outputs = defaultdict(str)\n        for report in scan_reports:\n            if not report.is_empty():\n                if \"json\" in config.output:\n                    report_jsons.append(report.get_dict(is_quiet=config.quiet, url=url))\n                if \"junitxml\" in config.output:\n                    junit_reports.append(report)\n                if \"github_failed_only\" in config.output:\n                    data_outputs[\"github_failed_only\"] += report.print_failed_github_md(use_bc_ids=config.output_bc_ids)\n                if \"sarif\" in config.output:\n                    sarif_reports.append(report)\n                if \"cli\" in config.output:\n                    cli_reports.append(report)\n                if \"cyclonedx\" in config.output:\n                    cyclonedx_reports.append(report)\n            logging.debug(f'Getting exit code for report {report.check_type}')\n            exit_codes.append(report.get_exit_code(config.soft_fail, config.soft_fail_on, config.hard_fail_on))\n\n        if \"cli\" in config.output:\n            cli_output = ''\n            for report in cli_reports:\n                cli_output += report.print_console(\n                    is_quiet=config.quiet,\n                    is_compact=config.compact,\n                    created_baseline_path=created_baseline_path,\n                    baseline=baseline,\n                    use_bc_ids=config.output_bc_ids,\n                )\n            print(cli_output)\n            # Remove colors from the cli output\n            ansi_escape = re.compile(r'(?:\\x1B[@-_]|[\\x80-\\x9F])[0-?]*[ -/]*[@-~]')\n            data_outputs['cli'] = ansi_escape.sub('', cli_output)\n            if url:\n                print(\"More details: {}\".format(url))\n            output_formats.remove(\"cli\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"sarif\" in config.output:\n            master_report = Report(\"merged\")\n            print(self.banner)\n            for report in sarif_reports:\n                print(report.print_console(\n                        is_quiet=config.quiet,\n                        is_compact=config.compact,\n                        created_baseline_path=created_baseline_path,\n                        baseline=baseline,\n                        use_bc_ids=config.output_bc_ids,\n                ))\n                master_report.failed_checks += report.failed_checks\n                master_report.skipped_checks += report.skipped_checks\n            if url:\n                print(\"More details: {}\".format(url))\n            master_report.write_sarif_output(self.tool)\n            data_outputs['sarif'] = json.dumps(master_report.get_sarif_json(self.tool), cls=CustomJSONEncoder)\n            output_formats.remove(\"sarif\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"json\" in config.output:\n            if not report_jsons:\n                print(dumps(Report(None).get_summary(), indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(Report(None).get_summary(), cls=CustomJSONEncoder)\n            elif len(report_jsons) == 1:\n                print(dumps(report_jsons[0], indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(report_jsons[0], cls=CustomJSONEncoder)\n            else:\n                print(dumps(report_jsons, indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(report_jsons, cls=CustomJSONEncoder)\n            output_formats.remove(\"json\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"junitxml\" in config.output:\n            properties = Report.create_test_suite_properties_block(config)\n\n            if junit_reports:\n                test_suites = [\n                    report.get_test_suite(properties=properties, use_bc_ids=config.output_bc_ids)\n                    for report in junit_reports\n                ]\n            else:\n                test_suites = [Report(None).get_test_suite(properties=properties)]\n\n            data_outputs['junitxml'] = Report.get_junit_xml_string(test_suites)\n            print(data_outputs['junitxml'])\n\n            output_formats.remove(\"junitxml\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"cyclonedx\" in config.output:\n            if cyclonedx_reports:\n                # More than one Report - combine Reports first\n                report = Report(None)\n                for r in cyclonedx_reports:\n                    report.passed_checks += r.passed_checks\n                    report.skipped_checks += r.skipped_checks\n                    report.failed_checks += r.failed_checks\n            else:\n                report = cyclonedx_reports[0]\n            cyclonedx_output = ExtXml(bom=report.get_cyclonedx_bom())\n            print(cyclonedx_output.output_as_string())\n            data_outputs['cyclonedx'] = cyclonedx_output.output_as_string()\n            output_formats.remove(\"cyclonedx\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n\n        # Save output to file\n        file_names = {'cli': 'results_cli.txt', 'github_failed_only': 'results_github_failed_only.txt', 'sarif': 'results_sarif.sarif',\n                      'json': 'results_json.json', 'junitxml': 'results_junitxml.xml', 'cyclonedx': 'results_cyclonedx.xml'}\n        if config.output_file_path:\n            for output in config.output:\n                self.save_output_to_file(file_name=f'{config.output_file_path}/{file_names[output]}', data=data_outputs[output],\n                                     data_format=output)\n        exit_code = 1 if 1 in exit_codes else 0\n        return exit_code\n\n    def filter_runner_framework(self) -> None:\n        if not self.runner_filter:\n            return\n        if not self.runner_filter.framework:\n            return\n        if \"all\" in self.runner_filter.framework:\n            return\n        self.runners = [runner for runner in self.runners if runner.check_type in self.runner_filter.framework]\n\n    def remove_runner(self, runner: BaseRunner) -> None:\n        if runner in self.runners:\n            self.runners.remove(runner)\n\n    @staticmethod\n    def enrich_report_with_guidelines(scan_report: Report) -> None:\n        for record in itertools.chain(scan_report.failed_checks, scan_report.passed_checks, scan_report.skipped_checks):\n            guideline = metadata_integration.get_guideline(record.check_id)\n            if guideline:\n                record.set_guideline(guideline)\n\n    @staticmethod\n    def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[str, Dict[str, Any]]:\n        repo_definitions = {}\n        for repo_root in repo_roots:\n            tf_definitions = {}\n            parsing_errors = {}\n            Parser().parse_directory(\n                directory=repo_root,  # assume plan file is in the repo-root\n                out_definitions=tf_definitions,\n                out_parsing_errors=parsing_errors,\n            )\n            repo_definitions[repo_root] = {'tf_definitions': tf_definitions, 'parsing_errors': parsing_errors}\n\n        enriched_resources = {}\n        for repo_root, parse_results in repo_definitions.items():\n            for full_file_path, definition in parse_results['tf_definitions'].items():\n                definitions_context = parser_registry.enrich_definitions_context((full_file_path, definition))\n                abs_scanned_file, _ = tf_runner._strip_module_referrer(full_file_path)\n                scanned_file = os.path.relpath(abs_scanned_file, repo_root)\n                for block_type, block_value in definition.items():\n                    if block_type in CHECK_BLOCK_TYPES:\n                        for entity in block_value:\n                            context_parser = parser_registry.context_parsers[block_type]\n                            definition_path = context_parser.get_entity_context_path(entity)\n                            entity_id = \".\".join(definition_path)\n                            entity_context_path = [block_type] + definition_path\n                            entity_context = data_structures_utils.get_inner_dict(\n                                definitions_context[full_file_path], entity_context_path\n                            )\n                            entity_lines_range = [\n                                entity_context.get(\"start_line\"),\n                                entity_context.get(\"end_line\"),\n                            ]\n                            entity_code_lines = entity_context.get(\"code_lines\")\n                            skipped_checks = entity_context.get(\"skipped_checks\")\n                            enriched_resources[entity_id] = {\n                                \"entity_code_lines\": entity_code_lines,\n                                \"entity_lines_range\": entity_lines_range,\n                                \"scanned_file\": scanned_file,\n                                \"skipped_checks\": skipped_checks,\n                            }\n        return enriched_resources\n", "path": "checkov/common/runners/runner_registry.py"}], "after_files": [{"content": "import argparse\nimport itertools\nimport json\nimport re\nfrom collections import defaultdict\nfrom json import dumps\nimport logging\nimport os\nfrom abc import abstractmethod\nfrom typing import List, Union, Dict, Any, Tuple, Optional\n\nfrom typing_extensions import Literal\n\nfrom checkov.common.bridgecrew.integration_features.integration_feature_registry import integration_feature_registry\nfrom checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import integration as metadata_integration\nfrom checkov.common.output.baseline import Baseline\nfrom checkov.common.output.report import Report\nfrom checkov.common.runners.base_runner import BaseRunner\nfrom checkov.common.util import data_structures_utils\nfrom checkov.common.util.json_utils import CustomJSONEncoder\nfrom checkov.runner_filter import RunnerFilter\nfrom checkov.terraform.context_parsers.registry import parser_registry\nfrom checkov.terraform.runner import Runner as tf_runner\nfrom checkov.terraform.parser import Parser\nfrom checkov.common.parallelizer.parallel_runner import parallel_runner\nfrom checkov.common.util.ext_cyclonedx_xml import ExtXml\nfrom checkov.common.util.banner import tool as tool_name\n\nCHECK_BLOCK_TYPES = frozenset([\"resource\", \"data\", \"provider\", \"module\"])\nOUTPUT_CHOICES = [\"cli\", \"cyclonedx\", \"json\", \"junitxml\", \"github_failed_only\", \"sarif\"]\nOUTPUT_DELIMITER = \"\\n--- OUTPUT DELIMITER ---\\n\"\n\n\nclass RunnerRegistry:\n    runners: List[BaseRunner] = []\n    scan_reports: List[Report] = []\n    banner = \"\"\n\n    def __init__(self, banner: str, runner_filter: RunnerFilter, *runners: BaseRunner) -> None:\n        self.logger = logging.getLogger(__name__)\n        self.runner_filter = runner_filter\n        self.runners = list(runners)\n        self.banner = banner\n        self.scan_reports = []\n        self.filter_runner_framework()\n        self.tool = tool_name\n\n    @abstractmethod\n    def extract_entity_details(self, entity: Dict[str, Any]) -> Tuple[str, str, Dict[str, Any]]:\n        raise NotImplementedError()\n\n    def run(\n        self,\n        root_folder: Optional[str] = None,\n        external_checks_dir: Optional[List[str]] = None,\n        files: Optional[List[str]] = None,\n        collect_skip_comments: bool = True,\n        repo_root_for_plan_enrichment: Optional[List[Union[str, os.PathLike]]] = None,\n    ) -> List[Report]:\n        integration_feature_registry.run_pre_runner()\n        if len(self.runners) == 1:\n            reports = [self.runners[0].run(root_folder, external_checks_dir=external_checks_dir, files=files,\n                                           runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments)]\n        else:\n            reports = parallel_runner.run_function(\n                lambda runner: runner.run(root_folder, external_checks_dir=external_checks_dir, files=files,\n                                          runner_filter=self.runner_filter, collect_skip_comments=collect_skip_comments),\n                self.runners, 1)\n\n        for scan_report in reports:\n            self._handle_report(scan_report, repo_root_for_plan_enrichment)\n        return self.scan_reports\n\n    def _handle_report(self, scan_report, repo_root_for_plan_enrichment):\n        integration_feature_registry.run_post_runner(scan_report)\n        if metadata_integration.check_metadata:\n            RunnerRegistry.enrich_report_with_guidelines(scan_report)\n        if repo_root_for_plan_enrichment:\n            enriched_resources = RunnerRegistry.get_enriched_resources(repo_root_for_plan_enrichment)\n            scan_report = Report(\"terraform_plan\").enrich_plan_report(scan_report, enriched_resources)\n            scan_report = Report(\"terraform_plan\").handle_skipped_checks(scan_report, enriched_resources)\n        self.scan_reports.append(scan_report)\n\n    def save_output_to_file(self, file_name: str, data: str, data_format: str) -> None:\n        try:\n            with open(file_name, 'w') as f:\n                f.write(data)\n            logging.info(f\"\\nWrote output in {data_format} format to the file '{file_name}')\")\n        except EnvironmentError:\n            logging.error(f\"\\nAn error occurred while writing {data_format} results to file: {file_name}\", exc_info=True)\n\n    def print_reports(\n        self,\n        scan_reports: List[Report],\n        config: argparse.Namespace,\n        url: Optional[str] = None,\n        created_baseline_path: Optional[str] = None,\n        baseline: Optional[Baseline] = None,\n    ) -> Literal[0, 1]:\n        output_formats = set(config.output)\n\n        if \"cli\" in config.output and not config.quiet:\n            print(f\"{self.banner}\\n\")\n        exit_codes = []\n        cli_reports = []\n        report_jsons = []\n        sarif_reports = []\n        junit_reports = []\n        cyclonedx_reports = []\n        data_outputs = defaultdict(str)\n        for report in scan_reports:\n            if not report.is_empty():\n                if \"json\" in config.output:\n                    report_jsons.append(report.get_dict(is_quiet=config.quiet, url=url))\n                if \"junitxml\" in config.output:\n                    junit_reports.append(report)\n                if \"github_failed_only\" in config.output:\n                    data_outputs[\"github_failed_only\"] += report.print_failed_github_md(use_bc_ids=config.output_bc_ids)\n                if \"sarif\" in config.output:\n                    sarif_reports.append(report)\n                if \"cli\" in config.output:\n                    cli_reports.append(report)\n                if \"cyclonedx\" in config.output:\n                    cyclonedx_reports.append(report)\n            logging.debug(f'Getting exit code for report {report.check_type}')\n            exit_codes.append(report.get_exit_code(config.soft_fail, config.soft_fail_on, config.hard_fail_on))\n\n        if \"cli\" in config.output:\n            cli_output = ''\n            for report in cli_reports:\n                cli_output += report.print_console(\n                    is_quiet=config.quiet,\n                    is_compact=config.compact,\n                    created_baseline_path=created_baseline_path,\n                    baseline=baseline,\n                    use_bc_ids=config.output_bc_ids,\n                )\n            print(cli_output)\n            # Remove colors from the cli output\n            ansi_escape = re.compile(r'(?:\\x1B[@-_]|[\\x80-\\x9F])[0-?]*[ -/]*[@-~]')\n            data_outputs['cli'] = ansi_escape.sub('', cli_output)\n            if url:\n                print(\"More details: {}\".format(url))\n            output_formats.remove(\"cli\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"sarif\" in config.output:\n            master_report = Report(\"merged\")\n            print(self.banner)\n            for report in sarif_reports:\n                print(report.print_console(\n                        is_quiet=config.quiet,\n                        is_compact=config.compact,\n                        created_baseline_path=created_baseline_path,\n                        baseline=baseline,\n                        use_bc_ids=config.output_bc_ids,\n                ))\n                master_report.failed_checks += report.failed_checks\n                master_report.skipped_checks += report.skipped_checks\n            if url:\n                print(\"More details: {}\".format(url))\n            master_report.write_sarif_output(self.tool)\n            data_outputs['sarif'] = json.dumps(master_report.get_sarif_json(self.tool), cls=CustomJSONEncoder)\n            output_formats.remove(\"sarif\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"json\" in config.output:\n            if config.compact and report_jsons:\n                self.strip_code_blocks_from_json(report_jsons)\n            if not report_jsons:\n                print(dumps(Report(None).get_summary(), indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(Report(None).get_summary(), cls=CustomJSONEncoder)\n            elif len(report_jsons) == 1:\n                print(dumps(report_jsons[0], indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(report_jsons[0], cls=CustomJSONEncoder)\n            else:\n                print(dumps(report_jsons, indent=4, cls=CustomJSONEncoder))\n                data_outputs['json'] = json.dumps(report_jsons, cls=CustomJSONEncoder)\n            output_formats.remove(\"json\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"junitxml\" in config.output:\n            properties = Report.create_test_suite_properties_block(config)\n\n            if junit_reports:\n                test_suites = [\n                    report.get_test_suite(properties=properties, use_bc_ids=config.output_bc_ids)\n                    for report in junit_reports\n                ]\n            else:\n                test_suites = [Report(None).get_test_suite(properties=properties)]\n\n            data_outputs['junitxml'] = Report.get_junit_xml_string(test_suites)\n            print(data_outputs['junitxml'])\n\n            output_formats.remove(\"junitxml\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n        if \"cyclonedx\" in config.output:\n            if cyclonedx_reports:\n                # More than one Report - combine Reports first\n                report = Report(None)\n                for r in cyclonedx_reports:\n                    report.passed_checks += r.passed_checks\n                    report.skipped_checks += r.skipped_checks\n                    report.failed_checks += r.failed_checks\n            else:\n                report = cyclonedx_reports[0]\n            cyclonedx_output = ExtXml(bom=report.get_cyclonedx_bom())\n            print(cyclonedx_output.output_as_string())\n            data_outputs['cyclonedx'] = cyclonedx_output.output_as_string()\n            output_formats.remove(\"cyclonedx\")\n            if output_formats:\n                print(OUTPUT_DELIMITER)\n\n        # Save output to file\n        file_names = {'cli': 'results_cli.txt', 'github_failed_only': 'results_github_failed_only.txt', 'sarif': 'results_sarif.sarif',\n                      'json': 'results_json.json', 'junitxml': 'results_junitxml.xml', 'cyclonedx': 'results_cyclonedx.xml'}\n        if config.output_file_path:\n            for output in config.output:\n                self.save_output_to_file(file_name=f'{config.output_file_path}/{file_names[output]}', data=data_outputs[output],\n                                     data_format=output)\n        exit_code = 1 if 1 in exit_codes else 0\n        return exit_code\n\n    def filter_runner_framework(self) -> None:\n        if not self.runner_filter:\n            return\n        if not self.runner_filter.framework:\n            return\n        if \"all\" in self.runner_filter.framework:\n            return\n        self.runners = [runner for runner in self.runners if runner.check_type in self.runner_filter.framework]\n\n    def remove_runner(self, runner: BaseRunner) -> None:\n        if runner in self.runners:\n            self.runners.remove(runner)\n\n    @staticmethod\n    def enrich_report_with_guidelines(scan_report: Report) -> None:\n        for record in itertools.chain(scan_report.failed_checks, scan_report.passed_checks, scan_report.skipped_checks):\n            guideline = metadata_integration.get_guideline(record.check_id)\n            if guideline:\n                record.set_guideline(guideline)\n\n    @staticmethod\n    def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[str, Dict[str, Any]]:\n        repo_definitions = {}\n        for repo_root in repo_roots:\n            tf_definitions = {}\n            parsing_errors = {}\n            Parser().parse_directory(\n                directory=repo_root,  # assume plan file is in the repo-root\n                out_definitions=tf_definitions,\n                out_parsing_errors=parsing_errors,\n            )\n            repo_definitions[repo_root] = {'tf_definitions': tf_definitions, 'parsing_errors': parsing_errors}\n\n        enriched_resources = {}\n        for repo_root, parse_results in repo_definitions.items():\n            for full_file_path, definition in parse_results['tf_definitions'].items():\n                definitions_context = parser_registry.enrich_definitions_context((full_file_path, definition))\n                abs_scanned_file, _ = tf_runner._strip_module_referrer(full_file_path)\n                scanned_file = os.path.relpath(abs_scanned_file, repo_root)\n                for block_type, block_value in definition.items():\n                    if block_type in CHECK_BLOCK_TYPES:\n                        for entity in block_value:\n                            context_parser = parser_registry.context_parsers[block_type]\n                            definition_path = context_parser.get_entity_context_path(entity)\n                            entity_id = \".\".join(definition_path)\n                            entity_context_path = [block_type] + definition_path\n                            entity_context = data_structures_utils.get_inner_dict(\n                                definitions_context[full_file_path], entity_context_path\n                            )\n                            entity_lines_range = [\n                                entity_context.get(\"start_line\"),\n                                entity_context.get(\"end_line\"),\n                            ]\n                            entity_code_lines = entity_context.get(\"code_lines\")\n                            skipped_checks = entity_context.get(\"skipped_checks\")\n                            enriched_resources[entity_id] = {\n                                \"entity_code_lines\": entity_code_lines,\n                                \"entity_lines_range\": entity_lines_range,\n                                \"scanned_file\": scanned_file,\n                                \"skipped_checks\": skipped_checks,\n                            }\n        return enriched_resources\n\n    @staticmethod\n    def strip_code_blocks_from_json(report_jsons: List[Dict[str, Any]]) -> None:\n        for report in report_jsons:\n            results = report.get('results', {})\n            for key, result in results.items():\n                for result_dict in result:\n                    result_dict.pop('code_block', None)\n                    result_dict.pop('connected_node', None)\n", "path": "checkov/common/runners/runner_registry.py"}]}