Repository: bridgecrewio/checkov
Pull request: removed code blocks in compact json output
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

resolves #2713 


Problem statement:
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.

Hints from issue discussion:

Commit message: removed code blocks in compact json output

Patch to review:
diff --git a/checkov/common/runners/runner_registry.py b/checkov/common/runners/runner_registry.py
index 429889e6c9..6884bfe6ed 100644
--- a/checkov/common/runners/runner_registry.py
+++ b/checkov/common/runners/runner_registry.py
@@ -165,6 +165,8 @@ def print_reports(
             if output_formats:
                 print(OUTPUT_DELIMITER)
         if "json" in config.output:
+            if config.compact and report_jsons:
+                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,13 @@ def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[st
                                 "skipped_checks": skipped_checks,
                             }
         return enriched_resources
+
+    @staticmethod
+    def strip_code_blocks_from_json(report_jsons):
+        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)
+        return report_jsons


Code review comments:
diff_hunk: @@ -283,3 +285,13 @@ def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[st
                                 "skipped_checks": skipped_checks,
                             }
         return enriched_resources
+
+    @staticmethod
+    def strip_code_blocks_from_json(report_jsons):
+        for report in report_jsons:
+            results = report.get('results', [])
path: checkov/common/runners/runner_registry.py
text: @user1:
it seems that at the next line you expect "results" as dict.
maybe you meant: 
`results = report.get('results', dict())`
?

@user2:
I think Itai is right 👍 but better to use
```python
results = report.get('results', {})
```

diff_hunk: @@ -283,3 +285,13 @@ def get_enriched_resources(repo_roots: List[Union[str, os.PathLike]]) -> Dict[st
                                 "skipped_checks": skipped_checks,
                             }
         return enriched_resources
+
+    @staticmethod
+    def strip_code_blocks_from_json(report_jsons):
path: checkov/common/runners/runner_registry.py
text: @user1:
```suggestion
    def strip_code_blocks_from_json(report_jsons: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
```
this method is actually non-idempotent, therefore it doesn't need to return the `report_jsons` they will be changed in-place, because `dict` in Python is a mutable object.
If you decide to remove the return statement then the type hints will be
```python
def strip_code_blocks_from_json(report_jsons: List[Dict[str, Any]]) -> None:
```

@author:
Thanks for clarifying this point