Add checkov linter for cloudformation

Co-Authored-By: jhandsel <64368631+jhandsel@users.noreply.github.com>
This commit is contained in:
w0rp
2025-08-14 17:33:36 +01:00
parent 37e64b5caf
commit 3539f39d4d
7 changed files with 191 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
" Author: J. Handsel <jennpbc@posteo.net>, Thyme-87 <thyme-87@posteo.me>
" Description: use checkov for providing warnings for cloudformation via ale
call ale#Set('cloudformation_checkov_executable', 'checkov')
call ale#Set('cloudformation_checkov_options', '')
function! ale_linters#cloudformation#checkov#GetExecutable(buffer) abort
return ale#Var(a:buffer, 'cloudformation_checkov_executable')
endfunction
function! ale_linters#cloudformation#checkov#GetCommand(buffer) abort
return '%e ' . '-f %t -o json --quiet --framework cloudformation ' . ale#Var(a:buffer, 'cloudformation_checkov_options')
endfunction
function! ale_linters#cloudformation#checkov#Handle(buffer, lines) abort
let l:output = []
let l:results = get(get(ale#util#FuzzyJSONDecode(a:lines, {}), 'results', []), 'failed_checks', [])
for l:violation in l:results
call add(l:output, {
\ 'filename': l:violation['file_path'],
\ 'lnum': l:violation['file_line_range'][0],
\ 'end_lnum': l:violation['file_line_range'][1],
\ 'text': l:violation['check_name'] . ' [' . l:violation['check_id'] . ']',
\ 'detail': l:violation['check_id'] . ': ' . l:violation['check_name'] . "\n" .
\ 'For more information, see: '. l:violation['guideline'],
\ 'type': 'W',
\ })
endfor
return l:output
endfunction
call ale#linter#Define('cloudformation', {
\ 'name': 'checkov',
\ 'output_stream': 'stdout',
\ 'executable': function('ale_linters#cloudformation#checkov#GetExecutable'),
\ 'command': function('ale_linters#cloudformation#checkov#GetCommand'),
\ 'callback': 'ale_linters#cloudformation#checkov#Handle',
\})

View File

@@ -41,5 +41,51 @@ Just put the following in `ftdetect/cloudformation.vim`: >
This will get both cloudformation and yaml linters to work on any file with
`.template.yaml` extension.
===============================================================================
checkov *ale-cloudformation-checkov*
*ale-options.cloudformation_checkov_executable*
*g:ale_cloudformation_checkov_executable*
*b:ale_cloudformation_checkov_executable*
cloudformation_checkov_executable
g:ale_cloudformation_checkov_executable
Type: |String|
Default: `'checkov'`
This variable can be changed to use a different executable for checkov.
*ale-options.cloudformation_checkov_options*
*g:ale_cloudformation_checkov_options*
*b:ale_cloudformation_checkov_options*
cloudformation_checkov_options
g:ale_cloudformation_checkov_options
Type: |String|
Default: `''`
This variable can be changed to set additional options for checkov.
-------------------------------------------------------------------------------
Configuration
To get chekov to work with cloudformation files (rather than general yaml
files) we must set the buffer |filetype| to `yaml.cloudformation`. This
causes ALE to lint the file with linters configured for cloudformation and
YAML files.
One option is to put the following in `ftdetect/cloudformation.vim`: >
au BufRead,BufNewFile *.template.yaml set filetype=yaml.cloudformation
This will get both cloudformation and yaml linters to work on any file with
`.template.yaml` extension.
Another option is to check for the presence of 'AWSTemplateFormatVersion' in
the yaml file: >
au BufRead,BufNewFile *.yaml,*.yml if search('AWSTemplateFormatVersion', 'nw') | set filetype=yaml.cloudformation | endif
<
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:

View File

@@ -121,6 +121,7 @@ Notes:
* `joker`
* CloudFormation
* `cfn-python-lint`
* `checkov`
* CMake
* `cmake-format`
* `cmake-lint`

View File

