From da201bac298670479e7d6dcd0078ebc893d4b264 Mon Sep 17 00:00:00 2001 From: Luke Exton <9834514+lexton@users.noreply.github.com> Date: Fri, 28 Apr 2023 12:19:40 -0400 Subject: [PATCH 1/4] feat: hook-config optionally delegate chdir push/pop --- README.md | 8 ++++++++ hooks/_common.sh | 29 +++++++++++++++++++++++++++-- hooks/terraform_tflint.sh | 12 ++++++++---- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2fa925886..c8f49c313 100644 --- a/README.md +++ b/README.md @@ -599,6 +599,14 @@ To replicate functionality in `terraform_docs` hook: - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl ``` +3. By default pre-commit-terraform performs directory switching into the terraform modules for you. If you want to delgate the directory changing to the binary - this will allow tflint to determine the full paths for error/warning messages, rather than just module relative paths. *Note: this requires `tflint>=0.44.0`.* For example: + + ```yaml + - id: terraform_tflint + args: + - --hook-config=--delegate-chdir + ``` + ### terraform_tfsec diff --git a/hooks/_common.sh b/hooks/_common.sh index 37b32d842..f19efc0a6 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -217,6 +217,25 @@ function common::per_dir_hook { ((index += 1)) done + # Lookup hook-config for modifiers that impact common behavior + local DELEGATE_CHDIR=false + IFS=";" read -r -a configs <<< "${HOOK_CONFIG[*]}" + for c in "${configs[@]}"; do + IFS="=" read -r -a config <<< "$c" + key=${config[0]} + value=${config[1]} + + case $key in + --delegate-chdir) + # this flag will skip pushing and popping directories + # delegating the responsibility to the hooked plugin/binary + if [[ ! $value || $value == true ]]; then + DELEGATE_CHDIR=true + fi + ;; + esac + done + # preserve errexit status shopt -qo errexit && ERREXIT_IS_SET=true # allow hook to continue if exit_code is greater than 0 @@ -226,7 +245,10 @@ function common::per_dir_hook { # run hook for each path for dir_path in $(echo "${dir_paths[*]}" | tr ' ' '\n' | sort -u); do dir_path="${dir_path//__REPLACED__SPACE__/ }" - pushd "$dir_path" > /dev/null || continue + + if [[ $DELEGATE_CHDIR != true ]]; then + pushd "$dir_path" > /dev/null || continue + fi per_dir_hook_unique_part "$dir_path" "${args[@]}" @@ -235,7 +257,10 @@ function common::per_dir_hook { final_exit_code=$exit_code fi - popd > /dev/null + if ! $DELEGATE_CHDIR; then + popd > /dev/null + fi + done # restore errexit if it was set before the "for" loop diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index 1a74ce344..3f982d26f 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -28,7 +28,7 @@ function main { } || { local exit_code=$? common::colorify "red" "Command 'tflint --init' failed:" - echo "${TFLINT_INIT}" + echo -e "${TFLINT_INIT}" return ${exit_code} } @@ -50,15 +50,19 @@ function per_dir_hook_unique_part { shift local -a -r args=("$@") - TFLINT_OUTPUT=$(tflint "${args[@]}" 2>&1) + if [[ $DELEGATE_CHDIR == true ]]; then + local dir_args="--chdir=$dir_path" + fi + + # shellcheck disable=SC2086 # we need to remove the arg if its unset + TFLINT_OUTPUT=$(tflint ${dir_args:-} "${args[@]}" 2>&1) local exit_code=$? if [ $exit_code -ne 0 ]; then common::colorify "yellow" "TFLint in $dir_path/:" - echo "$TFLINT_OUTPUT" + echo -e "$TFLINT_OUTPUT" fi - # return exit code to common::per_dir_hook return $exit_code } From 0725e707da5801ff72b6c0fe8977ca9272714b27 Mon Sep 17 00:00:00 2001 From: Luke Exton <9834514+lexton@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:03:03 -0400 Subject: [PATCH 2/4] fix delegate chdir call --- hooks/_common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index f19efc0a6..becc8d710 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -257,7 +257,7 @@ function common::per_dir_hook { final_exit_code=$exit_code fi - if ! $DELEGATE_CHDIR; then + if [[ $DELEGATE_CHDIR != true ]]; then popd > /dev/null fi From 7e5bda4822cb04ebd835fdcff2a28d2acaf914df Mon Sep 17 00:00:00 2001 From: Maksym Vlasov Date: Tue, 2 May 2023 14:54:52 +0300 Subject: [PATCH 3/4] Apply suggestions from code review --- hooks/terraform_tflint.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index 3f982d26f..3c17d71f2 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -63,6 +63,7 @@ function per_dir_hook_unique_part { echo -e "$TFLINT_OUTPUT" fi + # return exit code to common::per_dir_hook return $exit_code } From 5dc58c425a63a3b767d11058c785fb3dcb0d49da Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Mon, 8 May 2023 17:38:51 +0300 Subject: [PATCH 4/4] Make chdir extendible and explicitly provide it inside function --- hooks/_common.sh | 10 +++++----- hooks/terraform_checkov.sh | 7 ++++++- hooks/terraform_fmt.sh | 7 ++++++- hooks/terraform_providers_lock.sh | 3 +++ hooks/terraform_tflint.sh | 8 ++++++-- hooks/terraform_tfsec.sh | 7 ++++++- hooks/terraform_validate.sh | 9 +++++++-- hooks/terragrunt_fmt.sh | 7 ++++++- hooks/terragrunt_validate.sh | 7 ++++++- hooks/terrascan.sh | 7 ++++++- hooks/tfupdate.sh | 7 ++++++- 11 files changed, 63 insertions(+), 16 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index becc8d710..4f9c7f0ce 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -218,7 +218,7 @@ function common::per_dir_hook { done # Lookup hook-config for modifiers that impact common behavior - local DELEGATE_CHDIR=false + local change_dir_in_unique_part=false IFS=";" read -r -a configs <<< "${HOOK_CONFIG[*]}" for c in "${configs[@]}"; do IFS="=" read -r -a config <<< "$c" @@ -230,7 +230,7 @@ function common::per_dir_hook { # this flag will skip pushing and popping directories # delegating the responsibility to the hooked plugin/binary if [[ ! $value || $value == true ]]; then - DELEGATE_CHDIR=true + change_dir_in_unique_part="delegate_chdir" fi ;; esac @@ -246,18 +246,18 @@ function common::per_dir_hook { for dir_path in $(echo "${dir_paths[*]}" | tr ' ' '\n' | sort -u); do dir_path="${dir_path//__REPLACED__SPACE__/ }" - if [[ $DELEGATE_CHDIR != true ]]; then + if [[ $change_dir_in_unique_part == false ]]; then pushd "$dir_path" > /dev/null || continue fi - per_dir_hook_unique_part "$dir_path" "${args[@]}" + per_dir_hook_unique_part "$dir_path" "$change_dir_in_unique_part" "${args[@]}" local exit_code=$? if [ $exit_code -ne 0 ]; then final_exit_code=$exit_code fi - if [[ $DELEGATE_CHDIR != true ]]; then + if [[ $change_dir_in_unique_part == false ]]; then popd > /dev/null fi diff --git a/hooks/terraform_checkov.sh b/hooks/terraform_checkov.sh index fe0de0017..03ad208c6 100755 --- a/hooks/terraform_checkov.sh +++ b/hooks/terraform_checkov.sh @@ -31,6 +31,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -38,7 +41,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") checkov -d . "${args[@]}" diff --git a/hooks/terraform_fmt.sh b/hooks/terraform_fmt.sh index 73e3a3f1e..bb0b327d1 100755 --- a/hooks/terraform_fmt.sh +++ b/hooks/terraform_fmt.sh @@ -28,6 +28,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -35,7 +38,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook diff --git a/hooks/terraform_providers_lock.sh b/hooks/terraform_providers_lock.sh index a75a7e536..dedbcfd97 100755 --- a/hooks/terraform_providers_lock.sh +++ b/hooks/terraform_providers_lock.sh @@ -25,6 +25,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index 3c17d71f2..f26201a3c 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -41,16 +41,20 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { local -r dir_path="$1" - shift + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") - if [[ $DELEGATE_CHDIR == true ]]; then + if [ "$change_dir_in_unique_part" == "delegate_chdir" ]; then local dir_args="--chdir=$dir_path" fi diff --git a/hooks/terraform_tfsec.sh b/hooks/terraform_tfsec.sh index 535116794..24b7d438f 100755 --- a/hooks/terraform_tfsec.sh +++ b/hooks/terraform_tfsec.sh @@ -31,6 +31,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -38,7 +41,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook diff --git a/hooks/terraform_validate.sh b/hooks/terraform_validate.sh index 3e4694855..d0a9dfb70 100755 --- a/hooks/terraform_validate.sh +++ b/hooks/terraform_validate.sh @@ -70,13 +70,18 @@ function match_validate_errors { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status ####################################################################### function per_dir_hook_unique_part { local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") local exit_code @@ -95,7 +100,7 @@ function per_dir_hook_unique_part { case $key in --retry-once-with-cleanup) - if [ $retry_once_with_cleanup ]; then + if [ $retry_once_with_cleanup ]; then common::colorify "yellow" 'Invalid hook config. Make sure that you specify not more than one "--retry-once-with-cleanup" flag' exit 1 fi diff --git a/hooks/terragrunt_fmt.sh b/hooks/terragrunt_fmt.sh index 279e78d51..7c78b9233 100755 --- a/hooks/terragrunt_fmt.sh +++ b/hooks/terragrunt_fmt.sh @@ -24,6 +24,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -31,7 +34,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook diff --git a/hooks/terragrunt_validate.sh b/hooks/terragrunt_validate.sh index 7d9e287db..15e203be7 100755 --- a/hooks/terragrunt_validate.sh +++ b/hooks/terragrunt_validate.sh @@ -24,6 +24,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -31,7 +34,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook diff --git a/hooks/terrascan.sh b/hooks/terrascan.sh index ad81aaba9..ac040b93e 100755 --- a/hooks/terrascan.sh +++ b/hooks/terrascan.sh @@ -24,6 +24,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -31,7 +34,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook diff --git a/hooks/tfupdate.sh b/hooks/tfupdate.sh index ebfa7ce2d..d9a482917 100755 --- a/hooks/tfupdate.sh +++ b/hooks/tfupdate.sh @@ -34,6 +34,9 @@ function main { # Arguments: # dir_path (string) PATH to dir relative to git repo root. # Can be used in error logging +# change_dir_in_unique_part (string/false) Modifier which creates +# possibilities to use non-common chdir strategies. +# Availability depends on hook. # args (array) arguments that configure wrapped tool behavior # Outputs: # If failed - print out hook checks status @@ -41,7 +44,9 @@ function main { function per_dir_hook_unique_part { # shellcheck disable=SC2034 # Unused var. local -r dir_path="$1" - shift + # shellcheck disable=SC2034 # Unused var. + local -r change_dir_in_unique_part="$2" + shift 2 local -a -r args=("$@") # pass the arguments to hook