Files
michaelschiemer/deployment/lib/config-manager.sh
Michael Schiemer 9b74ade5b0 feat: Fix discovery system critical issues
Resolved multiple critical discovery system issues:

## Discovery System Fixes
- Fixed console commands not being discovered on first run
- Implemented fallback discovery for empty caches
- Added context-aware caching with separate cache keys
- Fixed object serialization preventing __PHP_Incomplete_Class

## Cache System Improvements
- Smart caching that only caches meaningful results
- Separate caches for different execution contexts (console, web, test)
- Proper array serialization/deserialization for cache compatibility
- Cache hit logging for debugging and monitoring

## Object Serialization Fixes
- Fixed DiscoveredAttribute serialization with proper string conversion
- Sanitized additional data to prevent object reference issues
- Added fallback for corrupted cache entries

## Performance & Reliability
- All 69 console commands properly discovered and cached
- 534 total discovery items successfully cached and restored
- No more __PHP_Incomplete_Class cache corruption
- Improved error handling and graceful fallbacks

## Testing & Quality
- Fixed code style issues across discovery components
- Enhanced logging for better debugging capabilities
- Improved cache validation and error recovery

Ready for production deployment with stable discovery system.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-13 12:04:17 +02:00

510 lines
16 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Configuration Management System for Custom PHP Framework
# Template management, validation, and secure credential handling
# Domain: michaelschiemer.de | Email: kontakt@michaelschiemer.de | PHP: 8.4
set -euo pipefail
# Configuration manager constants
DEPLOYMENT_DIR="${DEPLOYMENT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../" && pwd)}"
CONFIG_TEMPLATES_DIR="${DEPLOYMENT_DIR}/applications/environments"
CONFIG_CREDENTIALS_DIR="${DEPLOYMENT_DIR}/.credentials"
CONFIG_BACKUP_DIR="${DEPLOYMENT_DIR}/.backups"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Logging
log() { echo -e "${GREEN}[CONFIG] ✅ $1${NC}"; }
warn() { echo -e "${YELLOW}[CONFIG] ⚠️ $1${NC}"; }
error() { echo -e "${RED}[CONFIG] ❌ $1${NC}"; }
info() { echo -e "${BLUE}[CONFIG] $1${NC}"; }
# Initialize configuration directories
init_config_directories() {
mkdir -p "$CONFIG_CREDENTIALS_DIR" "$CONFIG_BACKUP_DIR"
chmod 700 "$CONFIG_CREDENTIALS_DIR" "$CONFIG_BACKUP_DIR"
}
# Generate secure password
generate_password() {
local length=${1:-25}
local type=${2:-"alphanumeric"}
case $type in
"alphanumeric")
openssl rand -base64 $((length * 3 / 4)) | tr -d "=+/" | cut -c1-"$length"
;;
"base64")
openssl rand -base64 "$length"
;;
"hex")
openssl rand -hex $((length / 2))
;;
"strong")
# Strong password with special characters
openssl rand -base64 "$length" | tr -d "=+/" | head -c"$length"
;;
*)
error "Unknown password type: $type"
return 1
;;
esac
}
# Generate all required credentials for an environment
generate_environment_credentials() {
local environment=$1
local creds_file="${CONFIG_CREDENTIALS_DIR}/${environment}.env"
info "Generating secure credentials for $environment environment..."
# Backup existing credentials if they exist
if [[ -f "$creds_file" ]]; then
local backup_file="${CONFIG_BACKUP_DIR}/${environment}.env.backup.$(date +%Y%m%d_%H%M%S)"
cp "$creds_file" "$backup_file"
warn "Existing credentials backed up to: $backup_file"
fi
# Generate credentials based on environment
cat > "$creds_file" << EOF
# Generated Credentials for $environment Environment
# Created: $(date)
# Custom PHP Framework Deployment
# Database Credentials
DB_PASSWORD=$(generate_password 25 alphanumeric)
DB_ROOT_PASSWORD=$(generate_password 25 alphanumeric)
# Redis Credentials
REDIS_PASSWORD=$(generate_password 25 alphanumeric)
# Application Security
APP_KEY=$(generate_password 32 base64)
CSRF_SECRET=$(generate_password 32 hex)
# Session Security
SESSION_SECRET=$(generate_password 32 base64)
# API Security
API_SECRET=$(generate_password 32 hex)
JWT_SECRET=$(generate_password 32 base64)
# External API Credentials
SHOPIFY_WEBHOOK_SECRET=$(generate_password 64 hex)
MAIL_API_KEY=$(generate_password 32 alphanumeric)
EOF
# Environment-specific credentials
if [[ "$environment" == "production" ]]; then
cat >> "$creds_file" << EOF
# Production-specific Credentials
GRAFANA_ADMIN_PASSWORD=$(generate_password 16 strong)
MONITORING_API_KEY=$(generate_password 32 hex)
BACKUP_ENCRYPTION_KEY=$(generate_password 32 base64)
SSL_PASSPHRASE=$(generate_password 20 strong)
EOF
fi
# Set secure permissions
chmod 600 "$creds_file"
success "Credentials generated: $creds_file"
return 0
}
# Load credentials from file
load_credentials() {
local environment=$1
local creds_file="${CONFIG_CREDENTIALS_DIR}/${environment}.env"
if [[ ! -f "$creds_file" ]]; then
error "Credentials file not found: $creds_file"
return 1
fi
# Source the credentials file
set -a # Export all variables
source "$creds_file"
set +a
info "Credentials loaded for $environment environment"
}
# Validate environment template
validate_template() {
local template_file=$1
if [[ ! -f "$template_file" ]]; then
error "Template file not found: $template_file"
return 1
fi
info "Validating template: $(basename "$template_file")"
# Check for required placeholders
local required_placeholders=(
"*** REQUIRED ***"
"DOMAIN_NAME="
"APP_ENV="
"DB_PASSWORD="
"APP_KEY="
)
local missing_placeholders=()
for placeholder in "${required_placeholders[@]}"; do
if ! grep -q "$placeholder" "$template_file"; then
missing_placeholders+=("$placeholder")
fi
done
if [[ ${#missing_placeholders[@]} -gt 0 ]]; then
error "Template missing required placeholders:"
printf ' - %s\n' "${missing_placeholders[@]}"
return 1
fi
success "Template validation passed"
return 0
}
# Apply configuration to template
apply_configuration() {
local environment=$1
local domain=$2
local email=$3
local additional_vars="${4:-}"
local template_file="${CONFIG_TEMPLATES_DIR}/${environment}.env.template"
local output_file="${CONFIG_TEMPLATES_DIR}/.env.${environment}"
local creds_file="${CONFIG_CREDENTIALS_DIR}/${environment}.env"
info "Creating $environment configuration from template..."
# Validate template first
if ! validate_template "$template_file"; then
return 1
fi
# Backup existing config
if [[ -f "$output_file" ]]; then
local backup_file="${CONFIG_BACKUP_DIR}/.env.${environment}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$output_file" "$backup_file"
warn "Existing config backed up to: $backup_file"
fi
# Copy template to output
cp "$template_file" "$output_file"
# Apply basic configuration
sed -i "s|DOMAIN_NAME=.*|DOMAIN_NAME=${domain}|g" "$output_file"
sed -i "s|MAIL_FROM_ADDRESS=.*|MAIL_FROM_ADDRESS=${email}|g" "$output_file"
sed -i "s|your-domain\.com|${domain}|g" "$output_file"
sed -i "s|your-email@example\.com|${email}|g" "$output_file"
# Apply environment-specific settings
case $environment in
"production")
sed -i 's|APP_DEBUG=.*|APP_DEBUG=false|g' "$output_file"
sed -i 's|LOG_LEVEL=.*|LOG_LEVEL=warning|g' "$output_file"
sed -i 's|APP_ENV=.*|APP_ENV=production|g' "$output_file"
;;
"staging")
sed -i 's|APP_DEBUG=.*|APP_DEBUG=false|g' "$output_file"
sed -i 's|LOG_LEVEL=.*|LOG_LEVEL=info|g' "$output_file"
sed -i 's|APP_ENV=.*|APP_ENV=staging|g' "$output_file"
;;
"development")
sed -i 's|APP_DEBUG=.*|APP_DEBUG=true|g' "$output_file"
sed -i 's|LOG_LEVEL=.*|LOG_LEVEL=debug|g' "$output_file"
sed -i 's|APP_ENV=.*|APP_ENV=development|g' "$output_file"
;;
esac
# Apply credentials if available
if [[ -f "$creds_file" ]]; then
info "Applying generated credentials..."
# Load credentials
while IFS='=' read -r key value; do
# Skip comments and empty lines
[[ $key =~ ^#.*$ ]] || [[ -z $key ]] && continue
# Remove any existing quotes
value=$(echo "$value" | sed 's/^["'\'']*//;s/["'\'']*$//')
# Apply to config
if grep -q "^${key}=" "$output_file"; then
sed -i "s|^${key}=.*|${key}=${value}|g" "$output_file"
elif grep -q "${key}=\*\*\* REQUIRED \*\*\*" "$output_file"; then
sed -i "s|${key}=\*\*\* REQUIRED \*\*\*|${key}=${value}|g" "$output_file"
fi
done < <(grep -v '^#' "$creds_file" | grep '=' || true)
fi
# Apply additional variables if provided
if [[ -n "$additional_vars" ]]; then
info "Applying additional configuration variables..."
# Parse additional_vars as key=value pairs
echo "$additional_vars" | tr ' ' '\n' | while IFS='=' read -r key value; do
if [[ -n "$key" && -n "$value" ]]; then
sed -i "s|^${key}=.*|${key}=${value}|g" "$output_file"
fi
done
fi
# Set secure permissions
chmod 600 "$output_file"
success "Configuration created: $output_file"
return 0
}
# Validate configuration file
validate_configuration() {
local config_file=$1
if [[ ! -f "$config_file" ]]; then
error "Configuration file not found: $config_file"
return 1
fi
info "Validating configuration: $(basename "$config_file")"
# Check for remaining placeholders
local remaining_placeholders
remaining_placeholders=$(grep "*** REQUIRED ***" "$config_file" || true)
if [[ -n "$remaining_placeholders" ]]; then
error "Configuration contains unfilled placeholders:"
echo "$remaining_placeholders"
return 1
fi
# Check for critical configuration
local required_vars=(
"APP_ENV"
"DOMAIN_NAME"
"DB_PASSWORD"
"APP_KEY"
)
local missing_vars=()
for var in "${required_vars[@]}"; do
if ! grep -q "^${var}=" "$config_file"; then
missing_vars+=("$var")
fi
done
if [[ ${#missing_vars[@]} -gt 0 ]]; then
error "Configuration missing required variables:"
printf ' - %s\n' "${missing_vars[@]}"
return 1
fi
# Load and validate specific values
local app_env
app_env=$(grep "^APP_ENV=" "$config_file" | cut -d'=' -f2 | tr -d '"')
if [[ "$app_env" == "production" ]]; then
# Additional production validation
local debug_mode
debug_mode=$(grep "^APP_DEBUG=" "$config_file" | cut -d'=' -f2 | tr -d '"')
if [[ "$debug_mode" == "true" ]]; then
warn "Debug mode is enabled in production configuration"
fi
# Check password strength
local db_password
db_password=$(grep "^DB_PASSWORD=" "$config_file" | cut -d'=' -f2 | tr -d '"')
if [[ ${#db_password} -lt 16 ]]; then
error "Database password too short for production (minimum 16 characters)"
return 1
fi
fi
success "Configuration validation passed"
return 0
}
# List available configurations
list_configurations() {
info "Available configurations:"
for env_file in "${CONFIG_TEMPLATES_DIR}/.env."*; do
if [[ -f "$env_file" && ! "$env_file" =~ \.template$ && ! "$env_file" =~ \.backup ]]; then
local env_name
env_name=$(basename "$env_file" | sed 's/\.env\.//')
local app_env domain
app_env=$(grep "^APP_ENV=" "$env_file" | cut -d'=' -f2 | tr -d '"' || echo "unknown")
domain=$(grep "^DOMAIN_NAME=" "$env_file" | cut -d'=' -f2 | tr -d '"' || echo "unknown")
echo "$env_name: $app_env environment for $domain"
fi
done
info "Available credentials:"
for creds_file in "${CONFIG_CREDENTIALS_DIR}"/*.env; do
if [[ -f "$creds_file" ]]; then
local env_name
env_name=$(basename "$creds_file" .env)
local created
created=$(stat -c %y "$creds_file" 2>/dev/null | cut -d' ' -f1 || echo "unknown")
echo "$env_name: created $created"
fi
done
}
# Rotate credentials
rotate_credentials() {
local environment=$1
warn "Rotating credentials for $environment environment..."
warn "This will generate new passwords and invalidate existing ones!"
printf "Continue with credential rotation? [y/N]: "
read -r confirm
if [[ ! $confirm =~ ^[Yy]$ ]]; then
info "Credential rotation cancelled"
return 0
fi
generate_environment_credentials "$environment"
success "Credentials rotated for $environment environment"
warn "You must redeploy the application for changes to take effect!"
}
# Backup configurations
backup_configurations() {
local backup_name="config_backup_$(date +%Y%m%d_%H%M%S)"
local backup_path="${CONFIG_BACKUP_DIR}/${backup_name}"
info "Creating configuration backup: $backup_name"
mkdir -p "$backup_path"
# Backup environment files
cp -r "$CONFIG_TEMPLATES_DIR" "${backup_path}/environments"
# Backup credentials (if they exist)
if [[ -d "$CONFIG_CREDENTIALS_DIR" && "$(ls -A "$CONFIG_CREDENTIALS_DIR" 2>/dev/null)" ]]; then
cp -r "$CONFIG_CREDENTIALS_DIR" "${backup_path}/credentials"
fi
# Create backup manifest
cat > "${backup_path}/manifest.txt" << EOF
Configuration Backup: $backup_name
Created: $(date)
Custom PHP Framework Configuration Management
Contents:
- Environment configurations: environments/
- Secure credentials: credentials/ (if any)
Restore with:
cp -r ${backup_path}/environments/* ${CONFIG_TEMPLATES_DIR}/
cp -r ${backup_path}/credentials/* ${CONFIG_CREDENTIALS_DIR}/
EOF
success "Configuration backup created: $backup_path"
}
# Show configuration info
show_config_info() {
local environment=$1
local config_file="${CONFIG_TEMPLATES_DIR}/.env.${environment}"
if [[ ! -f "$config_file" ]]; then
error "Configuration not found: $environment"
return 1
fi
info "Configuration information for $environment:"
# Extract key information
local domain app_env app_debug
domain=$(grep "^DOMAIN_NAME=" "$config_file" | cut -d'=' -f2 | tr -d '"' || echo "unknown")
app_env=$(grep "^APP_ENV=" "$config_file" | cut -d'=' -f2 | tr -d '"' || echo "unknown")
app_debug=$(grep "^APP_DEBUG=" "$config_file" | cut -d'=' -f2 | tr -d '"' || echo "unknown")
echo " Domain: $domain"
echo " Environment: $app_env"
echo " Debug mode: $app_debug"
echo " File: $config_file"
echo " Size: $(stat -c%s "$config_file" 2>/dev/null || echo "unknown") bytes"
echo " Modified: $(stat -c%y "$config_file" 2>/dev/null | cut -d' ' -f1 || echo "unknown")"
# Check for credentials
local creds_file="${CONFIG_CREDENTIALS_DIR}/${environment}.env"
if [[ -f "$creds_file" ]]; then
echo " Credentials: Available ($(stat -c%y "$creds_file" 2>/dev/null | cut -d' ' -f1))"
else
echo " Credentials: Not generated"
fi
}
# Command-line interface
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
# Initialize
init_config_directories
case "${1:-help}" in
"generate-credentials")
generate_environment_credentials "${2:-production}"
;;
"apply-config")
apply_configuration "$2" "$3" "$4" "${5:-}"
;;
"validate")
validate_configuration "${CONFIG_TEMPLATES_DIR}/.env.${2:-production}"
;;
"list")
list_configurations
;;
"rotate")
rotate_credentials "${2:-production}"
;;
"backup")
backup_configurations
;;
"info")
show_config_info "${2:-production}"
;;
"help"|*)
cat << EOF
${CYAN}Configuration Manager for Custom PHP Framework${NC}
${YELLOW}Usage:${NC} $0 <command> [options]
${YELLOW}Commands:${NC}
generate-credentials <env> Generate secure credentials for environment
apply-config <env> <domain> <email> [vars] Create config from template
validate <env> Validate configuration file
list List available configurations
rotate <env> Rotate credentials for environment
backup Backup all configurations
info <env> Show configuration information
help Show this help message
${YELLOW}Examples:${NC}
$0 generate-credentials production
$0 apply-config production michaelschiemer.de kontakt@michaelschiemer.de
$0 validate production
$0 list
$0 backup
EOF
;;
esac
fi