@@ -3419,6 +3419,7 @@ documented in additional help files.
joker.................................|ale-clojure-joker|
cloudformation..........................|ale-cloudformation-options|
cfn-python-lint.......................|ale-cloudformation-cfn-python-lint|
checkov...............................|ale-cloudformation-checkov|
cmake...................................|ale-cmake-options|
cmakelint.............................|ale-cmake-cmakelint|
cmake-lint............................|ale-cmake-cmake-lint|

View File

@@ -131,6 +131,7 @@ formatting.
* [joker](https://github.com/candid82/joker)
* CloudFormation
* [cfn-python-lint](https://github.com/awslabs/cfn-python-lint)
* [checkov](https://github.com/bridgecrewio/checkov)
* CMake
* [cmake-format](https://github.com/cheshirekow/cmake_format)
* [cmake-lint](https://github.com/cheshirekow/cmake_format)

View File

@@ -0,0 +1,86 @@
Before:
runtime ale_linters/cloudformation/checkov.vim
call ale#test#SetFilename('sample.template.yaml')
After:
call ale#linter#Reset()
Execute(Handle output for no findings correctly):
AssertEqual
\ [],
\ ale_linters#cloudformation#checkov#Handle(bufnr(''), [
\'{',
\' "passed": 0,',
\' "failed": 0,',
\' "skipped": 0,',
\' "parsing_errors": 0,',
\' "resource_count": 0,',
\' "checkov_version": "3.2.415"',
\'}'
\])
Execute(Handle output for all tests passed):
AssertEqual
\ [],
\ ale_linters#cloudformation#checkov#Handle(bufnr(''), [
\'{',
\' "check_type": "cloudformation",',
\' "results": {',
\' "failed_checks": []',
\' },',
\' "summary": {',
\' "passed": 18,',
\' "failed": 0,',
\' "skipped": 0,',
\' "parsing_errors": 0,',
\' "resource_count": 3,',
\' "checkov_version": "3.2.415"',
\' }',
\'}'
\])
Execute(The JSON output of checkov should be handled correctly):
AssertEqual
\ [
\ {
\ 'filename': '/sample.template.yaml',
\ 'lnum': 57,
\ 'end_lnum': 79,
\ 'text': 'Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ) [CKV_AWS_116]',
\ 'detail': "CKV_AWS_116: Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)\n" .
\ 'For more information, see: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/ensure-that-aws-lambda-function-is-configured-for-a-dead-letter-queue-dlq',
\ 'type': 'W',
\ }
\ ],
\ ale_linters#cloudformation#checkov#Handle(bufnr(''), [
\'{',
\' "check_type": "cloudformation",',
\' "results": {',
\' "failed_checks": [',
\' {',
\' "check_id": "CKV_AWS_116",',
\' "bc_check_id": "BC_AWS_GENERAL_64",',
\' "check_name": "Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)",',
\' "check_result": {',
\' "result": "FAILED",',
\' "evaluated_keys": [',
\' "Properties/DeadLetterQueue/TargetArn"',
\' ]',
\' },',
\' "file_path": "/sample.template.yaml",',
\' "repo_file_path": "/sample.template.yaml",',
\' "file_line_range": [',
\' 57,',
\' 79',
\' ],',
\' "resource": "AWS::Serverless::Function.FunctionName",',
\' "evaluations": {},',
\' "check_class": "checkov.cloudformation.checks.resource.aws.LambdaDLQConfigured",',
\' "entity_tags": null,',
\' "resource_address": null,',
\' "guideline": "https://docs.prismacloud.io/en/enterprise-edition/policy-reference/aws-policies/aws-general-policies/ensure-that-aws-lambda-function-is-configured-for-a-dead-letter-queue-dlq"',
\' }',
\' ]',
\' }',
\'}'
\ ])

View File

@@ -0,0 +1,15 @@
Before:
call ale#assert#SetUpLinterTest('cloudformation', 'checkov')
After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be direct):
AssertLinter 'checkov',
\ ale#Escape('checkov') . ' -f %t -o json --quiet --framework cloudformation '
Execute(It should be possible to override the default command):
let b:ale_cloudformation_checkov_executable = '/bin/other/checkov'
AssertLinter '/bin/other/checkov',
\ ale#Escape('/bin/other/checkov') . ' -f %t -o json --quiet --framework cloudformation '