Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion bash/aws.sh
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,24 @@ function aws::wait_for_scan_complete {
local repository=${1:?}
local tag=${2:?}
local wait_time=${3:-10}
while ! aws::is_scan_complete "$repository" "$tag"; do
local max_attempts=${4:-30}
local attempt=0
local status
while [ "$attempt" -lt "$max_attempts" ]; do
status=$(aws::scan_status "$repository" "$tag")
if [ "$status" = "COMPLETE" ]; then
return 0
fi
if [ "$status" = "FAILED" ]; then
log::error "ECR image scan FAILED for ${repository}:${tag}"
return 1
fi
log::trace "Waiting for ECR scan ${repository}:${tag} status=${status} attempt=$((attempt + 1))/${max_attempts}"
sleep "$wait_time"
attempt=$((attempt + 1))
done
log::error "Timed out waiting for ECR scan to complete for ${repository}:${tag} after ${max_attempts} attempts (${wait_time}s interval)"
return 1
}

function aws::list_findings {
Expand Down
20 changes: 18 additions & 2 deletions bash/docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,25 @@ function docker::login() {
function docker::registrycmd {
local url=${1:?}
local registry=${2:?}
local config="${HOME}/.docker/config.json"
local basic_token
basic_token=$(docker::_jq -r ".auths.\"$registry\".auth" ~/.docker/config.json)
$(commands::use curl) -s -H "Authorization: Basic $basic_token" "https://$registry/v2/$url"
if [ ! -r "$config" ]; then
log::error "Docker config missing or unreadable: $config (try: docker login $registry)"
return 1
fi
# shellcheck disable=SC2016 # jq filter: $reg is a jq binding from --arg, not bash.
if ! basic_token=$(
docker::_jq -r --arg reg "$registry" \
'(.auths[$reg] // {}).auth // empty' "$config"
); then
log::error "Could not read docker auth for registry '$registry' from $config"
return 1
fi
if [ -z "$basic_token" ] || [ "$basic_token" = "null" ]; then
log::error "No docker credentials for registry '$registry' in $config (try: docker login $registry)"
return 1
fi
$(commands::use curl) -fsS -H "Authorization: Basic $basic_token" "https://$registry/v2/$url"
}

function docker::list_repositories {
Expand Down
2 changes: 1 addition & 1 deletion bash/on-change
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ options::description "A makeshift minimal CI system. It watches a directory for\
working directory. While running, type X<Enter> on stdin to force an immediate\
re-run without waiting for a filesystem change."
options::add -o W -d "directory to watch for changes" -a -m -e WatchDir
options::add -o w -d "working directory" -a -m -e WorkingDir
options::add -o w -d "working directory (defaults to watch directory)" -a -e WorkingDir
options::add -o t -d "interval to check for changes" -a -m -e WaitTime
options::parse "$@"
shift "$((OPTIND - 1))"
Expand Down
42 changes: 40 additions & 2 deletions bash/options.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,30 @@ declare -g -A OPTIONS_OPTIONAL
declare -g -A OPTIONS_HAS_ARGS
declare -g -A OPTIONS_PARSE_FUNCS
declare -g -A OPTIONS_ENVIRONMENT
declare -g -A OPTIONS_SEEN
declare -g OPTIONS_DESCRIPTION

function options::_mandatory_options_validate() {
local opt
local varName
for opt in "${OPTIONS[@]}"; do
[ "${OPTIONS_OPTIONAL[$opt]}" = "true" ] && continue
if [ "${OPTIONS_SEEN[$opt]:-0}" != "1" ]; then
log::error "Missing required option: -$opt"
options::syntax_exit
fi
if [ "${OPTIONS_HAS_ARGS[$opt]}" = "true" ]; then
varName="${OPTIONS_ENVIRONMENT[$opt]:-}"
if [ -n "$varName" ]; then
if [ -z "${!varName}" ]; then
log::error "Required option -$opt cannot be empty"
options::syntax_exit
fi
fi
fi
done
}

function options::syntax_exit() {
@doc Print the command syntax and exit
# Use BASH_SOURCE[-1] (bottom of the call stack = entry script) instead
Expand All @@ -49,6 +71,7 @@ function options::clear() {
OPTIONS_HAS_ARGS=()
OPTIONS_PARSE_FUNCS=()
OPTIONS_ENVIRONMENT=()
OPTIONS_SEEN=()
OPTIONS_DESCRIPTION=""
options::add -o h -d "prints syntax and exits" -f options::syntax_exit &&
HELP_OPT_ADDED="true"
Expand Down Expand Up @@ -242,20 +265,34 @@ function options::standard() {
function options::parse_available() {
@doc parse the options using the provided argument array
@arg "$@" the provided argument array
OPTIONS_SEEN=()
while options::getopts opt "$@"; do
if [ "$opt" != "?" ]; then
OPTIONS_SEEN[$opt]=1
if [ -n "${OPTIONS_ENVIRONMENT[$opt]}" ]; then
local varName="${OPTIONS_ENVIRONMENT[$opt]}"
local val
if [ -n "${OPTARG}" ]; then
if [ "${OPTIONS_HAS_ARGS[$opt]}" = "true" ]; then
val="${OPTARG-}"
if [ "${OPTIONS_OPTIONAL[$opt]}" != "true" ] && [ -z "$val" ]; then
log::error "Required option -$opt cannot be empty"
options::syntax_exit
fi
elif [ -n "${OPTARG}" ]; then
val="${OPTARG}"
else
val="true"
fi
declare -g "$varName=${val}"
elif [ -n "${OPTIONS_PARSE_FUNCS[$opt]}" ]; then
if [ "${OPTIONS_OPTIONAL[$opt]}" != "true" ] &&
[ "${OPTIONS_HAS_ARGS[$opt]}" = "true" ] &&
[ -z "${OPTARG-}" ]; then
log::error "Required option -$opt cannot be empty"
options::syntax_exit
fi
if command -v "${OPTIONS_PARSE_FUNCS[$opt]}" >/dev/null; then
${OPTIONS_PARSE_FUNCS[$opt]} "${OPTARG}"
${OPTIONS_PARSE_FUNCS[$opt]} "${OPTARG-}"
else
echo "ERROR: for option ($opt) parse_functions must be defined or left out"
exit 1
Expand All @@ -265,6 +302,7 @@ function options::parse_available() {
return 1
fi
done
options::_mandatory_options_validate
}

function options::parse() {
Expand Down
12 changes: 11 additions & 1 deletion bash/pagerduty.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ function pagerduty::send_incident() {
local incident_key="${6}"

local rc=0
local incident_payload
incident_payload=$(
pagerduty::_incident_data "$service_id" "$alert_type" "$alert_title" "$incident_key"
)
local xtrace_was_on=0
case $- in *x*) xtrace_was_on=1 ;; esac
{ set +x; } 2>/dev/null
# --fail-with-body needs curl >= 7.76.0 (Apr 2021). On older hosts curl
# exits non-zero with "option unknown" — caller still sees a non-zero rc
# below, just with a less specific error body than --fail-with-body
Expand All @@ -77,8 +84,11 @@ function pagerduty::send_incident() {
--header 'Accept: application/vnd.pagerduty+json;version=2' \
--header "From: $alert_from" \
--header "Authorization: Token token=$alert_token" \
--data "$(pagerduty::_incident_data "$service_id" "$alert_type" "$alert_title" "$incident_key")" \
--data "$incident_payload" \
"${PAGERDUTY_INCIDENTS_URL:-https://api.pagerduty.com/incidents}" || rc=$?
if [ "$xtrace_was_on" -eq 1 ]; then
set -x
fi
if [ "$rc" -ne 0 ]; then
log::error "PagerDuty incident send failed (curl rc=$rc)"
return "$rc"
Expand Down
5 changes: 0 additions & 5 deletions bash/release-images
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ source "$(dirname "${BASH_SOURCE[0]}")/includer.sh"
@include options
@include docker

log::level 2
function usage() {
true
}

additional_registries=()
function _add_additional_registry {
local registry=${1:?}
Expand Down
9 changes: 6 additions & 3 deletions bash/switch-to-branch
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@ for d in "$TARGET_DIR"/*; do
log::warn "Cannot cd to $d"
continue
fi
if [ "$NEW_BRANCH" = "true" ] && exec::hide git::cmd checkout -b \
"$BRANCH" "$@"; then
log::info "Checked out into new branch $BRANCH in $d"
if [ "$NEW_BRANCH" = "true" ]; then
if _new_branch_err=$(git::cmd checkout -b "$BRANCH" "$@" 2>&1); then
log::info "Checked out into new branch $BRANCH in $d"
else
log::warn "Failed to create new branch $BRANCH in $d — $_new_branch_err; not falling back to checkout of an existing branch"
fi
elif exec::hide git::cmd checkout "$BRANCH" "$@"; then
log::info "Checked out $BRANCH in $d"
else
Expand Down
24 changes: 24 additions & 0 deletions tests/aws.bats
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,27 @@ setup() {
"
[ "$status" -ne 0 ]
}

@test "aws::wait_for_scan_complete returns non-zero after bounded attempts when stuck (SUR-2340)" {
run bash -c "
export LOG_DISABLE_TRACE=true
source '$REPO_ROOT/bash/includer.sh'
@include aws
aws::scan_status() { echo 'IN_PROGRESS'; }
sleep() { :; }
aws::wait_for_scan_complete myrepo mytag 0 5
"
[ "$status" -ne 0 ]
}

@test "aws::wait_for_scan_complete returns non-zero promptly on FAILED status (SUR-2340)" {
run bash -c "
export LOG_DISABLE_TRACE=true
source '$REPO_ROOT/bash/includer.sh'
@include aws
aws::scan_status() { echo 'FAILED'; }
sleep() { :; }
aws::wait_for_scan_complete myrepo mytag 0 99
"
[ "$status" -ne 0 ]
}
13 changes: 13 additions & 0 deletions tests/docker.bats
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,16 @@ run_cp() {
[[ "$output" == *"jq is either not installed or not on the PATH"* ]]
[[ "$output" != *"-r: command not found"* ]]
}

@test "docker::registrycmd fails with empty docker config auth for registry (SUR-2337)" {
run bash -c "
export LOGFILE_DISABLE=true
mkdir -p \"\$HOME/.docker\"
printf '%s\n' '{}' > \"\$HOME/.docker/config.json\"
source '$REPO_ROOT/bash/includer.sh'
@include docker
docker::registrycmd _catalog 'registry.example.invalid'
"
[ "$status" -ne 0 ]
[[ "$output" == *"No docker credentials"* ]] || [[ "$output" == *"docker login"* ]]
}
4 changes: 2 additions & 2 deletions tests/kind-test-environment.bats
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ teardown() {
"HELM_ARGV_LOG=$HELM_ARGV_LOG" \
"KIND_TEST_ENVIRONMENT_SOURCE_ONLY=true" \
bash -c "
source '$REPO_ROOT/bash/kind-test-environment' -c create
source '$REPO_ROOT/bash/kind-test-environment' -c create -f /dev/null
# Reset after source so the script's own repo defaults don't
# contaminate the test's controlled list.
ADD_HELM_REPOS=(
Expand Down Expand Up @@ -71,7 +71,7 @@ STUB_EOF
"PATH=$PATH" \
"KIND_TEST_ENVIRONMENT_SOURCE_ONLY=true" \
bash -c "
source '$REPO_ROOT/bash/kind-test-environment' -c create
source '$REPO_ROOT/bash/kind-test-environment' -c create -f /dev/null
::asdf kind
[ -z \"\${_asdf:-}\" ] || { echo '_asdf leaked' >&2; exit 1; }
[ -z \"\${_where:-}\" ] || { echo '_where leaked' >&2; exit 1; }
Expand Down
24 changes: 24 additions & 0 deletions tests/options.bats
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,27 @@ setup() {
[[ "$output" == *"a|optional=false|env=A"* ]]
[[ "$output" == *"b|optional=true|env=B"* ]]
}

@test "options::parse_available fails when mandatory -m option is absent (SUR-2322)" {
run bash -c "
source '$REPO_ROOT/bash/includer.sh'
@include options
options::clear
options::add -o l -d 'label' -a -m -e LabelSelector
NO_SYNTAX_EXIT=1 options::parse_available
"
[ "$status" -ne 0 ]
[[ "$output" == *"Missing required option: -l"* ]]
}

@test "options::parse_available fails when mandatory option argument is empty (SUR-2322)" {
run bash -c "
source '$REPO_ROOT/bash/includer.sh'
@include options
options::clear
options::add -o l -d 'label' -a -m -e LabelSelector
NO_SYNTAX_EXIT=1 options::parse_available -l ''
"
[ "$status" -ne 0 ]
[[ "$output" == *"Required option -l cannot be empty"* ]]
}
20 changes: 20 additions & 0 deletions tests/pagerduty.bats
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,23 @@ setup() {
[[ "$output" == *"svc1"* ]]
[[ "$output" == *"key-1"* ]]
}

@test "pagerduty::send_incident does not emit Token token= secret in xtrace (SUR-2339)" {
run bash -c "
trace=\$(mktemp)
trap 'rm -f \"\$trace\"' EXIT
source '$REPO_ROOT/bash/includer.sh'
@include pagerduty
pagerduty::_curl() { return 0; }
exec 2>\"\$trace\"
set -x
pagerduty::send_incident SVC1 incident T from 'PD_TOKEN_SUR2339_XYZ' ''
set +x
exec 2>&1
if grep -F 'Token token=PD_TOKEN_SUR2339_XYZ' \"\$trace\"; then
exit 1
fi
exit 0
"
[ "$status" -eq 0 ]
}
11 changes: 11 additions & 0 deletions tests/switch-to-branch.bats
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,14 @@ setup() {
[ -z "$(git -C "$HOME/git/myorg/repo1" status --porcelain)" ]
[ -z "$(git -C "$HOME/git/myorg/repo2" status --porcelain)" ]
}

@test "switch-to-branch -n does not checkout existing branch when create fails (SUR-2334)" {
git -C "$HOME/git/myorg/repo1" branch -f sur2334-newb main >/dev/null
run "$SWITCH" -o myorg -n -b sur2334-newb -v
[ "$status" -eq 0 ]
branch1=$(git -C "$HOME/git/myorg/repo1" rev-parse --abbrev-ref HEAD)
[ "$branch1" = "main" ]
[[ "$output" == *"Failed to create new branch sur2334-newb"* ]]
[ ! -f "$HOME/git/myorg/repo1/exec.log" ]
[ ! -f "$HOME/git/myorg/repo2/exec.log" ]
}
Loading