feat: fix file ownership after sudo installation

add step 8 to installation that restores file ownership to the invoking
user when running with sudo. also adds cleanup for legacy n8n worker
containers during updates.

- add 08_fix_permissions.sh script to detect real user and fix ownership
- add get_real_user() utility with multiple fallback detection methods
- add cleanup_legacy_n8n_workers() to remove old container naming format
- set restrictive permissions (600) on .env file for security
This commit is contained in:
Yury Kossakovsky
2025-12-16 16:06:08 -07:00
parent f9ea7783a0
commit 20106f21f8
4 changed files with 158 additions and 9 deletions

53
scripts/08_fix_permissions.sh Executable file
View File

@@ -0,0 +1,53 @@
#!/bin/bash
# =============================================================================
# 08_fix_permissions.sh - Fix file ownership after installation
# =============================================================================
# This script fixes file ownership when the installer was run with sudo.
# It detects the real user who invoked the installation and sets proper
# ownership for all project files.
#
# Usage: bash scripts/08_fix_permissions.sh
# =============================================================================
set -e
# Source the utilities file
source "$(dirname "$0")/utils.sh"
# Initialize paths
init_paths
log_info "Fixing file permissions..."
# Get the real user who ran the installer
REAL_USER=$(get_real_user)
REAL_GROUP=$(id -gn "$REAL_USER" 2>/dev/null || echo "$REAL_USER")
log_info "Detected user: $REAL_USER (group: $REAL_GROUP)"
# Skip if running as root without sudo (e.g., in Docker)
if [[ "$REAL_USER" == "root" ]]; then
log_info "Running as root user, no permission changes needed."
exit 0
fi
# Fix ownership of the entire project directory
if [[ -d "$PROJECT_ROOT" ]]; then
log_info "Setting ownership of $PROJECT_ROOT to $REAL_USER:$REAL_GROUP"
chown -R "$REAL_USER:$REAL_GROUP" "$PROJECT_ROOT"
# Ensure .env has restricted permissions (readable only by owner)
if [[ -f "$ENV_FILE" ]]; then
chmod 600 "$ENV_FILE"
log_info "Set restrictive permissions on .env file"
fi
# Ensure scripts are executable
chmod +x "$SCRIPT_DIR"/*.sh 2>/dev/null || true
chmod +x "$PROJECT_ROOT"/*.py 2>/dev/null || true
log_success "File permissions fixed successfully!"
else
log_error "Project root not found: $PROJECT_ROOT"
exit 1
fi

View File

@@ -58,6 +58,9 @@ bash "$SCRIPT_DIR/05_configure_services.sh" || {
}
log_success "Service configuration completed."
# Clean up legacy n8n worker containers from old naming convention
cleanup_legacy_n8n_workers
# Pull latest versions of selected containers based on updated .env
log_info "Pulling latest versions of selected containers..."
COMPOSE_FILES_FOR_PULL=("-f" "$PROJECT_ROOT/docker-compose.yml")

View File

@@ -3,7 +3,7 @@
# install.sh - Main installation orchestrator for n8n-install
# =============================================================================
# This script runs the complete installation process by sequentially executing
# 7 installation steps:
# 8 installation steps:
# 1. System Preparation - updates packages, installs utilities, configures firewall
# 2. Docker Installation - installs Docker and Docker Compose
# 3. Secret Generation - creates .env file with secure passwords and secrets
@@ -11,6 +11,7 @@
# 5. Service Configuration - prompts for API keys and service-specific settings
# 6. Service Launch - starts all selected services via Docker Compose
# 7. Final Report - displays credentials and access URLs
# 8. Fix Permissions - ensures correct file ownership for the invoking user
#
# Usage: sudo bash scripts/install.sh
# =============================================================================
@@ -55,6 +56,7 @@ required_scripts=(
"05_configure_services.sh"
"06_run_services.sh"
"07_final_report.sh"
"08_fix_permissions.sh"
)
missing_scripts=()
@@ -97,31 +99,31 @@ fi
# Run installation steps sequentially using their full paths
show_step 1 7 "System Preparation"
show_step 1 8 "System Preparation"
bash "$SCRIPT_DIR/01_system_preparation.sh" || { log_error "System Preparation failed"; exit 1; }
log_success "System preparation complete!"
show_step 2 7 "Installing Docker"
show_step 2 8 "Installing Docker"
bash "$SCRIPT_DIR/02_install_docker.sh" || { log_error "Docker Installation failed"; exit 1; }
log_success "Docker installation complete!"
show_step 3 7 "Generating Secrets and Configuration"
show_step 3 8 "Generating Secrets and Configuration"
bash "$SCRIPT_DIR/03_generate_secrets.sh" || { log_error "Secret/Config Generation failed"; exit 1; }
log_success "Secret/Config Generation complete!"
show_step 4 7 "Running Service Selection Wizard"
show_step 4 8 "Running Service Selection Wizard"
bash "$SCRIPT_DIR/04_wizard.sh" || { log_error "Service Selection Wizard failed"; exit 1; }
log_success "Service Selection Wizard complete!"
show_step 5 7 "Configure Services"
show_step 5 8 "Configure Services"
bash "$SCRIPT_DIR/05_configure_services.sh" || { log_error "Configure Services failed"; exit 1; }
log_success "Configure Services complete!"
show_step 6 7 "Running Services"
show_step 6 8 "Running Services"
bash "$SCRIPT_DIR/06_run_services.sh" || { log_error "Running Services failed"; exit 1; }
log_success "Running Services complete!"
show_step 7 7 "Generating Final Report"
show_step 7 8 "Generating Final Report"
# --- Installation Summary ---
log_info "Installation Summary:"
echo -e " ${GREEN}*${NC} System updated and basic utilities installed"
@@ -133,6 +135,12 @@ echo -e " ${GREEN}*${NC} '.env' generated with secure passwords and secrets"
echo -e " ${GREEN}*${NC} Services launched via Docker Compose"
bash "$SCRIPT_DIR/07_final_report.sh" || { log_error "Final Report Generation failed"; exit 1; }
log_success "Final Report generated!"
show_step 8 8 "Fixing File Permissions"
bash "$SCRIPT_DIR/08_fix_permissions.sh" || { log_error "Fix Permissions failed"; exit 1; }
log_success "File permissions fixed!"
log_success "Installation complete!"
exit 0
exit 0

View File

@@ -605,6 +605,91 @@ wt_parse_choices() {
read -ra arr <<< "$cleaned"
}
#=============================================================================
# LEGACY CONTAINER CLEANUP
#=============================================================================
# Remove legacy n8n worker containers from previous naming convention
# Old format: localai-n8n-worker-N (N = 1-10)
# New format: n8n-worker-N (managed by docker-compose.n8n-workers.yml)
# Usage: cleanup_legacy_n8n_workers
cleanup_legacy_n8n_workers() {
local removed_count=0
local container_name
log_info "Checking for legacy n8n worker containers..."
for i in {1..10}; do
container_name="localai-n8n-worker-$i"
# Check if container exists (running or stopped)
if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then
log_info "Removing legacy container: $container_name"
docker stop "$container_name" 2>/dev/null || true
docker rm -f "$container_name" 2>/dev/null || true
removed_count=$((removed_count + 1))
fi
done
if [ $removed_count -gt 0 ]; then
log_success "Removed $removed_count legacy n8n worker container(s)"
else
log_info "No legacy n8n worker containers found"
fi
}
#=============================================================================
# USER DETECTION
#=============================================================================
# Get the real user who invoked the script (even when running with sudo)
# Usage: real_user=$(get_real_user)
# Returns: username of the real user, or "root" if cannot determine
get_real_user() {
# Try SUDO_USER first (set by sudo)
if [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != "root" ]]; then
echo "$SUDO_USER"
return 0
fi
# Try logname (gets login name)
local logname_user
logname_user=$(logname 2>/dev/null) || true
if [[ -n "$logname_user" && "$logname_user" != "root" ]]; then
echo "$logname_user"
return 0
fi
# Try who am i (gets TTY user)
local who_user
who_user=$(who am i 2>/dev/null | awk '{print $1}') || true
if [[ -n "$who_user" && "$who_user" != "root" ]]; then
echo "$who_user"
return 0
fi
# Check if we're in a user's home directory
local current_dir="$PWD"
if [[ "$current_dir" =~ ^/home/([^/]+) ]]; then
local home_user="${BASH_REMATCH[1]}"
if id "$home_user" &>/dev/null; then
echo "$home_user"
return 0
fi
fi
# Fallback to current user
whoami
}
# Get the home directory of the real user
# Usage: real_home=$(get_real_user_home)
get_real_user_home() {
local real_user
real_user=$(get_real_user)
eval echo "~$real_user"
}
#=============================================================================
# DIRECTORY PRESERVATION (for git updates)
#=============================================================================