diff --git a/CHANGELOG.md b/CHANGELOG.md index f51354913a7ba33f67dc6d43d69aad82ee3ec25c..5f173fa106a34d4687534208cd8b9501125009ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## [3.5.2](https://gitlab.com/to-be-continuous/bash/compare/3.5.1...3.5.2) (2024-09-29) + + +### Bug Fixes + +* bats libs not downloaded behind a proxy ([c0d51df](https://gitlab.com/to-be-continuous/bash/commit/c0d51df73f35705f839afffb85415c4b6eed7115)) + +## [3.5.1](https://gitlab.com/to-be-continuous/bash/compare/3.5.0...3.5.1) (2024-09-29) + + +### Bug Fixes + +* support glob patterns in ShellCheck files ([4fee4c7](https://gitlab.com/to-be-continuous/bash/commit/4fee4c723602f01235d038c9f9b8b41d15e79577)) + +# [3.5.0](https://gitlab.com/to-be-continuous/bash/compare/3.4.1...3.5.0) (2024-08-30) + + +### Features + +* standard TBC secrets decoding ([d9568c9](https://gitlab.com/to-be-continuous/bash/commit/d9568c97298ba0f186d56b77404d4c9b06e021be)) + ## [3.4.1](https://gitlab.com/to-be-continuous/bash/compare/3.4.0...3.4.1) (2024-05-05) diff --git a/README.md b/README.md index 21b30af7863f67fdf14b91eb8028640392925937..f318362efa4396378ed3334d0bf1e50a41767f15 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Add the following to your `.gitlab-ci.yml`: ```yaml include: # 1: include the component - - component: $CI_SERVER_FQDN/to-be-continuous/bash/gitlab-ci-bash@3.4.1 + - component: $CI_SERVER_FQDN/to-be-continuous/bash/gitlab-ci-bash@3.5.2 # 2: set/override component inputs inputs: bats-enabled: true # ⚠ this is only an example @@ -28,7 +28,7 @@ Add the following to your `.gitlab-ci.yml`: include: # 1: include the template - project: 'to-be-continuous/bash' - ref: '3.4.1' + ref: '3.5.2' file: '/templates/gitlab-ci-bash.yml' variables: @@ -46,7 +46,7 @@ This job performs a static analysis of your shell scripts using [ShellCheck](htt | ----------------------- | -------------------------------------- | ----------------- | | `shellcheck-disabled` / `BASH_SHELLCHECK_DISABLED` | Set to `true` to disable ShellCheck | _none_ (enabled) | | `shellcheck-image` / `BASH_SHELLCHECK_IMAGE` | The Docker image used to run [ShellCheck](https://github.com/koalaman/shellcheck) | `registry.hub.docker.com/koalaman/shellcheck-alpine:stable` | -| `shellcheck-files` / `BASH_SHELLCHECK_FILES` | Shell file(s) pattern to analyse | `**/*.sh` | +| `shellcheck-files` / `BASH_SHELLCHECK_FILES` | Shell file(s) or pattern(s) to analyse | `**/*.sh` | | `shellcheck-opts` / `BASH_SHELLCHECK_OPTS` | ShellCheck [options](https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md) | _none_ | ### `bash-bats` job diff --git a/bumpversion.sh b/bumpversion.sh index 329e866dac988c049574a0a9f26ba89979c523a8..708faf434d2459d63b2bdaceada5eb32b0fd39eb 100755 --- a/bumpversion.sh +++ b/bumpversion.sh @@ -27,7 +27,7 @@ if [[ "$curVer" ]]; then log_info "Bump version from \\e[33;1m${curVer}\\e[0m to \\e[33;1m${nextVer}\\e[0m (release type: $relType)..." # replace in README - sed -e "s/ref: *'$curVer'/ref: '$nextVer'/" -e "s/ref: *\"$curVer\”/ref: \”$nextVer\”/" -e "s/component: *\(.*\)@$curVer/component: \1@$nextVer/" README.md > README.md.next + sed -e "s/ref: *'$curVer'/ref: '$nextVer'/" -e "s/ref: *\"$curVer\"/ref: \"$nextVer\"/" -e "s/component: *\(.*\)@$curVer/component: \1@$nextVer/" README.md > README.md.next mv -f README.md.next README.md # replace in template and variants diff --git a/kicker.json b/kicker.json index fcb04595070c259753a45936c539accc51a501dd..d612ef5fe24f6a1b5398fcd5b2e3b7c9580e4fa7 100644 --- a/kicker.json +++ b/kicker.json @@ -20,7 +20,7 @@ }, { "name": "BASH_SHELLCHECK_FILES", - "description": "Shell file(s) pattern to analyse", + "description": "Shell file(s) or pattern(s) to analyse", "default": "**/*.sh" }, { diff --git a/templates/gitlab-ci-bash.yml b/templates/gitlab-ci-bash.yml index 357de82c6fbd44b4c4a5135c219fd39110eac0cf..b3094a8163ae703ed9b0f6c4f28da644540da9cc 100644 --- a/templates/gitlab-ci-bash.yml +++ b/templates/gitlab-ci-bash.yml @@ -23,7 +23,7 @@ spec: description: The Docker image used to run [ShellCheck](https://github.com/koalaman/shellcheck) default: registry.hub.docker.com/koalaman/shellcheck-alpine:stable shellcheck-files: - description: Shell file(s) pattern to analyse + description: Shell file(s) or pattern(s) to analyse default: '**/*.sh' shellcheck-opts: description: ShellCheck [options](https://github.com/koalaman/shellcheck/blob/master/shellcheck.1.md) @@ -137,15 +137,15 @@ stages: set -e function log_info() { - echo -e "[\\e[1;94mINFO\\e[0m] $*" + >&2 echo -e "[\\e[1;94mINFO\\e[0m] $*" } function log_warn() { - echo -e "[\\e[1;93mWARN\\e[0m] $*" + >&2 echo -e "[\\e[1;93mWARN\\e[0m] $*" } function log_error() { - echo -e "[\\e[1;91mERROR\\e[0m] $*" + >&2 echo -e "[\\e[1;91mERROR\\e[0m] $*" } function install_ca_certs() { @@ -248,6 +248,99 @@ stages: log_info "... done" } + # evaluate and export a secret + # - $1: secret variable name + function eval_secret() { + name=$1 + value=$(eval echo "\$${name}") + case "$value" in + @b64@*) + decoded=$(mktemp) + errors=$(mktemp) + if echo "$value" | cut -c6- | base64 -d > "${decoded}" 2> "${errors}" + then + # shellcheck disable=SC2086 + export ${name}="$(cat ${decoded})" + log_info "Successfully decoded base64 secret \\e[33;1m${name}\\e[0m" + else + fail "Failed decoding base64 secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" + fi + ;; + @hex@*) + decoded=$(mktemp) + errors=$(mktemp) + if echo "$value" | cut -c6- | sed 's/\([0-9A-F]\{2\}\)/\\\\x\1/gI' | xargs printf > "${decoded}" 2> "${errors}" + then + # shellcheck disable=SC2086 + export ${name}="$(cat ${decoded})" + log_info "Successfully decoded hexadecimal secret \\e[33;1m${name}\\e[0m" + else + fail "Failed decoding hexadecimal secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" + fi + ;; + @url@*) + url=$(echo "$value" | cut -c6-) + if command -v curl > /dev/null + then + decoded=$(mktemp) + errors=$(mktemp) + if curl -s -S -f --connect-timeout 5 -o "${decoded}" "$url" 2> "${errors}" + then + # shellcheck disable=SC2086 + export ${name}="$(cat ${decoded})" + log_info "Successfully curl'd secret \\e[33;1m${name}\\e[0m" + else + log_warn "Failed getting secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" + fi + elif command -v wget > /dev/null + then + decoded=$(mktemp) + errors=$(mktemp) + if wget -T 5 -O "${decoded}" "$url" 2> "${errors}" + then + # shellcheck disable=SC2086 + export ${name}="$(cat ${decoded})" + log_info "Successfully wget'd secret \\e[33;1m${name}\\e[0m" + else + log_warn "Failed getting secret \\e[33;1m${name}\\e[0m:\\n$(sed 's/^/... /g' "${errors}")" + fi + else + fail "Couldn't get secret \\e[33;1m${name}\\e[0m: no http client found" + fi + ;; + esac + } + + function eval_all_secrets() { + encoded_vars=$(env | grep -v '^scoped__' | awk -F '=' '/^[a-zA-Z0-9_]*=@(b64|hex|url)@/ {print $1}') + for var in $encoded_vars + do + eval_secret "$var" + done + } + + function maybe_install_packages() { + if command -v apt-get > /dev/null + then + # Debian + if ! dpkg --status "$@" > /dev/null + then + apt-get update + apt-get install --no-install-recommends --yes --quiet "$@" + fi + elif command -v apk > /dev/null + then + # Alpine + if ! apk info --installed "$@" > /dev/null + then + apk add --no-cache "$@" + fi + else + log_error "... didn't find any supported package manager to install $*" + exit 1 + fi + } + function install_bats_libs() { export BATS_LIBRARIES_DIR=/opt/bats/libexec @@ -256,6 +349,13 @@ stages: return fi + if [[ "$https_proxy" || "$HTTPS_PROXY" ]] + then + # BusyBox wget doesn't support proxies and TLS/SSL at the same time: need to use offical full-featured wget instead + + maybe_install_packages wget + fi + # install Bats libraries for lib in $BASH_BATS_LIBRARIES do @@ -267,7 +367,7 @@ stages: target=$(mktemp) # 1: download - log_info " ... download" + log_info " ... download with wget" wget -O "$target" "$lib_url" # 2: unzip @@ -283,12 +383,29 @@ stages: fi done - # debug log - log_info " ... DONE" - ls -lart "$BATS_LIBRARIES_DIR" + if [ -n "${TRACE}" ]; then + # debug log + log_info " ... DONE" + ls -lart "$BATS_LIBRARIES_DIR" + fi + } + + function glob_expand() { + for f in "$@"; do + if [[ "$f" == *[*?[]* ]]; then + # expand pattern with * or ? or [ + find . -path "$f" -type f + elif [[ -f "$f" ]]; then + echo "$f" + else + log_error "File not found: $f" + exit 1 + fi + done } unscope_variables + eval_all_secrets # ENDSCRIPT @@ -296,7 +413,7 @@ stages: stage: build services: - name: "$TBC_TRACKING_IMAGE" - command: ["--service", "bash", "3.4.1"] + command: ["--service", "bash", "3.5.2"] before_script: - !reference [.bash-scripts] - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}" @@ -308,7 +425,8 @@ bash-shellcheck: entrypoint: [""] script: - export LC_ALL=C.UTF-8 - - shellcheck $BASH_SHELLCHECK_OPTS $BASH_SHELLCHECK_FILES + - shellcheck $BASH_SHELLCHECK_OPTS $(glob_expand $BASH_SHELLCHECK_FILES) + rules: - if: '$BASH_SHELLCHECK_DISABLED == "true"' when: never