Repository: bridgecrewio/checkov

Issue:
Parsing error scanning terraform file with "[*]"
**Describe the bug**
Receiving the error "Error parsing file c:\Users\BE53599\Documents\GitHub\cto_awsdocs\examples\hig_tfe_rhel7_ec2_server_fleet\dev\output.tf" when scanning a file of terraform code in Checkov that contains the string "[*]" (without quotes). We use the [*] token in Ansible for post-provisioning configuration management. Removing the [*] string allows the file to be scanned without error. Checkov is not scanning the entire directory where a file with the [*] string is contained. 

**To Reproduce**
Steps to reproduce the behavior:
1. Go to directory with file of terraform code containing [*] token
2. Run cli command  'checkov -f output.tf'
3. See error

**Expected behavior**
Checkov should scan files that contain [*] without generating a parsing error and generate accurate results. 

**Screenshots**
If applicable, add screenshots to help explain your problem.
![image](https://user-images.githubusercontent.com/92762953/137820719-c2fdf62a-6baa-44be-92f2-14c445644796.png)
![image](https://user-images.githubusercontent.com/92762953/137820734-b9b970bd-5cda-4a53-9a89-45ef8cf56fe0.png)
![image](https://user-images.githubusercontent.com/92762953/137820755-8227b641-be72-4834-b899-98b9657b7a41.png)


**Desktop (please complete the following information):**
 - OS: Windows 10
 - Checkov Version 2.0.495

**Additional context**
Add any other context about the problem here (e.g. code snippets).



Discussion:
Hey @benglerHIG, I tested this out and found that if I scan a directory with a file that has a splat expression `[*]`, the scanning works (you're probably not seeing results from the output.tf file in the last screenshot since there might not be any findings). See the example below:

```
❯ ccat test.tf
resource "aws_elb" "learn" {
  instances                   = aws_instance.ubuntu[*].id
  idle_timeout                = 400
  connection_draining         = true
  connection_draining_timeout = 400
  tags                        = local.common_tags
}

resource "aws_elb" "learn2" {
  instances                   = flatten(aws_instance.ubuntu[*].id)
  idle_timeout                = 400
  connection_draining         = true
  connection_draining_timeout = 400
  tags                        = local.common_tags
}
❯ checkov -d .

       _               _
   ___| |__   ___  ___| | _______   __
  / __| '_ \ / _ \/ __| |/ / _ \ \ / /
 | (__| | | |  __/ (__|   < (_) \ V /
  \___|_| |_|\___|\___|_|\_\___/ \_/

By bridgecrew.io | version: 2.0.495

terraform scan results:

Passed checks: 4, Failed checks: 2, Skipped checks: 0

Check: CKV_AWS_127: "Ensure that Elastic Load Balancer(s) uses SSL certificates provided by AWS Certificate Manager"
	PASSED for resource: aws_elb.learn
	File: /test.tf:1-7
	Guide: https://docs.bridgecrew.io/docs/ensure-that-elastic-load-balancers-uses-ssl-certificates-provided-by-aws-certificate-manager

Check: CKV_AWS_138: "Ensure that ELB is cross-zone-load-balancing enabled"
	PASSED for resource: aws_elb.learn
	File: /test.tf:1-7
	Guide: https://docs.bridgecrew.io/docs/ensure-that-elb-is-cross-zone-load-balancing-enabled

Check: CKV_AWS_127: "Ensure that Elastic Load Balancer(s) uses SSL certificates provided by AWS Certificate Manager"
	PASSED for resource: aws_elb.learn2
	File: /test.tf:9-15
	Guide: https://docs.bridgecrew.io/docs/ensure-that-elastic-load-balancers-uses-ssl-certificates-provided-by-aws-certificate-manager

Check: CKV_AWS_138: "Ensure that ELB is cross-zone-load-balancing enabled"
	PASSED for resource: aws_elb.learn2
	File: /test.tf:9-15
	Guide: https://docs.bridgecrew.io/docs/ensure-that-elb-is-cross-zone-load-balancing-enabled

Check: CKV_AWS_92: "Ensure the ELB has access logging enabled"
	FAILED for resource: aws_elb.learn
	File: /test.tf:1-7
	Guide: https://docs.bridgecrew.io/docs/bc_aws_logging_23

		1 | resource "aws_elb" "learn" {
		2 |   instances                   = aws_instance.ubuntu[*].id
		3 |   idle_timeout                = 400
		4 |   connection_draining         = true
		5 |   connection_draining_timeout = 400
		6 |   tags                        = local.common_tags
		7 | }


Check: CKV_AWS_92: "Ensure the ELB has access logging enabled"
	FAILED for resource: aws_elb.learn2
	File: /test.tf:9-15
	Guide: https://docs.bridgecrew.io/docs/bc_aws_logging_23

		9  | resource "aws_elb" "learn2" {
		10 |   instances                   = flatten(aws_instance.ubuntu[*].id)
		11 |   idle_timeout                = 400
		12 |   connection_draining         = true
		13 |   connection_draining_timeout = 400
		14 |   tags                        = local.common_tags
		15 | }
```

That said if a file is scanned using the `-f` flag, scanning is failing. I think that's the problem here. I'll take a look at this further. 

@benglerHIG can you share the logs from the VSCode extension too? You can view the log by running the "Open Checkov Log" VSCode command. 




Resolving patch:
diff --git a/checkov/terraform/parser.py b/checkov/terraform/parser.py
--- a/checkov/terraform/parser.py
+++ b/checkov/terraform/parser.py
@@ -109,10 +109,13 @@ def parse_directory(self, directory: str, out_definitions: Optional[Dict],
         default_ml_registry.external_modules_folder_name = external_modules_download_path
         self._parse_directory(dir_filter=lambda d: self._check_process_dir(d), vars_files=vars_files)
 
-    @staticmethod
-    def parse_file(file: str, parsing_errors: Dict[str, Exception] = None, scan_hcl = False) -> Optional[Dict]:
+    def parse_file(self, file: str, parsing_errors: Dict[str, Exception] = None, scan_hcl = False) -> Optional[Dict]:
         if file.endswith(".tf") or file.endswith(".tf.json") or (scan_hcl and file.endswith(".hcl")):
-            return _load_or_die_quietly(Path(file), parsing_errors)
+            parse_result = _load_or_die_quietly(Path(file), parsing_errors)
+            if parse_result:
+                parse_result = self._serialize_definitions(parse_result)
+                parse_result = self._clean_parser_types(parse_result)
+                return parse_result
         else:
             return None
 


Test patch:
diff --git a/tests/terraform/parser/resources/parse_file_vs_dir/main.tf b/tests/terraform/parser/resources/parse_file_vs_dir/main.tf
new file mode 100644
--- /dev/null
+++ b/tests/terraform/parser/resources/parse_file_vs_dir/main.tf
@@ -0,0 +1,40 @@
+# Do not add more files to this directory.
+
+resource "aws_elb" "learn" {
+  instances = aws_instance.ubuntu[*].id
+  idle_timeout                = 400
+  connection_draining         = true
+  connection_draining_timeout = 400
+  listener {
+    instance_port     = 0
+    instance_protocol = ""
+    lb_port           = 0
+    lb_protocol       = ""
+  }
+}
+
+resource "aws_elb" "learn1" {
+  instances = aws_instance.ubuntu[*].id
+  idle_timeout                = 400
+  connection_draining         = true
+  connection_draining_timeout = 400
+  listener {
+    instance_port     = 0
+    instance_protocol = ""
+    lb_port           = 0
+    lb_protocol       = ""
+  }
+}
+
+resource "aws_elb" "learn2" {
+  instances = aws_instance.ubuntu[*].id
+  idle_timeout                = 400
+  connection_draining         = true
+  connection_draining_timeout = 400
+  listener {
+    instance_port     = 0
+    instance_protocol = ""
+    lb_port           = 0
+    lb_protocol       = ""
+  }
+}
diff --git a/tests/terraform/parser/test_hcl2_load_assumptions.py b/tests/terraform/parser/test_hcl2_load_assumptions.py
--- a/tests/terraform/parser/test_hcl2_load_assumptions.py
+++ b/tests/terraform/parser/test_hcl2_load_assumptions.py
@@ -293,3 +293,10 @@ def test_weird_ternary_string_clipping(self):
             #                      missing quotes on outer tokens :-(
         }
         self.go(tf, expect)
+
+    def test_splat_expression(self):
+        tf = 'instances = flatten(aws_instance.ubuntu[*].id)'
+        expect = {
+            'instances': ["${flatten(Tree('full_splat_expr_term', ['aws_instance.ubuntu', 'id']))}"]
+        }
+        self.go(tf, expect)
diff --git a/tests/terraform/parser/test_parse_file_vs_dir.py b/tests/terraform/parser/test_parse_file_vs_dir.py
new file mode 100644
--- /dev/null
+++ b/tests/terraform/parser/test_parse_file_vs_dir.py
@@ -0,0 +1,20 @@
+import os
+import unittest
+
+from checkov.terraform.parser import Parser
+
+
+class TestFileVsDirParser(unittest.TestCase):
+
+    def test_file_dir_parser_results_match(self):
+        parser = Parser()
+        current_dir = os.path.dirname(os.path.realpath(__file__))
+        file_path = current_dir + '/resources/parse_file_vs_dir/main.tf'
+        dir_path = current_dir + '/resources/parse_file_vs_dir'
+        tf_definitions_file = parser.parse_file(file_path)
+        _, tf_definitions_dir = parser.parse_hcl_module(dir_path, 'terraform')
+        self.assertDictEqual(tf_definitions_file, tf_definitions_dir.get(list(tf_definitions_dir.keys())[0]))
+
+
+if __name__ == '__main__':
+    unittest.main()