GT AI OS Community Edition v2.0.33

Security hardening release addressing CodeQL and Dependabot alerts:

- Fix stack trace exposure in error responses
- Add SSRF protection with DNS resolution checking
- Implement proper URL hostname validation (replaces substring matching)
- Add centralized path sanitization to prevent path traversal
- Fix ReDoS vulnerability in email validation regex
- Improve HTML sanitization in validation utilities
- Fix capability wildcard matching in auth utilities
- Update glob dependency to address CVE
- Add CodeQL suppression comments for verified false positives

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
HackWeasel
2025-12-12 17:04:45 -05:00
commit b9dfb86260
746 changed files with 232071 additions and 0 deletions

273
scripts/lib/secrets.sh Executable file
View File

@@ -0,0 +1,273 @@
#!/bin/bash
# GT AI OS Secret Generation Library
# Centralized, idempotent secret generation for deployment scripts
#
# Usage: source scripts/lib/secrets.sh
# generate_all_secrets # Populates .env with missing secrets only
set -e
# Source common functions if available
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SCRIPT_DIR/common.sh" ]; then
source "$SCRIPT_DIR/common.sh"
fi
# =============================================================================
# SECRET GENERATION FUNCTIONS
# =============================================================================
# Generate a random hex string (for JWT secrets, encryption keys)
# Usage: generate_secret_hex [length]
# Default length: 64 characters (32 bytes)
generate_secret_hex() {
local length=${1:-64}
openssl rand -hex $((length / 2))
}
# Generate a Fernet key (for TFA encryption, API key encryption)
# Fernet requires base64-encoded 32-byte key
generate_fernet_key() {
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" 2>/dev/null || \
openssl rand -base64 32
}
# Generate a secure password (for database passwords)
# Usage: generate_password [length]
# Default length: 32 characters
generate_password() {
local length=${1:-32}
# Use alphanumeric + special chars, avoiding problematic shell chars
openssl rand -base64 48 | tr -dc 'a-zA-Z0-9!@#$%^&*()_+-=' | head -c "$length"
}
# Generate a simple alphanumeric password (for services that don't handle special chars well)
# Usage: generate_simple_password [length]
generate_simple_password() {
local length=${1:-32}
openssl rand -base64 48 | tr -dc 'a-zA-Z0-9' | head -c "$length"
}
# =============================================================================
# ENV FILE MANAGEMENT
# =============================================================================
# Get value from .env file
# Usage: get_env_value "KEY_NAME" ".env"
get_env_value() {
local key="$1"
local env_file="${2:-.env}"
if [ -f "$env_file" ]; then
grep "^${key}=" "$env_file" 2>/dev/null | cut -d'=' -f2- | head -1
fi
}
# Set value in .env file (preserves existing, only sets if missing or empty)
# Usage: set_env_value "KEY_NAME" "value" ".env"
set_env_value() {
local key="$1"
local value="$2"
local env_file="${3:-.env}"
# Create file if it doesn't exist
touch "$env_file"
local existing=$(get_env_value "$key" "$env_file")
if [ -z "$existing" ]; then
# Key doesn't exist or is empty, add/update it
if grep -q "^${key}=" "$env_file" 2>/dev/null; then
# Key exists but is empty, update it
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s|^${key}=.*|${key}=${value}|" "$env_file"
else
sed -i "s|^${key}=.*|${key}=${value}|" "$env_file"
fi
else
# Key doesn't exist, append it
echo "${key}=${value}" >> "$env_file"
fi
return 0 # Secret was generated
fi
return 1 # Secret already exists
}
# =============================================================================
# MAIN SECRET GENERATION
# =============================================================================
# Generate all required secrets for GT AI OS
# This function is IDEMPOTENT - it only generates missing secrets
# Usage: generate_all_secrets [env_file]
generate_all_secrets() {
local env_file="${1:-.env}"
local generated_count=0
echo "Checking and generating missing secrets..."
# JWT and Authentication Secrets
if set_env_value "JWT_SECRET" "$(generate_secret_hex 64)" "$env_file"; then
echo " Generated: JWT_SECRET"
((++generated_count))
fi
if set_env_value "CONTROL_PANEL_JWT_SECRET" "$(generate_secret_hex 64)" "$env_file"; then
echo " Generated: CONTROL_PANEL_JWT_SECRET"
((++generated_count))
fi
if set_env_value "RESOURCE_CLUSTER_SECRET_KEY" "$(generate_secret_hex 64)" "$env_file"; then
echo " Generated: RESOURCE_CLUSTER_SECRET_KEY"
((++generated_count))
fi
# Encryption Keys
if set_env_value "TFA_ENCRYPTION_KEY" "$(generate_fernet_key)" "$env_file"; then
echo " Generated: TFA_ENCRYPTION_KEY"
((++generated_count))
fi
if set_env_value "API_KEY_ENCRYPTION_KEY" "$(generate_fernet_key)" "$env_file"; then
echo " Generated: API_KEY_ENCRYPTION_KEY"
((++generated_count))
fi
# Database Passwords (use simple passwords for PostgreSQL compatibility)
if set_env_value "ADMIN_POSTGRES_PASSWORD" "$(generate_simple_password 32)" "$env_file"; then
echo " Generated: ADMIN_POSTGRES_PASSWORD"
((++generated_count))
fi
if set_env_value "TENANT_POSTGRES_PASSWORD" "$(generate_simple_password 32)" "$env_file"; then
echo " Generated: TENANT_POSTGRES_PASSWORD"
((++generated_count))
fi
# Sync TENANT_USER_PASSWORD with TENANT_POSTGRES_PASSWORD
local tenant_pass=$(get_env_value "TENANT_POSTGRES_PASSWORD" "$env_file")
if set_env_value "TENANT_USER_PASSWORD" "$tenant_pass" "$env_file"; then
echo " Set: TENANT_USER_PASSWORD (synced with TENANT_POSTGRES_PASSWORD)"
((++generated_count))
fi
if set_env_value "TENANT_REPLICATOR_PASSWORD" "$(generate_simple_password 32)" "$env_file"; then
echo " Generated: TENANT_REPLICATOR_PASSWORD"
((++generated_count))
fi
# Other Service Passwords
if set_env_value "RABBITMQ_PASSWORD" "$(generate_simple_password 24)" "$env_file"; then
echo " Generated: RABBITMQ_PASSWORD"
((++generated_count))
fi
if [ $generated_count -eq 0 ]; then
echo " All secrets already present (no changes needed)"
else
echo " Generated $generated_count new secret(s)"
fi
return 0
}
# Validate that all required secrets are present (non-empty)
# Usage: validate_secrets [env_file]
validate_secrets() {
local env_file="${1:-.env}"
local missing=0
local required_secrets=(
"JWT_SECRET"
"CONTROL_PANEL_JWT_SECRET"
"RESOURCE_CLUSTER_SECRET_KEY"
"TFA_ENCRYPTION_KEY"
"API_KEY_ENCRYPTION_KEY"
"ADMIN_POSTGRES_PASSWORD"
"TENANT_POSTGRES_PASSWORD"
"TENANT_USER_PASSWORD"
"RABBITMQ_PASSWORD"
)
echo "Validating required secrets..."
for secret in "${required_secrets[@]}"; do
local value=$(get_env_value "$secret" "$env_file")
if [ -z "$value" ]; then
echo " MISSING: $secret"
((missing++))
fi
done
if [ $missing -gt 0 ]; then
echo " $missing required secret(s) missing!"
return 1
fi
echo " All required secrets present"
return 0
}
# =============================================================================
# TEMPLATE CREATION
# =============================================================================
# Create a .env.template file with placeholder values
# Usage: create_env_template [output_file]
create_env_template() {
local output_file="${1:-.env.template}"
cat > "$output_file" << 'EOF'
# GT AI OS Environment Configuration
# Copy this file to .env and customize values
# Secrets are auto-generated on first install if not provided
# =============================================================================
# AUTHENTICATION (Auto-generated if empty)
# =============================================================================
JWT_SECRET=
CONTROL_PANEL_JWT_SECRET=
RESOURCE_CLUSTER_SECRET_KEY=
# =============================================================================
# ENCRYPTION KEYS (Auto-generated if empty)
# =============================================================================
PASSWORD_RESET_ENCRYPTION_KEY=
TFA_ENCRYPTION_KEY=
API_KEY_ENCRYPTION_KEY=
# =============================================================================
# DATABASE PASSWORDS (Auto-generated if empty)
# =============================================================================
ADMIN_POSTGRES_PASSWORD=
TENANT_POSTGRES_PASSWORD=
TENANT_USER_PASSWORD=
TENANT_REPLICATOR_PASSWORD=
RABBITMQ_PASSWORD=
# =============================================================================
# API KEYS (Configure via Control Panel UI after installation)
# =============================================================================
# Note: LLM API keys (Groq, OpenAI, Anthropic) are configured through
# the Control Panel UI, not environment variables.
# =============================================================================
# SMTP (Enterprise Edition Only - Password Reset)
# =============================================================================
# Set via environment variables or configure below
# SMTP_HOST=smtp-relay.brevo.com
# SMTP_PORT=587
# SMTP_USERNAME=
# SMTP_PASSWORD=
# SMTP_FROM_EMAIL=noreply@yourdomain.com
# SMTP_FROM_NAME=GT AI OS
# =============================================================================
# DEPLOYMENT
# =============================================================================
COMPOSE_PROJECT_NAME=gentwo
ENVIRONMENT=production
EOF
echo "Created $output_file"
}