set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/util.sh"
assert_cmd yq
assert_cmd find
found_embedded=0
info "Checking GitHub Actions workflows for embedded bash scripts..."
mapfile -t workflow_files < <(find .github/workflows -type f -name '*.yml' | sort)
check_run_command() {
local run_content="$1"
local line_count
if [[ ${run_content} == *"./scripts/ci/"* ]]; then
return 1
fi
line_count=$(printf '%s' "${run_content}" | grep -c '^' || true)
if [ "${line_count}" -ge 3 ]; then
return 0 fi
if [[ ${run_content} =~ \&\&.*\&\& ]]; then
return 0 fi
if [[ ${run_content} =~ \;.*[^[:space:]] ]] && [[ ! ${run_content} =~ ^[[:space:]]*for[[:space:]] ]]; then
return 0 fi
local pipe_count
pipe_count=$(printf '%s\n' "${run_content}" | tr -cd '|' | wc -c)
if [ "${pipe_count}" -ge 2 ]; then
return 0 fi
return 1 }
report_issue() {
local run_cmd="$1"
local issue_line_count
local preview
issue_line_count=$(printf '%s' "${run_cmd}" | grep -c '^' || true)
if [ "${issue_line_count}" -ge 4 ]; then
warn " Multi-line bash block detected (${issue_line_count} lines)"
elif [[ ${run_cmd} =~ \&\&.*\&\& ]]; then
warn " Complex command chain detected"
elif [[ ${run_cmd} =~ \;.*[^[:space:]] ]]; then
warn " Semicolon-separated commands detected"
else
warn " Complex piped command detected"
fi
preview="${run_cmd:0:80}"
preview="${preview//$'\n'/ }"
warn " Preview: ${preview}..."
}
for workflow in "${workflow_files[@]}"; do
workflow_has_issues=0
step_count=$(yq eval '[.jobs[].steps[]? | select(.run)] | length' "${workflow}" 2>/dev/null || echo "0")
for ((i = 0; i < step_count; i++)); do
run_cmd=$(yq eval "[.jobs[].steps[]? | select(.run)] | .[${i}].run" "${workflow}" 2>/dev/null)
[ -z "${run_cmd}" ] && continue
if check_run_command "${run_cmd}"; then
if [ ${workflow_has_issues} -eq 0 ]; then
warn "Issues found in ${workflow}:"
workflow_has_issues=1
found_embedded=1
fi
report_issue "${run_cmd}"
fi
done
done
if [ ${found_embedded} -eq 1 ]; then
err "Embedded bash scripts detected in workflows. Consider extracting complex bash logic to scripts in scripts/ci/."
else
info "No embedded bash scripts found in workflows!"
exit 0
fi