Hearth is the infrastructure home for the letemcook ecosystem. Ported from coherence-mcp/infra: - Terraform modules (VPC, EKS, IAM, NLB, S3, storage) - Kubernetes manifests (Forgejo, ingress, cert-manager, karpenter) - Deployment scripts (phased rollout) Status: Not deployed. EKS cluster needs to be provisioned. Next steps: 1. Bootstrap terraform backend 2. Deploy phase 1 (foundation) 3. Deploy phase 2 (core services including Forgejo) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
300 lines
7.9 KiB
Bash
Executable file
300 lines
7.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# Phase 5: E2EE Webmail Deployment (RFC 0043)
|
|
#
|
|
# This script deploys the E2EE webmail application including:
|
|
# - Webmail frontend (React/TypeScript)
|
|
# - Key service backend (Rust)
|
|
# - Integration with Stalwart and Vault
|
|
#
|
|
# Usage:
|
|
# ./deploy-phase5-e2ee-webmail.sh [--dry-run] [--build-local] [--skip-frontend] [--skip-key-service]
|
|
#
|
|
# Prerequisites:
|
|
# - Phase 4 (Observability) should be deployed
|
|
# - Stalwart email server running (Phase 3)
|
|
# - Vault S/MIME PKI configured (Phase 3)
|
|
# - kubectl configured for EKS cluster
|
|
#
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
INFRA_DIR="$(dirname "$SCRIPT_DIR")"
|
|
K8S_DIR="$INFRA_DIR/kubernetes"
|
|
APPS_DIR="$(dirname "$INFRA_DIR")/apps"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# Flags
|
|
DRY_RUN=false
|
|
BUILD_LOCAL=false
|
|
SKIP_FRONTEND=false
|
|
SKIP_KEY_SERVICE=false
|
|
|
|
# Configuration
|
|
REGISTRY="${REGISTRY:-ghcr.io/coherence}"
|
|
VERSION="${VERSION:-latest}"
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
--build-local)
|
|
BUILD_LOCAL=true
|
|
shift
|
|
;;
|
|
--skip-frontend)
|
|
SKIP_FRONTEND=true
|
|
shift
|
|
;;
|
|
--skip-key-service)
|
|
SKIP_KEY_SERVICE=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
echo "Usage: $0 [--dry-run] [--build-local] [--skip-frontend] [--skip-key-service]"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown option: $1${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
run_cmd() {
|
|
if [ "$DRY_RUN" = true ]; then
|
|
echo -e "${YELLOW}[DRY-RUN]${NC} Would run: $*"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
check_prerequisites() {
|
|
log_info "Checking prerequisites..."
|
|
|
|
# Check kubectl connectivity
|
|
if ! kubectl cluster-info &> /dev/null; then
|
|
log_error "kubectl not connected to cluster."
|
|
exit 1
|
|
fi
|
|
|
|
# Check Stalwart is running
|
|
if ! kubectl -n email get pods -l app=stalwart -o jsonpath='{.items[0].status.phase}' 2>/dev/null | grep -q Running; then
|
|
log_error "Stalwart email server not running. Ensure Phase 3 is complete."
|
|
exit 1
|
|
fi
|
|
|
|
# Check Vault is running
|
|
if [ "$DRY_RUN" = false ]; then
|
|
local vault_status
|
|
vault_status=$(kubectl -n vault exec vault-0 -- vault status -format=json 2>/dev/null || echo '{}')
|
|
local sealed
|
|
sealed=$(echo "$vault_status" | jq -r '.sealed // true')
|
|
if [ "$sealed" = "true" ]; then
|
|
log_error "Vault is sealed. Ensure it is unsealed."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Check build tools if building locally
|
|
if [ "$BUILD_LOCAL" = true ]; then
|
|
if ! command -v npm &> /dev/null; then
|
|
log_error "npm not found. Required for building frontend."
|
|
exit 1
|
|
fi
|
|
if ! command -v cargo &> /dev/null; then
|
|
log_error "cargo not found. Required for building key service."
|
|
exit 1
|
|
fi
|
|
if ! command -v docker &> /dev/null; then
|
|
log_error "docker not found. Required for building images."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
log_success "All prerequisites met"
|
|
}
|
|
|
|
build_frontend() {
|
|
if [ "$SKIP_FRONTEND" = true ]; then
|
|
log_warn "Skipping frontend build"
|
|
return
|
|
fi
|
|
|
|
if [ "$BUILD_LOCAL" = false ]; then
|
|
log_info "Using pre-built frontend image: $REGISTRY/webmail-frontend:$VERSION"
|
|
return
|
|
fi
|
|
|
|
log_info "Building webmail frontend..."
|
|
|
|
local webmail_dir="$APPS_DIR/webmail"
|
|
|
|
if [ ! -d "$webmail_dir" ]; then
|
|
log_warn "Webmail directory not found: $webmail_dir"
|
|
log_warn "Skipping frontend build"
|
|
return
|
|
fi
|
|
|
|
cd "$webmail_dir"
|
|
|
|
# Install dependencies
|
|
log_info "Installing npm dependencies..."
|
|
run_cmd npm install
|
|
|
|
# Build production bundle
|
|
log_info "Building production bundle..."
|
|
run_cmd npm run build
|
|
|
|
# Build Docker image
|
|
log_info "Building Docker image..."
|
|
run_cmd docker build -t "$REGISTRY/webmail-frontend:$VERSION" .
|
|
|
|
# Push to registry
|
|
if [ "$DRY_RUN" = false ]; then
|
|
log_info "Pushing image to registry..."
|
|
run_cmd docker push "$REGISTRY/webmail-frontend:$VERSION"
|
|
fi
|
|
|
|
log_success "Frontend build complete"
|
|
}
|
|
|
|
build_key_service() {
|
|
if [ "$SKIP_KEY_SERVICE" = true ]; then
|
|
log_warn "Skipping key service build"
|
|
return
|
|
fi
|
|
|
|
if [ "$BUILD_LOCAL" = false ]; then
|
|
log_info "Using pre-built key service image: $REGISTRY/key-service:$VERSION"
|
|
return
|
|
fi
|
|
|
|
log_info "Building key service..."
|
|
|
|
local key_service_dir="$APPS_DIR/key-service"
|
|
|
|
if [ ! -d "$key_service_dir" ]; then
|
|
log_warn "Key service directory not found: $key_service_dir"
|
|
log_warn "Skipping key service build"
|
|
return
|
|
fi
|
|
|
|
cd "$key_service_dir"
|
|
|
|
# Build Rust binary
|
|
log_info "Building Rust binary (release)..."
|
|
run_cmd cargo build --release
|
|
|
|
# Build Docker image
|
|
log_info "Building Docker image..."
|
|
run_cmd docker build -t "$REGISTRY/key-service:$VERSION" .
|
|
|
|
# Push to registry
|
|
if [ "$DRY_RUN" = false ]; then
|
|
log_info "Pushing image to registry..."
|
|
run_cmd docker push "$REGISTRY/key-service:$VERSION"
|
|
fi
|
|
|
|
log_success "Key service build complete"
|
|
}
|
|
|
|
deploy_webmail() {
|
|
log_info "Deploying webmail components..."
|
|
|
|
# Check if webmail manifests exist
|
|
if [ ! -d "$K8S_DIR/webmail" ]; then
|
|
log_warn "Webmail Kubernetes manifests not found: $K8S_DIR/webmail"
|
|
log_warn "Creating placeholder manifests..."
|
|
mkdir -p "$K8S_DIR/webmail"
|
|
fi
|
|
|
|
# Deploy webmail
|
|
run_cmd kubectl apply -k "$K8S_DIR/webmail/" || run_cmd kubectl apply -f "$K8S_DIR/webmail/" || true
|
|
|
|
# Wait for pods
|
|
if [ "$DRY_RUN" = false ]; then
|
|
log_info "Waiting for webmail pods to be ready..."
|
|
kubectl -n webmail wait --for=condition=ready pod -l app=webmail --timeout=300s 2>/dev/null || true
|
|
kubectl -n webmail wait --for=condition=ready pod -l app=key-service --timeout=300s 2>/dev/null || true
|
|
fi
|
|
|
|
log_success "Webmail deployment complete"
|
|
}
|
|
|
|
validate_phase5() {
|
|
log_info "Running Phase 5 validation..."
|
|
|
|
local validation_script="$SCRIPT_DIR/validate-phase5.sh"
|
|
if [ -x "$validation_script" ]; then
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_info "Would run validation script: $validation_script"
|
|
else
|
|
"$validation_script"
|
|
fi
|
|
else
|
|
log_warn "Validation script not found or not executable: $validation_script"
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
echo "========================================"
|
|
echo "Phase 5: E2EE Webmail (Optional)"
|
|
echo "RFC 0043 Deployment"
|
|
echo "========================================"
|
|
echo ""
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
log_warn "Running in DRY-RUN mode - no changes will be made"
|
|
echo ""
|
|
fi
|
|
|
|
check_prerequisites
|
|
build_frontend
|
|
build_key_service
|
|
deploy_webmail
|
|
validate_phase5
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
log_success "Phase 5 deployment complete!"
|
|
echo "========================================"
|
|
echo ""
|
|
echo "Post-deployment steps:"
|
|
echo " 1. Access webmail at https://mail.coherence.dev"
|
|
echo " 2. Login via Keycloak SSO"
|
|
echo " 3. Verify E2EE key generation works"
|
|
echo " 4. Send a test encrypted email"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Run validate-phase5.sh to verify deployment"
|
|
echo " 2. Tag this deployment: git tag -a v0.5.0-phase5 -m 'Phase 5: E2EE Webmail'"
|
|
echo " 3. Tag final release: git tag -a v1.0.0 -m 'Initial Release: Full Infrastructure Stack'"
|
|
}
|
|
|
|
main "$@"
|