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
154 changes: 154 additions & 0 deletions .github/workflows/shell-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
name: Shell Script Validation

on:
push:
branches: [ main ]
pull_request:

jobs:
validate-shell-scripts:
runs-on: ubuntu-latest
name: Validate Shell Scripts

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install shellcheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck

- name: Install shfmt
run: |
curl -L -o shfmt https://github.com/mvdan/sh/releases/latest/download/shfmt_v3.7.0_linux_amd64
chmod +x shfmt
sudo mv shfmt /usr/local/bin/

- name: Find shell scripts
id: find-scripts
run: |
echo "Found shell scripts:"
find scripts/ -type f -executable -o -name "*.sh" | tee scripts-list.txt
# Also check files with shell shebangs
find scripts/ -type f -exec grep -l '^#!/bin/sh\|^#!/bin/bash\|^#!/usr/bin/env sh\|^#!/usr/bin/env bash' {} \; | tee -a scripts-list.txt
sort -u scripts-list.txt > unique-scripts.txt
mv unique-scripts.txt scripts-list.txt
cat scripts-list.txt

- name: POSIX Compliance Check (shellcheck)
run: |
echo "Running shellcheck for POSIX compliance..."
exit_code=0
while IFS= read -r script; do
if [ -f "$script" ]; then
echo "Checking $script..."
if ! shellcheck -s sh -e SC1091 -e SC2039 "$script"; then
echo "❌ $script failed POSIX compliance check"
exit_code=1
else
echo "✅ $script passed POSIX compliance check"
fi
echo "---"
fi
done < scripts-list.txt
exit $exit_code

- name: Shell Script Linting (shellcheck extended)
run: |
echo "Running extended shellcheck analysis..."
exit_code=0
while IFS= read -r script; do
if [ -f "$script" ]; then
echo "Linting $script..."
if ! shellcheck -f gcc "$script"; then
echo "❌ $script failed extended linting"
exit_code=1
else
echo "✅ $script passed extended linting"
fi
echo "---"
fi
done < scripts-list.txt
exit $exit_code

- name: Executable Permissions Check
run: |
echo "Checking executable permissions..."
exit_code=0
while IFS= read -r script; do
if [ -f "$script" ]; then
if [ ! -x "$script" ]; then
echo "⚠️ $script is not executable"
exit_code=1
else
echo "✅ $script has correct executable permissions"
fi
fi
done < scripts-list.txt
exit $exit_code

- name: Shebang Validation
run: |
echo "Validating shebangs..."
exit_code=0
while IFS= read -r script; do
if [ -f "$script" ]; then
first_line=$(head -n1 "$script")
case "$first_line" in
"#!/bin/sh"|"#!/usr/bin/env sh")
echo "✅ $script has valid POSIX shebang: $first_line"
;;
"#!/bin/bash"|"#!/usr/bin/env bash")
echo "⚠️ $script uses bash shebang (not POSIX): $first_line"
;;
"#!"*)
echo "❌ $script has non-standard shebang: $first_line"
exit_code=1
;;
*)
echo "❌ $script missing shebang"
exit_code=1
;;
esac
fi
done < scripts-list.txt
exit $exit_code

- name: Security Scan (basic)
run: |
echo "Running basic security checks..."
exit_code=0
while IFS= read -r script; do
if [ -f "$script" ]; then
echo "Security scanning $script..."

# Check for potentially dangerous patterns
if grep -n "eval\|exec\|system\|curl.*|.*sh\|wget.*|.*sh" "$script" | grep -v "^#"; then
echo "⚠️ $script contains potentially dangerous patterns"
fi

# Check for hardcoded credentials patterns
if grep -ni "password\|secret\|token\|key" "$script" | grep -v "^#" | grep "="; then
echo "⚠️ $script may contain hardcoded credentials"
fi

# Check for unquoted variables
if grep -n '\$[A-Za-z_][A-Za-z0-9_]*[^A-Za-z0-9_"]' "$script" | grep -v "^#"; then
echo "⚠️ $script has potentially unquoted variables"
fi

