diff --git a/.bpkg.lock b/.bpkg.lock new file mode 100644 index 0000000..ee1e6c0 --- /dev/null +++ b/.bpkg.lock @@ -0,0 +1 @@ +fabasoad/sh-logging@v0.1.1 diff --git a/.gitignore b/.gitignore index 8c9578d..9a61e1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.bpkg .gitleaks.toml .vscode/* !.vscode/settings.json diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index f208d58..da75195 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -2,7 +2,7 @@ - id: grype-dir name: Grype Dir description: Scans directory - entry: src/main.sh "grype-dir" + entry: entrypoint.sh "grype-dir" language: script pass_filenames: false verbose: true diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dfea035 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +.PHONY: install + +install: + @./scripts/bpkg-install-packages.sh + @echo "[pre-commit-grype] Operation completed successfully: install" diff --git a/README.md b/README.md index 8c35f89..4200673 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ ![security](https://github.com/fabasoad/pre-commit-grype/actions/workflows/security.yml/badge.svg) ![linting](https://github.com/fabasoad/pre-commit-grype/actions/workflows/linting.yml/badge.svg) -1. [grype-dir](#grype-dir) - ## Table of Contents - [How it works?](#how-it-works) @@ -150,8 +148,8 @@ Here is the precedence order of `pre-commit-grype` tool: - Environment variable. - Default value. -For example, if you set `PRE_COMMIT_GRYPE_LOG_LEVEL=off` and `--hook-args=--log-level -debug` then `debug` value will be used. +For example, if you set `PRE_COMMIT_GRYPE_LOG_LEVEL=warning` and `--hook-args=--log-level +error` then `error` value will be used. ##### Log level @@ -161,7 +159,7 @@ please look at the [Grype parameters](#grype). - Parameter name: `--log-level` - Environment variable: `PRE_COMMIT_GRYPE_LOG_LEVEL` -- Possible values: `debug`, `info`, `warning`, `error`, `off` +- Possible values: `debug`, `info`, `warning`, `error` - Default: `info` ### Examples @@ -202,6 +200,6 @@ repos: hooks: - id: grype-dir args: - - --hook-args=--log-level=off + - --hook-args=--log-level=error - --grype-args=--quiet ``` diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100755 index 0000000..a21b472 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env sh + +# Install dependencies +scripts/bpkg-install-packages.sh +# Run hook +src/main.sh "$@" diff --git a/scripts/bpkg-install-packages.sh b/scripts/bpkg-install-packages.sh new file mode 100755 index 0000000..09bb3be --- /dev/null +++ b/scripts/bpkg-install-packages.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env sh + +export PREFIX="$(pwd)/src/.bpkg" + +main() { + rm -rf "${PREFIX}" + mkdir -p "${PREFIX}" + lock_file="./.bpkg.lock" + while IFS= read -r line; do + bpkg install "$line" + done < "${lock_file}" +} + +main "$@" diff --git a/src/lib/args/parse-all-args.sh b/src/lib/args/parse-all-args.sh index 9c29396..b94a7ec 100755 --- a/src/lib/args/parse-all-args.sh +++ b/src/lib/args/parse-all-args.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash parse_all_args() { - local -n map_ref=$1 + local -n args_map_ref=$1 shift - map_ref["grype-args"]="" - map_ref["hook-args"]="" + args_map_ref["grype-args"]="" + args_map_ref["hook-args"]="" curr_flag="" @@ -25,14 +25,14 @@ parse_all_args() { *) arg=$(echo "${args}" | cut -d ' ' -f 1) if [ "${curr_flag}" = "hook" ]; then - map_ref["hook-args"]="${map_ref["hook-args"]} ${arg}" + args_map_ref["hook-args"]="${args_map_ref["hook-args"]} ${arg}" elif [ "${curr_flag}" = "grype" ]; then - map_ref["grype-args"]="${map_ref["grype-args"]} ${arg}" + args_map_ref["grype-args"]="${args_map_ref["grype-args"]} ${arg}" else msg="Invalid format of the following argument: \"${arg}\". Please use" msg="${msg} --hook-args to pass args to pre-commit hook or --grype-args" - msg="${msg} to pass args to grype. For more information go to https://github.com/fabasoad/pre-commit-grype?tab=readme-ov-file" - log_error "${msg}" + msg="${msg} to pass args to grype. For more information see https://github.com/fabasoad/pre-commit-grype?tab=readme-ov-file" + fabasoad_log "error" "${msg}" exit 1 fi @@ -47,6 +47,6 @@ parse_all_args() { # Removing leading space is needed here because we concatenate string in a loop # and we start with a empty string. So, first iteration is empty string + space # + next value. Here we remove that empty string from the beginning - map_ref["hook-args"]=$(echo "${map_ref["hook-args"]}" | sed 's/^ *//') - map_ref["grype-args"]=$(echo "${map_ref["grype-args"]}" | sed 's/^ *//') + args_map_ref["hook-args"]=$(echo "${args_map_ref["hook-args"]}" | sed 's/^ *//') + args_map_ref["grype-args"]=$(echo "${args_map_ref["grype-args"]}" | sed 's/^ *//') } diff --git a/src/lib/args/parse-hook-args.sh b/src/lib/args/parse-hook-args.sh index 20d9d98..22b5d1b 100755 --- a/src/lib/args/parse-hook-args.sh +++ b/src/lib/args/parse-hook-args.sh @@ -1,41 +1,41 @@ #!/usr/bin/env sh -_set_param() { - set_param_func_name="set_global_$1" - args_str="$2" - delimiter="$3" - # Removing param key, such as "--log-level" - args_str=$(echo "${args_str}" | cut -d "${delimiter}" -f 2-) - # Taking param value, such as "debug" - param_val=$(echo "${args_str}" | cut -d ' ' -f 1) - # Saving leftover - args_str=$(echo "${args_str}" | cut -d ' ' -f 2-) - ${set_param_func_name} "${param_val}" - if [ "${param_val}" = "${args_str}" ]; then - echo "" - else - echo "${args_str}" - fi -} - parse_hook_args() { + local -n args_map_ref=$1 + shift + args_str="$1" if [ -n "${args_str}" ]; then orig_str="${args_str}" while [ ${#args_str} -gt 0 ]; do + delimiter="" case "${args_str}" in "${CONFIG_LOG_LEVEL_ARG_NAME}="*) - args_str=$(_set_param "log_level" "${args_str}" "=") + delimiter="=" ;; "${CONFIG_LOG_LEVEL_ARG_NAME} "*) - args_str=$(_set_param "log_level" "${args_str}" " ") + delimiter=" " ;; *) - log_warning "Unknown ${args_str} argument has been passed as --hook-args" + fabasoad_log "error" "Unknown \"${args_str}\" argument has been passed to --hook-args" + exit 1 ;; esac - shift + + # Removing param key, such as "--log-level" + param_key=$(echo "${args_str}" | cut -d "${delimiter}" -f 1) + args_str=$(echo "${args_str}" | cut -d "${delimiter}" -f 2-) + # Taking param value, such as "debug" + param_val=$(echo "${args_str}" | cut -d ' ' -f 1) + # Saving leftover + args_str=$(echo "${args_str}" | cut -d ' ' -f 2-) + # If leftover is the same as prev. value then it was the last argument in + # the string, so we finish loop + if [ "${param_val}" = "${args_str}" ]; then + args_str="" + fi + # Saving parameter to the map + args_map_ref["${param_key}"]="${param_val}" done - log_info "Pre-commit hook arguments: ${orig_str}" fi } diff --git a/src/lib/base/grype-common.sh b/src/lib/base/grype-common.sh index e857f68..71fea21 100755 --- a/src/lib/base/grype-common.sh +++ b/src/lib/base/grype-common.sh @@ -8,21 +8,21 @@ grype_common() { grype_path=$(install) grype_version=$(${grype_path} --version | cut -d ' ' -f 2) - log_info "Grype path: ${grype_path}" - log_info "Grype version: ${grype_version}" - log_info "Grype arguments: ${grype_args}" + fabasoad_log "info" "Grype path: ${grype_path}" + fabasoad_log "info" "Grype version: ${grype_version}" + fabasoad_log "info" "Grype arguments: ${grype_args}" - log_debug "Run Grype scanning:" + fabasoad_log "debug" "Run Grype scanning:" set +e ${grype_path} ${grype_args} grype_exit_code=$? set -e - log_debug "Grype scanning completed" + fabasoad_log "debug" "Grype scanning completed" msg="Grype exit code: ${grype_exit_code}" if [ "${grype_exit_code}" = "0" ]; then - log_info "${msg}" + fabasoad_log "info" "${msg}" else - log_warning "${msg}" + fabasoad_log "warning" "${msg}" fi uninstall "${CONFIG_TEMP_DIR}" diff --git a/src/lib/config/config-logging.sh b/src/lib/config/config-logging.sh new file mode 100755 index 0000000..d2cdbdc --- /dev/null +++ b/src/lib/config/config-logging.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +apply_logging_config() { + log_level="${1:-${PRE_COMMIT_GRYPE_LOG_LEVEL:-${CONFIG_LOG_LEVEL_DEFAULT_VAL}}}" + validate_enum "${CONFIG_LOG_LEVEL_ARG_NAME}" "${log_level}" "${CONFIG_LOG_LEVEL_OPTIONS}" + export FABASOAD_LOG_CONFIG_LOG_LEVEL="${log_level}" + + export FABASOAD_LOG_CONFIG_TEXT_COLOR="${CONFIG_LOG_TEXT_COLOR_DEFAULT_VAL}" + export FABASOAD_LOG_CONFIG_DATE_FORMAT="${CONFIG_LOG_DATE_FORMAT_DEFAULT_VAL}" + export FABASOAD_LOG_CONFIG_OUTPUT_FORMAT="${CONFIG_LOG_OUTPUT_FORMAT_DEFAULT_VAL}" + export FABASOAD_LOG_CONFIG_HEADER="${CONFIG_LOG_HEADER_DEFAULT_VAL}" +} diff --git a/src/lib/config.sh b/src/lib/config/defaults.sh similarity index 68% rename from src/lib/config.sh rename to src/lib/config/defaults.sh index 8f62691..04e5e59 100755 --- a/src/lib/config.sh +++ b/src/lib/config/defaults.sh @@ -1,9 +1,16 @@ #!/usr/bin/env sh +# Logging CONFIG_LOG_LEVEL_ARG_NAME="--log-level" CONFIG_LOG_LEVEL_DEFAULT_VAL="info" -CONFIG_LOG_LEVEL_OPTIONS="off,debug,info,warning,error" +CONFIG_LOG_LEVEL_OPTIONS="debug,info,warning,error" +CONFIG_LOG_HEADER_DEFAULT_VAL="pre-commit-grype" +CONFIG_LOG_TEXT_COLOR_DEFAULT_VAL="true" +CONFIG_LOG_DATE_FORMAT_DEFAULT_VAL="%Y-%m-%d %T" +CONFIG_LOG_OUTPUT_FORMAT_DEFAULT_VAL="text" + +# Temp dir CONFIG_TEMP_DIR_NAME=".pre-commit-grype" CONFIG_TEMP_DIR="$(pwd)/${CONFIG_TEMP_DIR_NAME}" CONFIG_TEMP_BIN_DIR="${CONFIG_TEMP_DIR}/bin" diff --git a/src/lib/global-vars/modifiers.sh b/src/lib/global-vars/modifiers.sh deleted file mode 100755 index ba77924..0000000 --- a/src/lib/global-vars/modifiers.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env sh - -# Gets log level. Precedence: -# (1) Parameter defined via --hook-args, i.e. value saved to temporary directory -# (2) Environment variable -# (3) Default value -get_global_log_level() { - set +u - # Removing trailing and leading spaces is needed here to be sure to have a correct - # value retrieved from environment variable in case user sets it incorrectly - # (with spaces) - get_prop "PRE_COMMIT_GRYPE_LOG_LEVEL" \ - "${PRE_COMMIT_GRYPE_LOG_LEVEL:-${CONFIG_LOG_LEVEL_DEFAULT_VAL}}" \ - | sed 's/^ *//' | sed 's/ *$//' - set -u -} - -set_global_log_level() { - log_level="$1" - is_valid=$(validate_log_level_param "${log_level}") - if [ "${is_valid}" = "true" ]; then - save_prop "PRE_COMMIT_GRYPE_LOG_LEVEL" "${log_level}" - fi -} - -reset_global_log_level() { - set_global_log_level "${CONFIG_LOG_LEVEL_DEFAULT_VAL}" -} diff --git a/src/lib/global-vars/verify.sh b/src/lib/global-vars/verify.sh deleted file mode 100755 index 5ef8f5e..0000000 --- a/src/lib/global-vars/verify.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env sh - -_verify_log_level() { - env_var_name="PRE_COMMIT_GRYPE_LOG_LEVEL" - env_var_val="$(get_global_log_level)" - is_valid=$(validate_log_level_global_var "${env_var_val}" "off") - if [ "${is_valid}" = "false" ]; then - msg="\"${env_var_name}\" environment variable is invalid (\"${env_var_val}\")." - msg="${msg} Possible values: $(echo "${CONFIG_LOG_LEVEL_OPTIONS%,}" | sed 's/,/, /g')." - msg="${msg} Resetting to default value: \"${CONFIG_LOG_LEVEL_DEFAULT_VAL}\"." - log_warning "${msg}" - reset_global_log_level - fi -} - -verify_global_vars() { - _verify_log_level -} diff --git a/src/lib/installation/install.sh b/src/lib/installation/install.sh index 65e655e..b2625f6 100755 --- a/src/lib/installation/install.sh +++ b/src/lib/installation/install.sh @@ -1,19 +1,19 @@ #!/usr/bin/env sh install() { - log_debug "Verifying Grype installation" + fabasoad_log "debug" "Verifying Grype installation" if command -v grype &> /dev/null; then grype_path="$(which grype)" - log_debug "Grype is found at ${grype_path}. Installation skipped" + fabasoad_log "debug" "Grype is found at ${grype_path}. Installation skipped" else grype_path="${CONFIG_TEMP_BIN_DIR}/grype" mkdir -p "${CONFIG_TEMP_BIN_DIR}" if [ ! -d "${CONFIG_TEMP_BIN_DIR}" ] || [ ! -f "${grype_path}" ]; then - log_debug "Grype is not found. Downloading latest version:" + fabasoad_log "debug" "Grype is not found. Downloading latest version:" curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b "${CONFIG_TEMP_BIN_DIR}" - log_debug "Downloading completed" + fabasoad_log "debug" "Downloading completed" else - log_debug "Grype is found at ${grype_path}. Installation skipped" + fabasoad_log "debug" "Grype is found at ${grype_path}. Installation skipped" fi fi echo "${grype_path}" diff --git a/src/lib/installation/uninstall.sh b/src/lib/installation/uninstall.sh index 2bbbbef..b989186 100755 --- a/src/lib/installation/uninstall.sh +++ b/src/lib/installation/uninstall.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh uninstall() { - log_debug "${CONFIG_TEMP_DIR} directory has been removed" + fabasoad_log "debug" "${CONFIG_TEMP_DIR} directory has been removed" rm -rf "${CONFIG_TEMP_DIR}" } diff --git a/src/lib/utils/logging.sh b/src/lib/utils/logging.sh deleted file mode 100755 index 12b5cc7..0000000 --- a/src/lib/utils/logging.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env sh - -_is_debug_ok() { - # ok: debug - # not ok: off, info, warning, error - if [ "$(get_global_log_level)" = "debug" ]; then - echo "true" - else - echo "false" - fi -} - -_is_info_ok() { - # ok: debug, info - # not ok: off, warning, error - if [ "$(get_global_log_level)" = "debug" ] || [ "$(get_global_log_level)" = "info" ]; then - echo "true" - else - echo "false" - fi -} - -_is_warning_ok() { - # ok: debug, info, warning - # not ok: off, error - if [ "$(get_global_log_level)" != "error" ] && [ "$(get_global_log_level)" != "off" ]; then - echo "true" - else - echo "false" - fi -} - -_is_error_ok() { - # ok: debug, info, warning, error - # not ok: off - if [ "$(get_global_log_level)" != "off" ]; then - echo "true" - else - echo "false" - fi -} - -_log() { - prefix="[pre-commit-grype]" - level=$1 - msg=$2 - - printf "%s %s level=%s %s\n" "$prefix" "$(date +'%Y-%m-%d %T')" "$level" "$msg" >&2 -} - -log_off() { - : -} - -log_debug() { - if [ "$(_is_debug_ok)" = "true" ]; then - _log "debug" "$1" - fi -} - -log_info() { - if [ "$(_is_info_ok)" = "true" ]; then - _log "info" "$1" - fi -} - -log_warning() { - if [ "$(_is_warning_ok)" = "true" ]; then - _log "warning" "$1" - fi -} - -log_error() { - if [ "$(_is_error_ok)" = "true" ]; then - _log "error" "$1" - fi -} diff --git a/src/lib/utils/map.sh b/src/lib/utils/map.sh new file mode 100755 index 0000000..3e75ba1 --- /dev/null +++ b/src/lib/utils/map.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env sh + +map_to_str() { + local -n map_ref=$1 + shift + + args_delimiter="${1:-" "}" + key_val_delimiter="${2:-"="}" + + str="" + if [ "${#map_ref[@]}" -ne 0 ]; then + for key in "${!map_ref[@]}"; do + str="${str}${args_delimiter}${key}${key_val_delimiter}${map_ref[$key]}" + done + fi + if [ "${#str}" -ne 0 ]; then + str=${str:${#args_delimiter}} + fi + echo "${str}" +} diff --git a/src/lib/utils/validators.sh b/src/lib/utils/validators.sh index d33a0af..76928f7 100755 --- a/src/lib/utils/validators.sh +++ b/src/lib/utils/validators.sh @@ -4,33 +4,12 @@ validate_enum() { param_key="$1" param_val="$2" enum_opts="$3," - log_level="${4:-warning}" case ",${enum_opts}" in *",${param_val},"*) - echo "true" ;; *) - log_${log_level} "\"${param_key}\" parameter is invalid. Possible values: $(echo "${enum_opts%,}" | sed 's/,/, /g')." - echo "false" + fabasoad_log "error" "\"${param_key}\" parameter is invalid. Possible values: $(echo "${enum_opts%,}" | sed 's/,/, /g')." + exit 1 ;; esac } - -_validate_log_level() { - param_key="${1}" - param_val="${2}" - log_level="${3:-warning}" - validate_enum "${param_key}" "${param_val}" "${CONFIG_LOG_LEVEL_OPTIONS}" "${log_level}" -} - -validate_log_level_param() { - param_val="${1}" - log_level="${2:-warning}" - _validate_log_level "${CONFIG_LOG_LEVEL_ARG_NAME}" "${param_val}" "${log_level}" -} - -validate_log_level_global_var() { - param_val="${1}" - log_level="${2:-warning}" - _validate_log_level "PRE_COMMIT_GRYPE_LOG_LEVEL" "${param_val}" "${log_level}" -} diff --git a/src/main.sh b/src/main.sh index c0d954b..4c18b9e 100755 --- a/src/main.sh +++ b/src/main.sh @@ -3,8 +3,8 @@ # Import all scripts _import_all() { current_file=$(basename "$0") - sh_files=$(find "$(dirname "$(realpath "$0")")" -type f -name "*.sh") - for file in $sh_files; do + exec_files=$(find "src" -type f -perm +111) + for file in $exec_files; do if [ "$(basename "${file}")" != "${current_file}" ]; then . "${file}" fi @@ -19,24 +19,24 @@ main() { cmd_actual="$1" shift - declare -A args_map - parse_all_args args_map "$(echo "$@" | sed 's/^ *//' | sed 's/ *$//')" - parse_hook_args "${args_map["hook-args"]}" + declare -A all_args_map + parse_all_args all_args_map "$(echo "$@" | sed 's/^ *//' | sed 's/ *$//')" + declare -A hook_args_map + parse_hook_args hook_args_map "${all_args_map["hook-args"]}" - verify_global_vars + # Apply configs + set +u + apply_logging_config "${hook_args_map["${CONFIG_LOG_LEVEL_ARG_NAME}"]}" + + fabasoad_log "info" "Pre-commit hook arguments: $(map_to_str hook_args_map)" + set -u case "${cmd_actual}" in "${cmd_grype_dir}") - grype_dir "${args_map["grype-args"]}" + grype_dir "${all_args_map["grype-args"]}" ;; *) - is_valid=$(validate_enum "hook" "${cmd_actual}" "${cmd_grype_dir}" "error") - if [ "${is_valid}" = "false" ]; then - exit 1 - else - log_error "Something went wrong" - exit 1 - fi + validate_enum "hook" "${cmd_actual}" "${cmd_grype_dir}" ;; esac }