Repository: bridgecrewio/checkov

Issue:
CKV_AWS_40: failure even when not setting users
**Describe the issue**
The check fails when executing checkov on Terraform plan's JSON output.

**Examples**
```
resource "aws_iam_policy_attachment" "attachment" {
  ...
  roles = [...]
  # no users
}
```
JSON:
```
{
  "address": "aws_iam_policy_attachment.attachment",
  ...
  "values": {
    ...
    "roles": [
      "data-analytics@eng-0"
    ],
    "users": []
  },
...
```
The `users` field is set to `[]` in JSON, and the [check implementation](https://github.com/bridgecrewio/checkov/blob/e2538c48df14363d6ed46e5b838e19cc71ba6cbf/checkov/terraform/checks/resource/base_resource_negative_value_check.py#L39-L53) doesn't handle this scenario correctly:

https://github.com/bridgecrewio/checkov/blob/e2538c48df14363d6ed46e5b838e19cc71ba6cbf/checkov/terraform/checks/resource/base_resource_negative_value_check.py#L39-L53

**Version (please complete the following information):**
```
> checkov --version
2.0.780
```

I saw there are tests for the check implementation, but only targeting Terraform source files. Are there tests targeting JSON output from Terraform plan?


Discussion:
hi @paulolieuthier thanks for raising this issue, I fixed that for other tests, but didn't expect it was an issue here too. A new version with the fix should be out by tomorrow.

Resolving patch:
diff --git a/checkov/terraform/checks/resource/base_resource_negative_value_check.py b/checkov/terraform/checks/resource/base_resource_negative_value_check.py
--- a/checkov/terraform/checks/resource/base_resource_negative_value_check.py
+++ b/checkov/terraform/checks/resource/base_resource_negative_value_check.py
@@ -42,11 +42,11 @@ def scan_resource_conf(self, conf: Dict[str, List[Any]]) -> CheckResult:
             value = dpath.get(conf, inspected_key)
             if isinstance(value, list) and len(value) == 1:
                 value = value[0]
+            if value is None or (isinstance(value, list) and not value):
+                return self.missing_attribute_result
             if get_referenced_vertices_in_value(value=value, aliases={}, resources_types=[]):
                 # we don't provide resources_types as we want to stay provider agnostic
                 return CheckResult.UNKNOWN
-            if value is None:
-                return self.missing_attribute_result
             if value in bad_values or ANY_VALUE in bad_values:
                 return CheckResult.FAILED
             else:


Test patch:
diff --git a/tests/terraform/checks/resource/aws/example_IAMPolicyAttachedToGroupOrRoles/iam.tf b/tests/terraform/checks/resource/aws/example_IAMPolicyAttachedToGroupOrRoles/iam.tf
--- a/tests/terraform/checks/resource/aws/example_IAMPolicyAttachedToGroupOrRoles/iam.tf
+++ b/tests/terraform/checks/resource/aws/example_IAMPolicyAttachedToGroupOrRoles/iam.tf
@@ -12,6 +12,13 @@ resource "aws_iam_policy_attachment" "null" {
   users = null
 }
 
+resource "aws_iam_policy_attachment" "empty" {
+  name       = "example"
+  policy_arn = "aws_iam_policy.policy.arn"
+
+  users = []
+}
+
 # fail
 
 resource "aws_iam_policy_attachment" "fail" {
diff --git a/tests/terraform/checks/resource/aws/test_IAMPolicyAttachedToGroupOrRoles.py b/tests/terraform/checks/resource/aws/test_IAMPolicyAttachedToGroupOrRoles.py
--- a/tests/terraform/checks/resource/aws/test_IAMPolicyAttachedToGroupOrRoles.py
+++ b/tests/terraform/checks/resource/aws/test_IAMPolicyAttachedToGroupOrRoles.py
@@ -20,6 +20,7 @@ def test(self):
         passing_resources = {
             "aws_iam_policy_attachment.pass",
             "aws_iam_policy_attachment.null",
+            "aws_iam_policy_attachment.empty",
         }
         failing_resources = {
             "aws_iam_policy_attachment.fail",
@@ -30,7 +31,7 @@ def test(self):
         passed_check_resources = {c.resource for c in report.passed_checks}
         failed_check_resources = {c.resource for c in report.failed_checks}
 
-        self.assertEqual(summary["passed"], 2)
+        self.assertEqual(summary["passed"], 3)
         self.assertEqual(summary["failed"], 3)
         self.assertEqual(summary["skipped"], 0)
         self.assertEqual(summary["parsing_errors"], 0)