frappe_docker/production/scripts/validate-env.sh
duthink f167e83bda Add production environment configuration and deployment scripts for ERPNext
- Created example environment files for MariaDB and production settings.
- Implemented backup script for ERPNext sites with options for file inclusion, compression, and encryption.
- Developed site creation script to streamline ERPNext site setup with admin password handling.
- Added deployment script to manage the deployment of ERPNext, MariaDB, and Traefik services.
- Introduced log viewing script for monitoring ERPNext services.
- Implemented stop script to manage stopping of ERPNext and its dependencies.
- Added validation script to check environment configuration for common issues and security best practices.
2025-11-13 15:32:30 +05:30

249 lines
No EOL
7.8 KiB
Bash

#!/bin/bash
# Validate Environment Configuration Script
# Checks for common issues in production env files
set -euo pipefail
# Colors
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m'
# Counters
errors=0
warnings=0
# Logging functions
echo_info() { echo -e "${GREEN}${NC} $1"; }
echo_warn() { echo -e "${YELLOW}${NC} $1"; ((warnings++)); }
echo_error() { echo -e "${RED}${NC} $1"; ((errors++)); }
# Validation patterns
readonly WEAK_PASSWORDS="changeit|123456|admin123|password123|qwerty|letmein|welcome"
readonly PLACEHOLDER_DOMAINS="yourdomain\.com|example\.com|localhost"
readonly EMAIL_REGEX="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
# Get script directory and change to production directory
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly PRODUCTION_DIR="$(dirname "$SCRIPT_DIR")"
cd "$PRODUCTION_DIR"
# Validate single environment file
validate_env_file() {
local file="$1"
local required_vars=("${@:2}")
echo "Checking $file..."
if [[ ! -f "$file" ]]; then
echo_error "$file not found"
echo " Create it from ${file}.example or run setup script"
return 1
fi
if [[ ! -s "$file" ]]; then
echo_error "$file is empty"
return 1
fi
echo_info "File exists"
# Read file content once
local content
content=$(grep -v "^\s*#" "$file" 2>/dev/null | grep "=" || true)
# Check placeholders
if echo "$content" | grep -q "CHANGEME_"; then
echo_error "Contains CHANGEME_ placeholders"
echo "$content" | grep "CHANGEME_" | sed 's/^/ /'
return 1
fi
echo_info "No CHANGEME_ placeholders"
# Check weak passwords
echo "$content" | cut -d'=' -f2- | grep -qi "$WEAK_PASSWORDS" && echo_warn "Contains weak passwords"
# Check required variables
local missing_vars=()
for var in "${required_vars[@]}"; do
echo "$content" | grep -q "^$var=" || missing_vars+=("$var")
done
[[ ${#missing_vars[@]} -gt 0 ]] && { echo_error "Missing: ${missing_vars[*]}"; return 1; }
return 0
}
# Validate email
validate_email() {
local email="$1" var_name="$2"
[[ ! "$email" =~ $EMAIL_REGEX ]] && { echo_error "$var_name invalid: $email"; return 1; }
echo "$email" | grep -q "$PLACEHOLDER_DOMAINS" && { echo_error "$var_name has placeholder"; return 1; }
return 0
}
# Validate password strength
validate_password_strength() {
local password="$1" min_length="${2:-16}"
if [[ ${#password} -lt $min_length ]]; then
echo_warn "Password < $min_length chars (current: ${#password})"
return 1
fi
echo_info "Password length good (${#password} chars)"
return 0
}
# Extract value from env file
get_env_value() {
local file="$1"
local var="$2"
grep "^$var=" "$file" 2>/dev/null | cut -d'=' -f2- || echo ""
}
# Main validation
main() {
# Handle help
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then
cat << EOF
Usage: $0
Validates ERPNext production environment configuration files.
Checks:
- production.env (DB_PASSWORD, SITES, LETSENCRYPT_EMAIL)
- traefik.env (TRAEFIK_DOMAIN, EMAIL, HASHED_PASSWORD)
- mariadb.env (DB_PASSWORD)
- Password strength and cross-file consistency
- Placeholder and weak password detection
Exit Codes:
0 - Validation passed
1 - Validation failed (errors found)
Examples:
$0 # Validate all env files
Run before deployment to catch configuration issues.
EOF
exit 0
fi
echo "🔍 Validating Production Environment Configuration"
echo "=================================================="
echo ""
# Validate production.env
if validate_env_file "production.env" "DB_PASSWORD" "DB_HOST" "LETSENCRYPT_EMAIL" "SITES"; then
# Additional production.env validations
local letsencrypt_email
letsencrypt_email=$(get_env_value "production.env" "LETSENCRYPT_EMAIL")
if [[ -n "$letsencrypt_email" ]]; then
validate_email "$letsencrypt_email" "LETSENCRYPT_EMAIL"
fi
# Check SITES format
local sites
sites=$(get_env_value "production.env" "SITES")
if [[ -n "$sites" ]] && [[ ! "$sites" =~ ^\`.*\`$ ]]; then
echo_warn "SITES should be wrapped in backticks: SITES=\`erp.example.com\`"
fi
# Validate DB password strength
local db_password
db_password=$(get_env_value "production.env" "DB_PASSWORD")
if [[ -n "$db_password" ]]; then
validate_password_strength "$db_password"
fi
fi
echo ""
# Validate traefik.env
if validate_env_file "traefik.env" "TRAEFIK_DOMAIN" "EMAIL" "HASHED_PASSWORD"; then
# Additional traefik.env validations
local traefik_email
traefik_email=$(get_env_value "traefik.env" "EMAIL")
if [[ -n "$traefik_email" ]]; then
validate_email "$traefik_email" "EMAIL"
fi
# Check if password is properly hashed
local hashed_password
hashed_password=$(get_env_value "traefik.env" "HASHED_PASSWORD")
if [[ -n "$hashed_password" ]] && echo "$hashed_password" | grep -q "openssl\|changeit"; then
echo_error "HASHED_PASSWORD not properly set"
echo " Generate with: openssl passwd -apr1 yourpassword"
fi
# Check if HASHED_PASSWORD has username prefix (it shouldn't)
if [[ -n "$hashed_password" ]] && echo "$hashed_password" | grep -q "^admin:"; then
echo_error "HASHED_PASSWORD should NOT include 'admin:' prefix"
echo_warn "Remove 'admin:' from the hash in traefik.env"
echo_warn "The compose file adds it automatically"
fi
# Check domain format
local traefik_domain
traefik_domain=$(get_env_value "traefik.env" "TRAEFIK_DOMAIN")
if [[ -n "$traefik_domain" ]] && echo "$traefik_domain" | grep -q "$PLACEHOLDER_DOMAINS"; then
echo_error "TRAEFIK_DOMAIN still has placeholder domain"
fi
fi
echo ""
# Validate mariadb.env
validate_env_file "mariadb.env" "DB_PASSWORD"
echo ""
# Cross-file validation
echo "Cross-checking configurations..."
if [[ -f "production.env" && -f "mariadb.env" ]]; then
local prod_pass maria_pass
prod_pass=$(get_env_value "production.env" "DB_PASSWORD")
maria_pass=$(get_env_value "mariadb.env" "DB_PASSWORD")
if [[ -n "$prod_pass" && -n "$maria_pass" ]]; then
if [[ "$prod_pass" == "$maria_pass" ]]; then
echo_info "Database passwords match"
else
echo_error "Database passwords DO NOT match between files"
# Don't expose actual passwords in logs
fi
fi
fi
# Final summary
echo ""
echo "=================================================="
echo "Validation Summary"
echo "=================================================="
echo ""
if (( errors > 0 )); then
echo -e "${RED}❌ Validation Failed${NC}"
echo " Errors: $errors"
echo " Warnings: $warnings"
echo ""
echo "Please fix the errors above before deploying."
exit 1
elif (( warnings > 0 )); then
echo -e "${YELLOW}⚠️ Validation Passed with Warnings${NC}"
echo " Warnings: $warnings"
echo ""
echo "Consider addressing the warnings for better security."
exit 0
else
echo -e "${GREEN}✅ Validation Passed${NC}"
echo " No errors or warnings found."
echo ""
echo "You can now proceed with deployment:"
echo " ./scripts/deploy.sh"
exit 0
fi
}
# Run main function
main "$@"