fix(terraform): ensure consistent JSON output format when no checks are evaluated#7472
fix(terraform): ensure consistent JSON output format when no checks are evaluated#7472daily-dreamer wants to merge 3 commits intobridgecrewio:mainfrom
Conversation
hanges: - Modified runner_registry.py line 535 to use Report.get_dict() instead of Report.get_summary() - Ensures consistent JSON structure across all scenarios (empty results, file not found, no matches) Impact: - API consumers no longer need special handling for empty results - JSON output structure is now consistent regardless of check evaluation status - Maintains backward compatibility by keeping summary data within the response Fixes: Inconsistent JSON output format when no checks are evaluated
Test Scenarios for JSON Output Format FixPrerequisites# Install checkov (if not already installed)
pip install checkov
# Or install from your fork for testing
cd /path/to/your/fork/checkov
pip install -e .Test Scenario 1: Empty Directory (Nothing to Scan)PurposeVerify that when scanning an empty directory, Checkov returns a consistent JSON structure. Setup# Create a clean test directory
mkdir -p /tmp/checkov-test-empty
cd /tmp/checkov-test-empty
# Ensure it's completely empty
rm -rf *
ls -la # Should show only . and ..Test Commandcheckov -d /tmp/checkov-test-empty --output jsonExpected Behavior BEFORE Fix{
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
}❌ Problem: Only summary object, missing Expected Behavior AFTER Fix{
"check_type": "terraform",
"results": {
"passed_checks": [],
"failed_checks": [],
"skipped_checks": [],
"parsing_errors": []
},
"summary": {
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
},
"url": "https://www.checkov.io/"
}✅ Fixed: Full JSON structure with all expected fields. Verification# Save output to file
checkov -d /tmp/checkov-test-empty --output json > /tmp/output1.json
# Check if it has the 'check_type' field (should exist after fix)
cat /tmp/output1.json | grep -q "check_type" && echo "✅ PASS: Full structure" || echo "❌ FAIL: Summary only"
# Check if it has the 'results' field (should exist after fix)
cat /tmp/output1.json | grep -q "results" && echo "✅ PASS: Has results field" || echo "❌ FAIL: Missing results"
# Check if it has the 'summary' field (should exist after fix)
cat /tmp/output1.json | grep -q "summary" && echo "✅ PASS: Has summary field" || echo "❌ FAIL: Missing summary"Test Scenario 2: File Not PresentPurposeVerify that when scanning a non-existent file, Checkov returns a consistent JSON structure. Setup# Ensure the file doesn't exist
rm -f /tmp/nonexistent-file.tf
ls /tmp/nonexistent-file.tf # Should show "No such file or directory"Test Commandcheckov -f /tmp/nonexistent-file.tf --output json 2>/dev/nullExpected Behavior BEFORE Fix{
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
}❌ Problem: Only summary object. Expected Behavior AFTER Fix{
"check_type": "terraform",
"results": {
"passed_checks": [],
"failed_checks": [],
"skipped_checks": [],
"parsing_errors": []
},
"summary": {
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
},
"url": "https://www.checkov.io/"
}✅ Fixed: Full JSON structure. Verification# Save output to file (suppress stderr)
checkov -f /tmp/nonexistent-file.tf --output json 2>/dev/null > /tmp/output2.json
# Verify structure
cat /tmp/output2.json | python3 -c "
import json, sys
data = json.load(sys.stdin)
assert 'check_type' in data, 'Missing check_type'
assert 'results' in data, 'Missing results'
assert 'summary' in data, 'Missing summary'
print('✅ PASS: All required fields present')
"Test Scenario 3: File with No Scannable ResourcesPurposeVerify that when scanning a file with no recognizable resources, Checkov returns a consistent JSON structure. Setup# Create a file with only comments (no resources)
cat > /tmp/empty-content.tf << 'EOF'
# This is just a comment file
# No actual Terraform resources here
# Another comment
# Still no resources
EOFTest Commandcheckov -f /tmp/empty-content.tf --output jsonExpected Behavior BEFORE Fix{
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
}❌ Problem: Only summary object. Expected Behavior AFTER Fix{
"check_type": "terraform",
"results": {
"passed_checks": [],
"failed_checks": [],
"skipped_checks": [],
"parsing_errors": []
},
"summary": {
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
},
"url": "https://www.checkov.io/"
}✅ Fixed: Full JSON structure. Verification# Save output to file
checkov -f /tmp/empty-content.tf --output json > /tmp/output3.json
# Verify using jq (if available)
if command -v jq &> /dev/null; then
echo "Checking with jq..."
jq -e '.check_type' /tmp/output3.json && echo "✅ Has check_type"
jq -e '.results' /tmp/output3.json && echo "✅ Has results"
jq -e '.summary' /tmp/output3.json && echo "✅ Has summary"
else
echo "Checking with grep..."
grep -q "check_type" /tmp/output3.json && echo "✅ Has check_type"
grep -q "results" /tmp/output3.json && echo "✅ Has results"
grep -q "summary" /tmp/output3.json && echo "✅ Has summary"
fiTest Scenario 4: Comparison with Normal Scan (Control Test)PurposeVerify that the fix doesn't break normal scanning behavior when resources ARE found. Setup# Create a valid Terraform file with a resource
cat > /tmp/valid-resource.tf << 'EOF'
resource "aws_s3_bucket" "example" {
bucket = "my-test-bucket"
tags = {
Name = "My bucket"
Environment = "Dev"
}
}
EOFTest Commandcheckov -f /tmp/valid-resource.tf --output jsonExpected Behavior (BEFORE and AFTER Fix - Should be Same){
"check_type": "terraform",
"results": {
"passed_checks": [
{
"check_id": "CKV_AWS_...",
"check_name": "...",
"check_result": {
"result": "passed"
},
"file_path": "/tmp/valid-resource.tf",
"resource": "aws_s3_bucket.example"
}
],
"failed_checks": [
{
"check_id": "CKV_AWS_...",
"check_name": "...",
"check_result": {
"result": "failed"
},
"file_path": "/tmp/valid-resource.tf",
"resource": "aws_s3_bucket.example"
}
],
"skipped_checks": [],
"parsing_errors": []
},
"summary": {
"passed": 5,
"failed": 10,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 1,
"checkov_version": "3.2.509"
},
"url": "https://www.checkov.io/"
}✅ Expected: Normal scans should work exactly as before. Verification# Save output
checkov -f /tmp/valid-resource.tf --output json > /tmp/output4.json
# Verify it has the full structure
python3 << 'PYTHON'
import json
with open('/tmp/output4.json') as f:
data = json.load(f)
# Check structure
assert 'check_type' in data, "Missing check_type"
assert 'results' in data, "Missing results"
assert 'summary' in data, "Missing summary"
# Check that checks were actually run
summary = data['summary']
total_checks = summary['passed'] + summary['failed'] + summary['skipped']
assert total_checks > 0, "No checks were run!"
print(f"✅ PASS: Normal scan works correctly")
print(f" - Passed: {summary['passed']}")
print(f" - Failed: {summary['failed']}")
print(f" - Skipped: {summary['skipped']}")
print(f" - Total checks: {total_checks}")
PYTHONTest Scenario 5: Multiple Frameworks (Comprehensive Test)PurposeVerify the fix works across different framework types (Terraform, Kubernetes, etc.). Setup# Create test directory
mkdir -p /tmp/checkov-multi-framework-test
# Create empty Kubernetes file
cat > /tmp/checkov-multi-framework-test/empty.yaml << 'EOF'
# Just comments
# No actual Kubernetes resources
EOF
# Create empty Dockerfile
cat > /tmp/checkov-multi-framework-test/Dockerfile << 'EOF'
# Empty Dockerfile
# No actual instructions
EOFTest Commands# Test Kubernetes framework
checkov -f /tmp/checkov-multi-framework-test/empty.yaml --framework kubernetes --output json > /tmp/output5-k8s.json
# Test Dockerfile framework
checkov -f /tmp/checkov-multi-framework-test/Dockerfile --framework dockerfile --output json > /tmp/output5-docker.jsonExpected Behavior AFTER FixBoth outputs should have full JSON structure: {
"check_type": "kubernetes", // or "dockerfile"
"results": {
"passed_checks": [],
"failed_checks": [],
"skipped_checks": [],
"parsing_errors": []
},
"summary": {
"passed": 0,
"failed": 0,
"skipped": 0,
"parsing_errors": 0,
"resource_count": 0,
"checkov_version": "3.2.509"
},
"url": "https://www.checkov.io/"
}Verification# Verify both outputs
for file in /tmp/output5-k8s.json /tmp/output5-docker.json; do
echo "Checking $file..."
python3 << PYTHON
import json
with open('$file') as f:
data = json.load(f)
assert 'check_type' in data, "Missing check_type in $file"
assert 'results' in data, "Missing results in $file"
assert 'summary' in data, "Missing summary in $file"
print(f"✅ PASS: $file has correct structure")
PYTHON
doneManual Verification ChecklistUse this checklist to manually verify the fix:
Expected Test ResultsBEFORE Fix AppliedAFTER Fix AppliedTroubleshootingIssue: Tests still failing after applying fixSolution:
Issue: Cannot find checkov commandSolution: # Install from your fork
cd /path/to/your/fork/checkov
pip install -e .
# Verify installation
which checkov
checkov --versionIssue: JSON output is malformedSolution:
|
|
Hi maintainers! 👋 I've implemented a fix for JSON output format consistency. This PR includes:
The fix ensures empty reports return the same JSON structure as non-empty reports, making it easier for tools to parse Checkov output. |
Changes:
Impact:
Fixes: Inconsistent JSON output format when no checks are evaluated
*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
PR Title: docs(general): add documentation for nominal success JSON output
Description
This PR adds a new documentation file
JSON_SUMMARY_README.mdthat clarifies the JSON output format when Checkov runs but evaluates zero checks (Nominal Success).Motivation and Context
Users were confused about the difference between a "successful" scan that returns a full JSON vs one that returns only a summary dictionary.
passed: 0andfailed: 0(e.g., file not found, no scannable resources, or no check matches).passed > 0.This documentation helps developers understand and parse the JSON output correctly by accounting for the "Empty Report" edge case.
Checklist: