"""Translate Checkov JSON output to ACDL PolicyCheckResult records. Reads Checkov's JSON output (one framework key, e.g. terraform_plan), emits a list of PolicyCheckResult dicts conforming to schemas/policy_check_result.schema.json. Run Checkov with --soft-fail so Checkov never exits non-zero; the confidence signal decides the gate, not Checkov's exit code. Spike scope (D-043): tag/naming is a single SKIPPED record. A custom Checkov YAML rule for tag presence lands in v1.2. """ import datetime import json import sys RULE_MAP = { "CKV_AWS_41": ("secrets-in-plaintext", "high"), "CKV_AWS_45": ("secrets-in-plaintext", "high"), "CKV_AWS_46": ("secrets-in-plaintext", "high"), "CKV_AWS_20": ("public-ingress", "high"), "CKV_AWS_57": ("public-ingress", "high"), "CKV_AWS_24": ("public-ingress", "medium"), "CKV_AWS_25": ("public-ingress", "medium"), "CKV_AWS_1": ("iam-wildcard", "high"), "CKV_AWS_40": ("iam-wildcard", "medium"), "CKV_AWS_7": ("kms-key-reference", "medium"), "CKV_AWS_33": ("kms-key-reference", "medium"), } _RESULT_MAP = {"PASSED": "pass", "FAILED": "fail", "SKIPPED": "skipped"} def _iso8601_now(): return datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") def _to_pcr(checkov_record, contract_id, result_str): check_id = checkov_record.get("check_id", "") default_sev = RULE_MAP.get(check_id, (check_id, "info"))[1] severity = checkov_record.get("severity", default_sev) if isinstance(severity, str): severity = severity.lower() return { "contractId": contract_id, "evaluatedAt": _iso8601_now(), "engine": "checkov", "ruleId": check_id, "severity": severity, "result": _RESULT_MAP.get(result_str, "error"), "message": checkov_record.get("check_name", ""), "evidence": { "file_path": checkov_record.get("file_path"), "resource": checkov_record.get("resource"), "resource_address": checkov_record.get("resource_address"), "code_block": checkov_record.get("code_block"), }, "resourceRef": checkov_record.get("resource_address") or checkov_record.get("resource", ""), } def _emit_tag_naming_skipped(contract_id): return { "contractId": contract_id, "evaluatedAt": _iso8601_now(), "engine": "checkov", "ruleId": "ACDL_TAG_NAMING", "severity": "info", "result": "skipped", "message": "tag/naming check deferred to v1.2 (D-043)", "evidence": {}, "resourceRef": "", } def adapt(checkov_json_path, contract_id): with open(checkov_json_path, "r", encoding="utf-8") as fh: data = json.load(fh) out = [] for framework, body in data.items(): results = body.get("results", body) if isinstance(body, dict) else {} if not isinstance(results, dict): continue for rec in results.get("passed_checks", []): out.append(_to_pcr(rec, contract_id, "PASSED")) for rec in results.get("failed_checks", []): out.append(_to_pcr(rec, contract_id, "FAILED")) for rec in results.get("skipped_checks", []): out.append(_to_pcr(rec, contract_id, "SKIPPED")) out.append(_emit_tag_naming_skipped(contract_id)) return out if __name__ == "__main__": if len(sys.argv) != 3: print("usage: checkov_adapter.py ", file=sys.stderr) sys.exit(2) print(json.dumps(adapt(sys.argv[1], sys.argv[2]), indent=2))