diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 7b504706d..95a000ffb 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -108,4 +108,6 @@ description: Runs terrascan on Terraform templates. language: script entry: terrascan.sh + files: \.tf$ + exclude: \.terraform\/.*$ require_serial: true diff --git a/README.md b/README.md index 45f8b3049..2c2375a2b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ If you are using `pre-commit-terraform` already or want to support its developme * [terraform_tflint](#terraform_tflint) * [terraform_tfsec](#terraform_tfsec) * [terraform_validate](#terraform_validate) + * [terrascan](#terrascan) * [Authors](#authors) * [License](#license) @@ -223,7 +224,7 @@ There are several [pre-commit](https://pre-commit.com/) hooks to keep Terraform | `terraform_validate` | Validates all Terraform configuration files. [Hook notes](#terraform_validate) | - | | `terragrunt_fmt` | Reformat all [Terragrunt](https://github.com/gruntwork-io/terragrunt) configuration files (`*.hcl`) to a canonical format. | `terragrunt` | | `terragrunt_validate` | Validates all [Terragrunt](https://github.com/gruntwork-io/terragrunt) configuration files (`*.hcl`) | `terragrunt` | -| `terrascan` | [terrascan](https://github.com/accurics/terrascan) Detect compliance and security violations. | `terrascan` | +| `terrascan` | [terrascan](https://github.com/accurics/terrascan) Detect compliance and security violations. [Hook notes](#terrascan) | `terrascan` | Check the [source file](https://github.com/antonbabenko/pre-commit-terraform/blob/master/.pre-commit-hooks.yaml) to know arguments used for each hook. @@ -550,6 +551,22 @@ Example: **Warning:** If you use Terraform workspaces, DO NOT use this workaround ([details](https://github.com/antonbabenko/pre-commit-terraform/issues/203#issuecomment-918791847)). Wait to [`force-init`](https://github.com/antonbabenko/pre-commit-terraform/issues/224) option implementation. +### terrascan + +1. `terrascan` supports custom arguments so you can pass supported flags like `--non-recursive` and `--policy-type` to disable recursive inspection and set the policy type respectively: + + ```yaml + - id: terrascan + args: + - --args=--non-recursive # avoids scan errors on subdirectories without Terraform config files + - --args=--policy-type=azure + ``` + + See the `terrascan run -h` command line help for available options. + +2. Use the `--args=--verbose` parameter to see the rule ID in the scaning output. Usuful to skip validations. +3. Use `--skip-rules="ruleID1,ruleID2"` parameter to skip one or more rules globally while scanning (e.g.: `--args=--skip-rules="ruleID1,ruleID2"`). +4. Use the syntax `#ts:skip=RuleID optional_comment` inside a resource to skip the rule for that resource. ## Authors diff --git a/terrascan.sh b/terrascan.sh index d8233068b..bd66a73de 100755 --- a/terrascan.sh +++ b/terrascan.sh @@ -4,27 +4,49 @@ set -eo pipefail main() { initialize_ parse_cmdline_ "$@" - - # propagate $FILES to custom function - terrascan_ "$ARGS" "$FILES" + terrascan_ "${ARGS[*]}" "${FILES[@]}" } terrascan_() { + local -r args="${1}" + shift 1 + local -a -r files=("$@") + # consume modified files passed from pre-commit so that # terrascan runs against only those relevant directories - for file_with_path in $FILES; do + for file_with_path in "${files[@]}"; do file_with_path="${file_with_path// /__REPLACED__SPACE__}" paths[index]=$(dirname "$file_with_path") - - let "index+=1" + index=$((index + 1)) done + # allow terrascan to continue if exit_code is greater than 0 + # preserve errexit status + shopt -qo errexit && ERREXIT_IS_SET=true + set +e + terrascan_final_exit_code=0 + + # for each path run terrascan for path_uniq in $(echo "${paths[*]}" | tr ' ' '\n' | sort -u); do path_uniq="${path_uniq//__REPLACED__SPACE__/ }" pushd "$path_uniq" > /dev/null - terrascan scan -i terraform $ARGS + + # pass the arguments to terrascan + # shellcheck disable=SC2086 # terrascan fails when quoting is used ("$arg" vs $arg) + terrascan scan -i terraform $args + + local exit_code=$? + if [ $exit_code != 0 ]; then + terrascan_final_exit_code=$exit_code + fi + popd > /dev/null done + + # restore errexit if it was set before the "for" loop + [[ $ERREXIT_IS_SET ]] && set -e + # return the terrascan final exit_code + exit $terrascan_final_exit_code } initialize_() {