Skip to content

JSON Output from Custom Checks #7296

@msweikata-jha

Description

@msweikata-jha

Describe the issue
When creating a custom check, some of the attributes set in the YAML or the Python don't appear in the output, and it's different for each depending on the method of defined custom policy.

The example below is purely for PoC'ing the efforts, I don't actually want to check this string length :)

I have a simple Terraform Plan JSON:

{
    "format_version": "1.2",
    "terraform_version": "1.5.7",
    "planned_values": {
        "root_module": {
            "resources": [
                {
                    "address": "random_string.name",
                    "mode": "managed",
                    "type": "random_string",
                    "name": "name",
                    "provider_name": "registry.terraform.io/hashicorp/random",
                    "schema_version": 2,
                    "values": {
                        "keepers": null,
                        "length": 8,
                        "lower": true,
                        "min_lower": 0,
                        "min_numeric": 0,
                        "min_special": 0,
                        "min_upper": 0,
                        "number": true,
                        "numeric": true,
                        "override_special": null,
                        "special": false,
                        "upper": true
                    },
                    "sensitive_values": {}
                }
            ]
        }
    },
    "resource_changes": [
        {
            "address": "random_string.name",
            "mode": "managed",
            "type": "random_string",
            "name": "name",
            "provider_name": "registry.terraform.io/hashicorp/random",
            "change": {
                "actions": [
                    "create"
                ],
                "before": null,
                "after": {
                    "keepers": null,
                    "length": 8,
                    "lower": true,
                    "min_lower": 0,
                    "min_numeric": 0,
                    "min_special": 0,
                    "min_upper": 0,
                    "number": true,
                    "numeric": true,
                    "override_special": null,
                    "special": false,
                    "upper": true
                },
                "after_unknown": {
                    "id": true,
                    "result": true
                },
                "before_sensitive": false,
                "after_sensitive": {}
            }
        }
    ],
    "configuration": {
        "provider_config": {
            "random": {
                "name": "random",
                "full_name": "registry.terraform.io/hashicorp/random"
            }
        },
        "root_module": {
            "resources": [
                {
                    "address": "random_string.name",
                    "mode": "managed",
                    "type": "random_string",
                    "name": "name",
                    "provider_config_key": "random",
                    "expressions": {
                        "length": {
                            "constant_value": 8
                        },
                        "special": {
                            "constant_value": false
                        }
                    },
                    "schema_version": 2
                }
            ]
        }
    },
    "timestamp": "2025-09-03T19:38:32Z"
}

When I provide this yaml custom policy:

metadata:
  name: "Random String Length > 5 YML"
  id: "CKV_random_odyssey_1"
  category: "NETWORKING"
  description: "Ensure random_string resource length is not greater than 5 FROM YML."
  severity: "HIGH"

definition:
  cond_type: "attribute"
  resource_types:
    - "random_string"
  attribute: "length"
  operator: "less_than"
  value: 5

And this python test:

from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck

class RandomStringLengthCheck(BaseResourceCheck):
    def __init__(self):
        name = "Random String Length > 5"
        id = "CKV_random_odyssey_1"
        categories = (CheckCategories.NETWORKING,)
        supported_resources = ["random_string"]
        guideline = "Testing"
        
        super().__init__(name=name, id=id, categories=categories, supported_resources=supported_resources, guideline=guideline)
        

    def scan_resource_conf(self, conf):
        length = conf.get("length")
        self.details.append("Ensure random_string resource length is not greater than 5.")
        if isinstance(length, list):
            length = length[0]
        if length is not None and int(length) > 5:
            return CheckResult.FAILED
        return CheckResult.PASSED

check = RandomStringLengthCheck()

I also have the necessary __init__.py file in the directory as outlined in the codebase.

My JSON output for the command is this (I omitted the code block because omg lines):

