413 lines
21 KiB
Bash
Executable File
413 lines
21 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# =============================================================================
|
|
# setup/configure_env.sh — Interactive .env configuration wizard
|
|
# Prompts for every required variable with validation and progress tracking.
|
|
# =============================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="${SCRIPT_DIR}/.."
|
|
ENV_FILE="${PROJECT_ROOT}/.env"
|
|
ENV_EXAMPLE="${PROJECT_ROOT}/.env.example"
|
|
|
|
# shellcheck source=../lib/common.sh
|
|
# shellcheck disable=SC1091
|
|
source "${PROJECT_ROOT}/lib/common.sh"
|
|
|
|
# Colors
|
|
if [[ -t 1 ]]; then
|
|
C_RESET='\033[0m'; C_BOLD='\033[1m'; C_GREEN='\033[0;32m'
|
|
C_YELLOW='\033[0;33m'; C_RED='\033[0;31m'; C_CYAN='\033[0;36m'; C_DIM='\033[2m'
|
|
else
|
|
C_RESET=''; C_BOLD=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_CYAN=''; C_DIM=''
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Initialize .env if it doesn't exist
|
|
# ---------------------------------------------------------------------------
|
|
if [[ ! -f "$ENV_FILE" ]]; then
|
|
if [[ ! -f "$ENV_EXAMPLE" ]]; then
|
|
printf '%b[ERROR]%b .env.example not found at %s\n' "$C_RED" "$C_RESET" "$ENV_EXAMPLE" >&2
|
|
exit 1
|
|
fi
|
|
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
|
printf '%b[INFO]%b Created .env from .env.example\n' "$C_CYAN" "$C_RESET" >&2
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load current values
|
|
# ---------------------------------------------------------------------------
|
|
# Lookup a variable's current value from .env (bash 3.2 compatible — no assoc arrays)
|
|
get_env_val() {
|
|
local key="$1" default="${2:-}"
|
|
local line val
|
|
line=$(grep "^${key}=" "$ENV_FILE" 2>/dev/null | head -1) || true
|
|
if [[ -z "$line" ]]; then
|
|
printf '%s' "$default"
|
|
return 0
|
|
fi
|
|
val="${line#*=}"
|
|
# Strip inline comment
|
|
val="${val%%#*}"
|
|
# Trim trailing whitespace
|
|
val="${val%"${val##*[![:space:]]}"}"
|
|
printf '%s' "$val"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Validation functions — sourced from lib/common.sh (validate_ip, validate_port,
|
|
# validate_email, validate_path, validate_url, validate_bool, validate_integer,
|
|
# validate_nonempty, validate_password, validate_ssl_mode)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Prompt function
|
|
# ---------------------------------------------------------------------------
|
|
# Base prompt count (fixed prompts only — repo/DB prompts added dynamically)
|
|
TOTAL_PROMPTS=59
|
|
CURRENT_PROMPT=0
|
|
LAST_SECTION=""
|
|
|
|
# Collected SSL_MODE for conditional logic
|
|
COLLECTED_TLS_MODE=""
|
|
|
|
prompt_var() {
|
|
local var_name="$1"
|
|
local description="$2"
|
|
local validation="$3"
|
|
local default="${4:-}"
|
|
local section="$5"
|
|
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
|
|
# Print section header when entering a new section
|
|
if [[ "$section" != "$LAST_SECTION" ]]; then
|
|
LAST_SECTION="$section"
|
|
printf '\n%b── %s ──────────────────────────────────────────%b\n' "$C_BOLD" "$section" "$C_RESET"
|
|
fi
|
|
|
|
# Determine current value (from .env or default)
|
|
local current
|
|
current=$(get_env_val "$var_name" "$default")
|
|
|
|
# Build prompt
|
|
local progress
|
|
progress=$(printf '[%d/%d]' "$CURRENT_PROMPT" "$TOTAL_PROMPTS")
|
|
|
|
local prompt_text
|
|
if [[ -n "$current" ]]; then
|
|
# Mask passwords
|
|
if [[ "$validation" == "password" ]]; then
|
|
prompt_text=$(printf '%b%s%b %s (%s) %b[****]%b: ' "$C_DIM" "$progress" "$C_RESET" "$var_name" "$description" "$C_YELLOW" "$C_RESET")
|
|
else
|
|
prompt_text=$(printf '%b%s%b %s (%s) %b[%s]%b: ' "$C_DIM" "$progress" "$C_RESET" "$var_name" "$description" "$C_YELLOW" "$current" "$C_RESET")
|
|
fi
|
|
else
|
|
prompt_text=$(printf '%b%s%b %s (%s): ' "$C_DIM" "$progress" "$C_RESET" "$var_name" "$description")
|
|
fi
|
|
|
|
# Read input with validation loop
|
|
local value
|
|
while true; do
|
|
printf '%b' "$prompt_text"
|
|
read -r value
|
|
|
|
# Use current/default if empty
|
|
if [[ -z "$value" ]]; then
|
|
value="$current"
|
|
fi
|
|
|
|
# Validate
|
|
if [[ -z "$value" ]] && [[ "$validation" != "optional" ]]; then
|
|
printf '%b Invalid: value cannot be empty%b\n' "$C_RED" "$C_RESET"
|
|
continue
|
|
fi
|
|
|
|
# Optional fields accept any value including empty
|
|
if [[ "$validation" == "optional" ]]; then
|
|
break
|
|
fi
|
|
|
|
case "$validation" in
|
|
ip)
|
|
if validate_ip "$value"; then break; fi
|
|
printf '%b Invalid IP address format (expected: x.x.x.x)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
port)
|
|
if validate_port "$value"; then break; fi
|
|
printf '%b Invalid port (expected: 1-65535)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
email)
|
|
if validate_email "$value"; then break; fi
|
|
printf '%b Invalid email (must contain @)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
path)
|
|
if validate_path "$value"; then break; fi
|
|
printf '%b Invalid path (must start with /)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
url)
|
|
if validate_url "$value"; then break; fi
|
|
printf '%b Invalid URL (must start with http:// or https://)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
bool)
|
|
if validate_bool "$value"; then break; fi
|
|
printf '%b Invalid: must be true or false%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
integer)
|
|
if validate_integer "$value"; then break; fi
|
|
printf '%b Invalid: must be a number%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
positive_integer)
|
|
if validate_positive_integer "$value"; then break; fi
|
|
printf '%b Invalid: must be a positive integer (>= 1)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
password)
|
|
if validate_password "$value"; then break; fi
|
|
printf '%b Invalid: password must be at least 8 characters%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
tls_mode)
|
|
if validate_tls_mode "$value"; then break; fi
|
|
printf '%b Invalid: must be "cloudflare" or "existing"%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
db_type)
|
|
if validate_db_type "$value"; then break; fi
|
|
printf '%b Invalid: must be sqlite3, mysql, postgres, or mssql%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
nonempty|*)
|
|
if validate_nonempty "$value"; then break; fi
|
|
printf '%b Invalid: value cannot be empty%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Write to .env
|
|
write_env_var "$var_name" "$value"
|
|
|
|
# Track TLS mode for conditional prompts
|
|
if [[ "$var_name" == "TLS_MODE" ]]; then
|
|
COLLECTED_TLS_MODE="$value"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Write a variable to .env file (preserving structure)
|
|
# ---------------------------------------------------------------------------
|
|
write_env_var() {
|
|
local key="$1" value="$2"
|
|
|
|
if grep -q "^${key}=" "$ENV_FILE"; then
|
|
# Replace existing line (preserve inline comment if present in .env.example)
|
|
local comment=""
|
|
if grep -q "^${key}=" "$ENV_EXAMPLE" 2>/dev/null; then
|
|
comment=$(grep "^${key}=" "$ENV_EXAMPLE" | sed "s/^${key}=[^#]*//" | sed 's/^[[:space:]]*//')
|
|
fi
|
|
if [[ -n "$comment" ]]; then
|
|
# Pad value to align comment
|
|
local padded
|
|
padded=$(printf '%-30s' "$value")
|
|
sed -i.bak "s|^${key}=.*|${key}=${padded}${comment}|" "$ENV_FILE"
|
|
else
|
|
sed -i.bak "s|^${key}=.*|${key}=${value}|" "$ENV_FILE"
|
|
fi
|
|
rm -f "${ENV_FILE}.bak"
|
|
else
|
|
printf '%s=%s\n' "$key" "$value" >> "$ENV_FILE"
|
|
fi
|
|
}
|
|
|
|
# ===========================================================================
|
|
# Main — walk through all variables in section order
|
|
# ===========================================================================
|
|
|
|
printf '\n%b╔══════════════════════════════════════════════════════════╗%b\n' "$C_BOLD" "$C_RESET"
|
|
printf '%b║ Gitea Migration — Environment Setup ║%b\n' "$C_BOLD" "$C_RESET"
|
|
printf '%b╚══════════════════════════════════════════════════════════╝%b\n\n' "$C_BOLD" "$C_RESET"
|
|
printf 'Press Enter to keep the current value shown in [brackets].\n'
|
|
printf 'Auto-populated variables (tokens) will be skipped.\n'
|
|
|
|
# --- UNRAID SERVER ---
|
|
prompt_var "UNRAID_IP" "Static IP of Unraid server" ip "" "UNRAID SERVER"
|
|
prompt_var "UNRAID_SSH_USER" "SSH username for Unraid" nonempty "" "UNRAID SERVER"
|
|
prompt_var "UNRAID_SSH_PORT" "SSH port" port "22" "UNRAID SERVER"
|
|
prompt_var "UNRAID_GITEA_DATA_PATH" "Absolute path on NVMe for Gitea data" path "" "UNRAID SERVER"
|
|
prompt_var "UNRAID_SSH_KEY" "Absolute path to SSH private key, e.g. /Users/you/.ssh/id_ed25519 (empty = ssh-agent)" optional "" "UNRAID SERVER"
|
|
|
|
# --- FEDORA SERVER ---
|
|
prompt_var "FEDORA_IP" "Static IP of Fedora server" ip "" "FEDORA SERVER"
|
|
prompt_var "FEDORA_SSH_USER" "SSH username for Fedora" nonempty "" "FEDORA SERVER"
|
|
prompt_var "FEDORA_SSH_PORT" "SSH port" port "22" "FEDORA SERVER"
|
|
prompt_var "FEDORA_GITEA_DATA_PATH" "Absolute path on NVMe for Gitea data" path "" "FEDORA SERVER"
|
|
prompt_var "FEDORA_SSH_KEY" "Absolute path to SSH private key, e.g. /Users/you/.ssh/id_ed25519 (empty = ssh-agent)" optional "" "FEDORA SERVER"
|
|
|
|
# --- DOCKER NETWORKING (macvlan) ---
|
|
prompt_var "UNRAID_MACVLAN_PARENT" "Unraid host NIC (e.g. br0, eth0)" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_MACVLAN_SUBNET" "Unraid LAN subnet (e.g. 192.168.1.0/24)" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_MACVLAN_GATEWAY" "Unraid LAN gateway (e.g. 192.168.1.1)" ip "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_MACVLAN_IP_RANGE" "Unraid container IP range (e.g. 192.168.1.192/28)" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_GITEA_IP" "Unraid Gitea container IP" ip "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_DB_IP" "Unraid DB container IP (empty if sqlite3)" optional "" "DOCKER NETWORKING"
|
|
prompt_var "UNRAID_CADDY_IP" "Unraid Caddy container IP" ip "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_MACVLAN_PARENT" "Fedora host NIC (e.g. eth0)" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_MACVLAN_SUBNET" "Fedora LAN subnet (CIDR)" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_MACVLAN_GATEWAY" "Fedora LAN gateway" ip "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_MACVLAN_IP_RANGE" "Fedora container IP range" nonempty "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_GITEA_IP" "Fedora Gitea container IP" ip "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_DB_IP" "Fedora DB container IP (empty if sqlite3)" optional "" "DOCKER NETWORKING"
|
|
prompt_var "FEDORA_CADDY_IP" "Fedora Caddy container IP" ip "" "DOCKER NETWORKING"
|
|
|
|
# --- GITEA SHARED CREDENTIALS ---
|
|
prompt_var "GITEA_ADMIN_USER" "Admin username (same on both instances)" nonempty "" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "GITEA_ADMIN_PASSWORD" "Admin password (min 8 chars)" password "" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "GITEA_ADMIN_EMAIL" "Admin email" email "" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "GITEA_ORG_NAME" "Organization name (e.g. mifi-llc)" nonempty "" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "GITEA_INSTANCE_NAME" "Display name for Gitea (e.g. MIFI Git)" nonempty "" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "GITEA_DB_TYPE" "Database type (sqlite3, mysql, postgres, mssql)" db_type "sqlite3" "GITEA SHARED CREDENTIALS"
|
|
|
|
# Track DB type for conditional prompts
|
|
COLLECTED_DB_TYPE=$(get_env_val "GITEA_DB_TYPE" "sqlite3")
|
|
|
|
if [[ "$COLLECTED_DB_TYPE" != "sqlite3" ]]; then
|
|
# Determine default port based on DB type
|
|
case "$COLLECTED_DB_TYPE" in
|
|
mysql) db_port_default="3306" ;;
|
|
postgres) db_port_default="5432" ;;
|
|
mssql) db_port_default="1433" ;;
|
|
*) db_port_default="" ;;
|
|
esac
|
|
prompt_var "GITEA_DB_HOST" "Database host (container IP or hostname)" nonempty "" "DATABASE"
|
|
prompt_var "GITEA_DB_PORT" "Database port" port "$db_port_default" "DATABASE"
|
|
prompt_var "GITEA_DB_NAME" "Database name" nonempty "gitea" "DATABASE"
|
|
prompt_var "GITEA_DB_USER" "Database user" nonempty "gitea" "DATABASE"
|
|
prompt_var "GITEA_DB_PASSWD" "Database password (min 8 chars)" password "" "DATABASE"
|
|
# Update total for the 5 DB prompts
|
|
TOTAL_PROMPTS=$((TOTAL_PROMPTS + 5))
|
|
fi
|
|
|
|
prompt_var "GITEA_VERSION" "Gitea Docker image tag" nonempty "1.25" "GITEA SHARED CREDENTIALS"
|
|
prompt_var "ACT_RUNNER_VERSION" "act_runner version" nonempty "0.3.0" "GITEA SHARED CREDENTIALS"
|
|
|
|
# --- GITEA PRIMARY INSTANCE ---
|
|
prompt_var "GITEA_DOMAIN" "Public domain pointing to Unraid" nonempty "" "GITEA PRIMARY INSTANCE"
|
|
prompt_var "GITEA_INTERNAL_URL" "Internal URL (e.g. http://IP:3000)" url "" "GITEA PRIMARY INSTANCE"
|
|
|
|
# --- GITEA BACKUP INSTANCE ---
|
|
prompt_var "GITEA_BACKUP_INTERNAL_URL" "Internal URL of Fedora Gitea" url "" "GITEA BACKUP INSTANCE"
|
|
prompt_var "GITEA_BACKUP_MIRROR_INTERVAL" "How often Fedora pulls from Unraid" nonempty "8h" "GITEA BACKUP INSTANCE"
|
|
prompt_var "BACKUP_STORAGE_PATH" "Absolute path on Fedora for backup archives" path "" "GITEA BACKUP INSTANCE"
|
|
prompt_var "BACKUP_RETENTION_COUNT" "Number of backup archives to keep" integer "5" "GITEA BACKUP INSTANCE"
|
|
|
|
# --- REPOSITORIES ---
|
|
prompt_var "GITHUB_USERNAME" "GitHub username or org name" nonempty "" "REPOSITORIES"
|
|
prompt_var "GITHUB_TOKEN" "GitHub PAT with repo scope (read+write)" nonempty "" "REPOSITORIES"
|
|
# Dynamic repo collection — ask how many, then prompt for each
|
|
printf '\n%b── REPOSITORIES ─────────────────────────────────────────%b\n' "$C_BOLD" "$C_RESET"
|
|
LAST_SECTION="REPOSITORIES"
|
|
|
|
# Determine existing repo count from .env
|
|
EXISTING_REPOS=$(get_env_val "REPO_NAMES" "")
|
|
EXISTING_COUNT=0
|
|
if [[ -n "$EXISTING_REPOS" ]]; then
|
|
# shellcheck disable=SC2086
|
|
set -- $EXISTING_REPOS
|
|
EXISTING_COUNT=$#
|
|
fi
|
|
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
printf '%b[%d/~%d]%b How many repos to migrate? %b[%s]%b: ' "$C_DIM" "$CURRENT_PROMPT" "$TOTAL_PROMPTS" "$C_RESET" "$C_YELLOW" "${EXISTING_COUNT:-3}" "$C_RESET"
|
|
read -r REPO_COUNT
|
|
if [[ -z "$REPO_COUNT" ]]; then REPO_COUNT="${EXISTING_COUNT:-3}"; fi
|
|
while ! [[ "$REPO_COUNT" =~ ^[1-9][0-9]*$ ]]; do
|
|
printf '%b Invalid: must be a positive integer%b\n' "$C_RED" "$C_RESET"
|
|
printf 'How many repos to migrate? '
|
|
read -r REPO_COUNT
|
|
done
|
|
# Update total now that we know how many repos
|
|
TOTAL_PROMPTS=$((TOTAL_PROMPTS + 1 + REPO_COUNT))
|
|
|
|
# Collect repo names
|
|
COLLECTED_REPOS=""
|
|
# shellcheck disable=SC2086
|
|
set -- $EXISTING_REPOS
|
|
for ((i = 1; i <= REPO_COUNT; i++)); do
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
local_default="${1:-}"
|
|
shift 2>/dev/null || true
|
|
if [[ -n "$local_default" ]]; then
|
|
printf '%b[%d/~%d]%b Repo %d name %b[%s]%b: ' "$C_DIM" "$CURRENT_PROMPT" "$TOTAL_PROMPTS" "$C_RESET" "$i" "$C_YELLOW" "$local_default" "$C_RESET"
|
|
else
|
|
printf '%b[%d/~%d]%b Repo %d name: ' "$C_DIM" "$CURRENT_PROMPT" "$TOTAL_PROMPTS" "$C_RESET" "$i"
|
|
fi
|
|
read -r repo_name
|
|
if [[ -z "$repo_name" ]]; then repo_name="$local_default"; fi
|
|
while [[ -z "$repo_name" ]]; do
|
|
printf '%b Invalid: repo name cannot be empty%b\n' "$C_RED" "$C_RESET"
|
|
printf 'Repo %d name: ' "$i"
|
|
read -r repo_name
|
|
done
|
|
if [[ -n "$COLLECTED_REPOS" ]]; then
|
|
COLLECTED_REPOS="${COLLECTED_REPOS} ${repo_name}"
|
|
else
|
|
COLLECTED_REPOS="${repo_name}"
|
|
fi
|
|
done
|
|
write_env_var "REPO_NAMES" "$COLLECTED_REPOS"
|
|
prompt_var "MIGRATE_ISSUES" "Migrate GitHub issues" bool "false" "REPOSITORIES"
|
|
prompt_var "MIGRATE_LABELS" "Migrate GitHub labels" bool "true" "REPOSITORIES"
|
|
prompt_var "MIGRATE_MILESTONES" "Migrate GitHub milestones" bool "false" "REPOSITORIES"
|
|
prompt_var "MIGRATE_WIKI" "Migrate GitHub wiki" bool "false" "REPOSITORIES"
|
|
prompt_var "GITHUB_MIRROR_INTERVAL" "How often Gitea pushes to GitHub" nonempty "8h" "REPOSITORIES"
|
|
|
|
# --- RUNNERS ---
|
|
prompt_var "RUNNER_DEFAULT_IMAGE" "Default container image for docker runners" nonempty "catthehacker/ubuntu:act-latest" "RUNNERS"
|
|
prompt_var "RUNNER_DATA_BASE_PATH" "Base dir on remote hosts for runner data (host path)" nonempty "/mnt/nvme/gitea-runner" "RUNNERS"
|
|
# shellcheck disable=SC2088 # tilde intentionally stored as literal (expanded at runtime)
|
|
prompt_var "LOCAL_RUNNER_DATA_BASE_PATH" "Base dir on macOS for native runner data" nonempty "~/gitea-runner" "RUNNERS"
|
|
prompt_var "LOCAL_REGISTRY" "Local registry prefix (empty = Docker Hub)" optional "" "RUNNERS"
|
|
|
|
# --- TLS / REVERSE PROXY (Caddy) ---
|
|
prompt_var "TLS_MODE" "TLS mode: cloudflare (DNS-01) or existing (manual certs)" tls_mode "cloudflare" "TLS / REVERSE PROXY"
|
|
prompt_var "CADDY_DOMAIN" "Wildcard base domain (e.g. privacyindesign.com)" nonempty "" "TLS / REVERSE PROXY"
|
|
prompt_var "CADDY_DATA_PATH" "Absolute path on host for Caddy data" path "" "TLS / REVERSE PROXY"
|
|
|
|
# Conditional TLS prompts
|
|
if [[ "$COLLECTED_TLS_MODE" == "cloudflare" ]]; then
|
|
prompt_var "CLOUDFLARE_API_TOKEN" "Cloudflare API token (Zone:DNS:Edit)" nonempty "" "TLS / REVERSE PROXY"
|
|
# Skip cert path prompts but still count them for progress
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 2))
|
|
else
|
|
# Skip cloudflare token prompt but count it
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
prompt_var "SSL_CERT_PATH" "Absolute path to SSL cert" path "" "TLS / REVERSE PROXY"
|
|
prompt_var "SSL_KEY_PATH" "Absolute path to SSL key" path "" "TLS / REVERSE PROXY"
|
|
fi
|
|
|
|
# --- BRANCH PROTECTION ---
|
|
prompt_var "PROTECTED_BRANCH" "Branch to protect across all repos" nonempty "main" "BRANCH PROTECTION"
|
|
prompt_var "REQUIRE_PR_REVIEW" "Require PR review before merge" bool "false" "BRANCH PROTECTION"
|
|
prompt_var "REQUIRED_APPROVALS" "Number of approvals required" integer "1" "BRANCH PROTECTION"
|
|
|
|
# --- SECURITY ---
|
|
prompt_var "SEMGREP_VERSION" "Semgrep OSS version" nonempty "latest" "SECURITY"
|
|
prompt_var "TRIVY_VERSION" "Trivy version" nonempty "latest" "SECURITY"
|
|
prompt_var "GITLEAKS_VERSION" "Gitleaks version" nonempty "latest" "SECURITY"
|
|
prompt_var "SECURITY_FAIL_ON_ERROR" "Block PR merge if security scan fails" bool "true" "SECURITY"
|
|
|
|
# ===========================================================================
|
|
# Summary
|
|
# ===========================================================================
|
|
printf '\n%b╔══════════════════════════════════════════════════════════╗%b\n' "$C_GREEN" "$C_RESET"
|
|
printf '%b║ Configuration Complete ║%b\n' "$C_GREEN" "$C_RESET"
|
|
printf '%b╚══════════════════════════════════════════════════════════╝%b\n\n' "$C_GREEN" "$C_RESET"
|
|
|
|
printf '%bSummary:%b\n' "$C_BOLD" "$C_RESET"
|
|
printf ' Unraid: %s@%s:%s\n' "$(get_env_val UNRAID_SSH_USER)" "$(get_env_val UNRAID_IP)" "$(get_env_val UNRAID_SSH_PORT 22)"
|
|
printf ' Fedora: %s@%s:%s\n' "$(get_env_val FEDORA_SSH_USER)" "$(get_env_val FEDORA_IP)" "$(get_env_val FEDORA_SSH_PORT 22)"
|
|
printf ' Gitea: %s (admin: %s, password: ****)\n' "$(get_env_val GITEA_DOMAIN)" "$(get_env_val GITEA_ADMIN_USER)"
|
|
printf ' Org: %s\n' "$(get_env_val GITEA_ORG_NAME)"
|
|
printf ' Repos: %s\n' "$(get_env_val REPO_NAMES)"
|
|
printf ' TLS: %s (Caddy)\n' "${COLLECTED_TLS_MODE}"
|
|
printf ' .env saved: %s\n\n' "$ENV_FILE"
|
|
|
|
printf 'Next step: run %bsetup/macbook.sh%b to install local prerequisites.\n' "$C_BOLD" "$C_RESET"
|