echo "✅ Basic security scan completed for $script"
echo "---"
fi
done < scripts-list.txt
exit $exit_code

- name: Summary Report
if: always()
run: |
echo "=== Shell Script Validation Summary ==="
echo "Scripts validated:"
cat scripts-list.txt | wc -l
echo ""
echo "Validation completed. Check individual step results above for details."
Empty file modified scripts/help
100644 → 100755
Empty file.
5 changes: 4 additions & 1 deletion scripts/install
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ headline() {
check_for_user_confirmation() {
if [ "$INTERACTIVE" = "true" ]; then
echo "Press Enter to continue, or Ctrl+C to cancel..."
# shellcheck disable=SC2034
read -r answer </dev/tty
fi
}
Expand All @@ -97,7 +98,7 @@ get_latest_release_version() {
}

generate_random_password() {
dd if=/dev/urandom bs=1 count=512 2>/dev/null | LC_ALL=C tr -dc '[:alnum:]' | cut -c -"${1:-16}"
dd if=/dev/urandom bs=1 count=512 2>/dev/null | LC_ALL=C tr -dc '[:alnum:]' | cut -c -16
}

generate_random_hex() {
Expand Down Expand Up @@ -174,8 +175,10 @@ install_docker_debian() {
echo "Installing Docker on Debian-like..."
sudo apt-get update -y
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
# shellcheck disable=SC2046,SC1091
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# shellcheck disable=SC1091
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) stable" \
Expand Down
5 changes: 3 additions & 2 deletions scripts/share-logs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if [ -f docker-compose.yml ]; then
echo "Found docker-compose.yml"
else
echo "Could not find docker-compose.yml, trying $INSTALL_DIR"
cd $INSTALL_DIR || exit 1
cd "$INSTALL_DIR" || exit 1
if [ -f docker-compose.yml ]; then
echo "Found docker-compose.yml"
else
Expand All @@ -28,10 +28,11 @@ else
fi

echo "Writing logs to a file..."
# shellcheck disable=SC2024
sudo docker compose logs --timestamps --no-color > logs.txt
echo "Uploading logs to S3..."
LOGS_FILE=$(date +%Y%m%d_%H%M%S).log
curl -fLX PUT --upload-file logs.txt https://openops-client-logs.s3.amazonaws.com/$LOGS_FILE
curl -fLX PUT --upload-file logs.txt "https://openops-client-logs.s3.amazonaws.com/$LOGS_FILE"
echo "Done. File uploaded to https://openops-client-logs.s3.amazonaws.com/$LOGS_FILE"
echo "Please share the following file name with OpenOps: $LOGS_FILE"

Expand Down
8 changes: 5 additions & 3 deletions scripts/tls
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ headline() {
check_for_user_confirmation() {
if [ "$INTERACTIVE" = "true" ]; then
echo "Press Enter to continue, or Ctrl+C to cancel..."
# shellcheck disable=SC2034
read -r answer </dev/tty
fi
}
Expand Down Expand Up @@ -170,6 +171,7 @@ retry() {
}

create_certificates() {
cd "$INSTALL_DIR"
sudo mkdir -p tls/etc tls/var tls/acme
dockercmd run --rm --name certbot \
-v ./tls/etc:/etc/letsencrypt \
Expand All @@ -178,11 +180,11 @@ create_certificates() {
certbot/certbot certonly \
--webroot -w /var/www/acme \
-m "$EMAIL" \
-d $DOMAIN \
-d "$DOMAIN" \
--non-interactive --agree-tos

sudo cp -v tls/etc/live/$DOMAIN/fullchain.pem tls/cert.pem
sudo cp -v tls/etc/live/$DOMAIN/privkey.pem tls/key.pem
sudo cp -v "tls/etc/live/$DOMAIN/fullchain.pem" tls/cert.pem
sudo cp -v "tls/etc/live/$DOMAIN/privkey.pem" tls/key.pem
}

main
Expand Down