{
    "check_type": "terraform_plan",
    "results": {
        "passed_checks": [],
        "failed_checks": [
            {
                "check_id": "CKV_random_odyssey_1",
                "bc_check_id": null,
                "check_name": "Random String Length > 5",
                "check_result": {
                    "result": "FAILED",
                    "evaluated_keys": []
                },
                
                "file_path": "/input.json",
                "file_abs_path": "/Users/mikesweikata/Documents/repositories/iac-policy/input.json",
                "repo_file_path": "/input.json",
                "file_line_range": [
                    13,
                    26
                ],
                "resource": "random_string.name",
                "evaluations": null,
                "check_class": "custompy",
                "fixed_definition": null,
                "entity_tags": null,
                "caller_file_path": null,
                "caller_file_line_range": null,
                "resource_address": "random_string.name",
                "severity": null,
                "bc_category": null,
                "benchmarks": null,
                "description": null,
                "short_description": null,
                "vulnerability_details": null,
                "connected_node": null,
                "guideline": "Testing",
                "details": [
                    "Ensure random_string resource length is not greater than 5."
                ],
                "check_len": null,
                "definition_context_file_path": null
            },
            {
                "check_id": "CKV_random_odyssey_1",
                "bc_check_id": null,
                "check_name": "Random String Length > 5 YML",
                "check_result": {
                    "result": "FAILED",
                    "entity": {
                        "random_string": {
                            "name": {
                                "keepers": [
                                    null
                                ],
                                "length": [
                                    8
                                ],
                                "lower": [
                                    true
                                ],
                                "min_lower": [
                                    0
                                ],
                                "min_numeric": [
                                    0
                                ],
                                "min_special": [
                                    0
                                ],
                                "min_upper": [
                                    0
                                ],
                                "number": [
                                    true
                                ],
                                "numeric": [
                                    true
                                ],
                                "override_special": [
                                    null
                                ],
                                "special": [
                                    false
                                ],
                                "upper": [
                                    true
                                ],
                                "__file__": [
                                    "/Users/mikesweikata/Documents/repositories/iac-policy/input.json"
                                ],
                                "__startline__": [
                                    14
                                ],
                                "__endline__": [
                                    27
                                ],
                                "start_line": [
                                    13
                                ],
                                "end_line": [
                                    26
                                ],
                                "__address__": "random_string.name",
                                "__change_actions__": [
                                    "create"
                                ],
                                "__change_keys__": []
                            }
                        }
                    },
                    "evaluated_keys": [
                        "length"
                    ]
                },
                "file_path": "/input.json",
                "file_abs_path": "/Users/mikesweikata/Documents/repositories/iac-policy/input.json",
                "repo_file_path": "/input.json",
                "file_line_range": [
                    13,
                    26
                ],
                "resource": "random_string.name",
                "evaluations": null,
                "check_class": "checkov.common.graph.checks_infra.base_check",
                "fixed_definition": null,
                "entity_tags": {},
                "caller_file_path": null,
                "caller_file_line_range": null,
                "resource_address": "random_string.name",
                "severity": "HIGH",
                "bc_category": null,
                "benchmarks": {},
                "description": null,
                "short_description": null,
                "vulnerability_details": null,
                "connected_node": null,
                "guideline": null,
                "details": [],
                "check_len": null,
                "definition_context_file_path": "/Users/mikesweikata/Documents/repositories/iac-policy/input.json"
            }
        ],
        "skipped_checks": [],
        "parsing_errors": []
    },
    "summary": {
        "passed": 0,
        "failed": 2,
        "skipped": 0,
        "parsing_errors": 0,
        "resource_count": 1,
        "checkov_version": "3.2.450"
    },
    "url": "Add an api key '--bc-api-key <api-key>' to see more detailed insights via https://bridgecrew.cloud"
}

Some of the key attributes between the two outputs are missing. For example, for the YML based policy, I get severity, but in the Python I don't even though it's set in both. And both outputs are missing the ClassCategories in the output.

Is this a feature break that's needed in the higher tier? Or am I missing something?

I know it's working on ingestion because if I set the attribute incorrectly, checkov will fail to run.

Additional context

Installed view Brew on an M4 MacBook.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions