Files
action-stalwart-install/scripts/configure.sh
Sebastian Krupinski c16dcc80c8
Some checks failed
Test Stalwart Installation Action / Error Handling Tests (pull_request) Successful in 20s
Test Stalwart Installation Action / Installation with Admin Password (pull_request) Failing after 26s
Test Stalwart Installation Action / Full Configuration (Domains + Users) (pull_request) Failing after 37s
Test Stalwart Installation Action / Basic Installation (No Config) (pull_request) Successful in 45s
Test Stalwart Installation Action / Test on Ubuntu ubuntu-20.04 (pull_request) Has been cancelled
Test Stalwart Installation Action / Test on Ubuntu ubuntu-22.04 (pull_request) Has been cancelled
Test Stalwart Installation Action / Test on Ubuntu ubuntu-24.04 (pull_request) Has been cancelled
Test Stalwart Installation Action / Test Summary (pull_request) Has been cancelled
feat: initial version
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
2026-02-15 00:01:49 -05:00

302 lines
8.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Stalwart Post-Installation Configuration Script
# Configures admin password, domains, and users via REST API
#
set -euo pipefail
# Source utility functions
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/utils.sh"
# Configuration
readonly STALWART_PATH="${STALWART_INSTALL_PATH:-/opt/stalwart}"
readonly API_URL="http://localhost:8080/api"
readonly MAX_RETRIES=60
readonly RETRY_DELAY=2
# Read the generated password from installation
DEFAULT_ADMIN_PASSWORD="changeme"
if [ -f "${STALWART_PATH}/.init_password" ]; then
DEFAULT_ADMIN_PASSWORD=$(cat "${STALWART_PATH}/.init_password" | tr -d '\n\r')
log_info "Using generated password from installation"
# Clean up the password file for security
rm -f "${STALWART_PATH}/.init_password"
else
log_warning "Password file not found, using default password"
fi
readonly DEFAULT_ADMIN_PASSWORD
# Environment variables (passed from action.yml)
ADMIN_PASSWORD="${STALWART_ADMIN_PASSWORD:-}"
DOMAINS_JSON="${STALWART_DOMAINS:-}"
USERS_JSON="${STALWART_USERS:-}"
# Main configuration function
main() {
log_info "Starting Stalwart post-installation configuration"
# Wait for Stalwart API to be ready
if ! wait_for_stalwart_api; then
log_error "Stalwart API failed to become ready within timeout"
return 1
fi
# Set current password (start with generated one)
local current_password="$DEFAULT_ADMIN_PASSWORD"
# Test authentication with generated password
log_info "Verifying API access with generated password..."
if ! test_auth "$current_password"; then
log_error "Failed to authenticate with generated password"
return 1
fi
log_success "API authentication verified"
# Update admin password if provided and different from generated one
if [ -n "$ADMIN_PASSWORD" ] && [ "$ADMIN_PASSWORD" != "$current_password" ]; then
log_info "Updating admin password..."
if update_admin_password "$current_password" "$ADMIN_PASSWORD"; then
log_success "Admin password updated successfully"
current_password="$ADMIN_PASSWORD"
else
log_error "Failed to update admin password"
return 1
fi
else
log_info "No custom admin password provided"
log_warning "⚠️ Using generated password. Save it securely!"
fi
# Create domains if provided
if [ -n "$DOMAINS_JSON" ]; then
log_info "Creating domains..."
if validate_json "$DOMAINS_JSON"; then
create_domains "$current_password" "$DOMAINS_JSON"
else
log_error "Invalid domains JSON format"
return 1
fi
else
log_info "No domains specified, skipping domain creation"
fi
# Create users if provided
if [ -n "$USERS_JSON" ]; then
log_info "Creating users..."
if validate_json "$USERS_JSON"; then
create_users "$current_password" "$USERS_JSON"
else
log_error "Invalid users JSON format"
return 1
fi
else
log_info "No users specified, skipping user creation"
fi
log_success "Stalwart configuration completed successfully!"
return 0
}
# Wait for Stalwart API to be ready
wait_for_stalwart_api() {
log_info "Waiting for Stalwart API to be ready (timeout: ${MAX_RETRIES}s)..."
local attempt=0
while [ $attempt -lt $MAX_RETRIES ]; do
# Try to access the API login endpoint
if curl -sf -m 5 "${API_URL%/api}/login" >/dev/null 2>&1; then
log_success "Stalwart API is ready"
return 0
fi
attempt=$((attempt + 1))
if [ $attempt -lt $MAX_RETRIES ]; then
sleep $RETRY_DELAY
fi
done
return 1
}
# Test authentication with Stalwart API
# Args: $1 = password
# Returns: 0 if auth works, 1 otherwise
test_auth() {
local password="$1"
local http_code
# Test with a simple API call to get account info
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
-u "admin:${password}" \
"${API_URL}/accounts")
if [ "$http_code" = "200" ]; then
return 0
else
log_error "API test failed with HTTP $http_code"
return 1
fi
}
# Update admin password
# Args: $1 = current password, $2 = new password
update_admin_password() {
local current_password="$1"
local new_password="$2"
local http_code
local response
response=$(curl -s -w "\n%{http_code}" -X PUT "${API_URL}/account/admin" \
-u "admin:${current_password}" \
-H "Content-Type: application/json" \
-d "{\"password\":\"${new_password}\"}" 2>&1)
http_code=$(echo "$response" | tail -n 1)
response=$(echo "$response" | sed '$d')
if [ "$http_code" = "200" ] || [ "$http_code" = "204" ]; then
return 0
else
log_error "Password update failed with HTTP $http_code"
log_error "Response: $response"
return 1
fi
}
# Create domains from JSON array
# Args: $1 = password, $2 = domains JSON array
create_domains() {
local password="$1"
local domains_json="$2"
local domain_count
domain_count=$(echo "$domains_json" | jq 'length' 2>/dev/null)
if [ -z "$domain_count" ] || [ "$domain_count" = "0" ]; then
log_warning "No domains found in JSON array"
return 0
fi
log_info "Creating $domain_count domain(s)..."
local index=0
local created=0
local failed=0
while [ $index -lt "$domain_count" ]; do
local domain
domain=$(echo "$domains_json" | jq -c ".[$index]" 2>/dev/null)
if [ -z "$domain" ] || [ "$domain" = "null" ]; then
log_warning "Skipping invalid domain at index $index"
failed=$((failed + 1))
index=$((index + 1))
continue
fi
local domain_name
domain_name=$(echo "$domain" | jq -r '.name // empty' 2>/dev/null)
if [ -z "$domain_name" ]; then
log_warning "Skipping domain without 'name' field at index $index"
failed=$((failed + 1))
index=$((index + 1))
continue
fi
# Create domain via API
if curl -sf -X POST "${API_URL}/domain" \
-u "admin:${password}" \
-H "Content-Type: application/json" \
-d "$domain" >/dev/null 2>&1; then
log_success "✓ Created domain: $domain_name"
created=$((created + 1))
else
log_warning "✗ Failed to create domain: $domain_name"
failed=$((failed + 1))
fi
index=$((index + 1))
done
log_info "Domain creation summary: $created created, $failed failed"
return 0
}
# Create users from JSON array
# Args: $1 = password, $2 = users JSON array
create_users() {
local password="$1"
local users_json="$2"
local user_count
user_count=$(echo "$users_json" | jq 'length' 2>/dev/null)
if [ -z "$user_count" ] || [ "$user_count" = "0" ]; then
log_warning "No users found in JSON array"
return 0
fi
log_info "Creating $user_count user(s)..."
local index=0
local created=0
local failed=0
while [ $index -lt "$user_count" ]; do
local user
user=$(echo "$users_json" | jq -c ".[$index]" 2>/dev/null)
if [ -z "$user" ] || [ "$user" = "null" ]; then
log_warning "Skipping invalid user at index $index"
failed=$((failed + 1))
index=$((index + 1))
continue
fi
local email
email=$(echo "$user" | jq -r '.email // empty' 2>/dev/null)
if [ -z "$email" ]; then
log_warning "Skipping user without 'email' field at index $index"
failed=$((failed + 1))
index=$((index + 1))
continue
fi
# Build API payload (name, password, description, quota)
local payload
payload=$(echo "$user" | jq '{
name: .email,
password: .password,
description: (.name // .email),
quota: (.quota // 1073741824)
}' 2>/dev/null)
# Create user via API
if curl -sf -X POST "${API_URL}/account" \
-u "admin:${password}" \
-H "Content-Type: application/json" \
-d "$payload" >/dev/null 2>&1; then
log_success "✓ Created user: $email"
created=$((created + 1))
else
log_warning "✗ Failed to create user: $email"
failed=$((failed + 1))
fi
index=$((index + 1))
done
log_info "User creation summary: $created created, $failed failed"
return 0
}
# Execute main function
main "$@"