# Settings Validation Module # Validates configuration settings, paths, and user inputs # Follows Nushell guidelines: explicit types, single purpose, no try-catch use ./mod.nu * # ============================================================================ # PATH VALIDATION # ============================================================================ # Validate configuration base path export def validate-config-path [ path: string ]: nothing -> record { let path_exists = ($path | path exists) let path_is_dir = (if $path_exists { ($path | path type) == "dir" } else { false }) let path_writable = ((do { mkdir $path } | complete) | get exit_code) == 0 let is_valid = ($path_exists and $path_is_dir) { path: $path exists: $path_exists is_directory: $path_is_dir writable: $path_writable valid: $is_valid } } # Validate workspace path export def validate-workspace-path [ workspace_name: string workspace_path: string ]: nothing -> record { let config_base = (get-config-base-path) let required_dirs = ["config", "infra"] mut missing_dirs = [] for dir in $required_dirs { let dir_path = $"($workspace_path)/($dir)" if not ($dir_path | path exists) { $missing_dirs = ($missing_dirs | append $dir) } } let workspace_exists = ($workspace_path | path exists) let is_dir = (if $workspace_exists { ($workspace_path | path type) == "dir" } else { false }) let has_config_file = ($"($workspace_path)/config/provisioning.k" | path exists) let is_valid = ($workspace_exists and ($missing_dirs | length) == 0) { workspace_name: $workspace_name path: $workspace_path exists: $workspace_exists is_directory: $is_dir has_config: $has_config_file missing_directories: $missing_dirs valid: $is_valid } } # ============================================================================ # CONFIGURATION VALUE VALIDATION # ============================================================================ # Validate OS name export def validate-os-name [ os_name: string ]: nothing -> record { let valid_os = ["linux", "macos", "windows"] let is_valid = ($os_name in $valid_os) let error_msg = (if not $is_valid { $"Invalid OS: ($os_name)" } else { null }) { value: $os_name valid_values: $valid_os valid: $is_valid error: $error_msg } } # Validate port number export def validate-port-number [ port: int ]: nothing -> record { let is_valid = ($port >= 1 and $port <= 65535) let error_msg = (if not $is_valid { "Port must be between 1 and 65535" } else { null }) { port: $port valid: $is_valid error: $error_msg } } # Validate port is available export def validate-port-available [ port: int ]: nothing -> record { let port_valid = (validate-port-number $port) if not $port_valid.valid { return $port_valid } let available = (is-port-available $port) let error_msg = (if not $available { $"Port ($port) is already in use" } else { null }) { port: $port valid: $available available: $available error: $error_msg } } # Validate provider name export def validate-provider-name [ provider_name: string ]: nothing -> record { let valid_providers = ["upcloud", "aws", "hetzner", "local"] let is_valid = ($provider_name in $valid_providers) let error_msg = (if not $is_valid { $"Unknown provider: ($provider_name)" } else { null }) { provider: $provider_name valid_providers: $valid_providers valid: $is_valid error: $error_msg } } # Validate email address format export def validate-email [ email: string ]: nothing -> record { let email_pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" let is_valid = ($email | str contains "@") let error_msg = (if not $is_valid { "Invalid email format" } else { null }) { email: $email valid: $is_valid error: $error_msg } } # ============================================================================ # SYSTEM RESOURCE VALIDATION # ============================================================================ # Validate CPU count export def validate-cpu-count [ cpu_count: int ]: nothing -> record { let is_valid = ($cpu_count >= 1 and $cpu_count <= 1024) let error_msg = (if not $is_valid { "CPU count must be between 1 and 1024" } else { null }) { cpu_count: $cpu_count valid: $is_valid valid_range: "1-1024" error: $error_msg } } # Validate memory allocation in GB export def validate-memory-gb [ memory_gb: int ]: nothing -> record { let is_valid = ($memory_gb >= 1 and $memory_gb <= 4096) let error_msg = (if not $is_valid { "Memory must be between 1 and 4096 GB" } else { null }) { memory_gb: $memory_gb valid: $is_valid valid_range: "1-4096 GB" error: $error_msg } } # Validate disk space in GB export def validate-disk-gb [ disk_gb: int ]: nothing -> record { let is_valid = ($disk_gb >= 10 and $disk_gb <= 100000) let error_msg = (if not $is_valid { "Disk space must be between 10 and 100000 GB" } else { null }) { disk_gb: $disk_gb valid: $is_valid valid_range: "10-100000 GB" error: $error_msg } } # ============================================================================ # COMPLEX VALIDATION # ============================================================================ # Validate complete system configuration export def validate-system-config [ config: record ]: nothing -> record { mut errors = [] mut warnings = [] # Validate OS name let os_validation = (validate-os-name ($config.os_name? | default "linux")) if not $os_validation.valid { $errors = ($errors | append $os_validation.error) } # Validate paths if ($config.install_path? != null) { let path_validation = (validate-config-path $config.install_path) if not $path_validation.valid { $errors = ($errors | append $"Invalid install_path: ($config.install_path)") } } # Validate CPU count if ($config.cpu_count? != null) { let cpu_validation = (validate-cpu-count $config.cpu_count) if not $cpu_validation.valid { $errors = ($errors | append $cpu_validation.error) } } # Validate memory if ($config.memory_gb? != null) { let mem_validation = (validate-memory-gb $config.memory_gb) if not $mem_validation.valid { $errors = ($errors | append $mem_validation.error) } } # Validate disk if ($config.disk_gb? != null) { let disk_validation = (validate-disk-gb $config.disk_gb) if not $disk_validation.valid { $errors = ($errors | append $disk_validation.error) } } let is_valid = ($errors | length) == 0 let error_count = ($errors | length) let warning_count = ($warnings | length) { valid: $is_valid errors: $errors warnings: $warnings error_count: $error_count warning_count: $warning_count } } # Validate workspace configuration export def validate-workspace-config [ workspace_name: string workspace_path: string config: record ]: nothing -> record { mut errors = [] mut warnings = [] # Validate workspace name if ($workspace_name | str length) == 0 { $errors = ($errors | append "Workspace name cannot be empty") } # Validate workspace path let path_validation = (validate-workspace-path $workspace_name $workspace_path) if not $path_validation.valid { $errors = ($errors | append $"Invalid workspace path: ($workspace_path)") if ($path_validation.missing_directories | length) > 0 { $warnings = ($warnings | append $"Missing directories: ($path_validation.missing_directories | str join ', ')") } } # Validate active providers if specified if ($config.active_providers? != null) { for provider in $config.active_providers { let provider_validation = (validate-provider-name $provider) if not $provider_validation.valid { $errors = ($errors | append $provider_validation.error) } } } let is_valid = ($errors | length) == 0 let error_count = ($errors | length) let warning_count = ($warnings | length) { workspace_name: $workspace_name valid: $is_valid errors: $errors warnings: $warnings error_count: $error_count warning_count: $warning_count } } # Validate platform services configuration export def validate-platform-config [ config: record ]: nothing -> record { mut errors = [] mut warnings = [] # Validate orchestrator port if ($config.orchestrator_port? != null) { let port_validation = (validate-port-number $config.orchestrator_port) if not $port_validation.valid { $errors = ($errors | append $port_validation.error) } } # Validate control center port if ($config.control_center_port? != null) { let port_validation = (validate-port-number $config.control_center_port) if not $port_validation.valid { $errors = ($errors | append $port_validation.error) } } # Validate KMS port if ($config.kms_port? != null) { let port_validation = (validate-port-number $config.kms_port) if not $port_validation.valid { $errors = ($errors | append $port_validation.error) } } # Check for port conflicts let ports = [ ($config.orchestrator_port? | default 9090), ($config.control_center_port? | default 3000), ($config.kms_port? | default 3001) ] for port in $ports { if not (is-port-available $port) { $warnings = ($warnings | append $"Port ($port) is already in use") } } let is_valid = ($errors | length) == 0 let error_count = ($errors | length) let warning_count = ($warnings | length) { valid: $is_valid errors: $errors warnings: $warnings error_count: $error_count warning_count: $warning_count } } # ============================================================================ # VALIDATION REPORT # ============================================================================ # Print validation report export def print-validation-report [ report: record ]: nothing -> nothing { print "" print "═══════════════════════════════════════════════════════════════" print " VALIDATION REPORT" print "═══════════════════════════════════════════════════════════════" print "" if $report.valid { print "✅ All validation checks passed!" } else { print "❌ Validation failed with errors" } print "" if ($report.error_count? | default 0) > 0 { print "ERRORS:" for error in ($report.errors? | default []) { print $" ❌ ($error)" } print "" } if ($report.warning_count? | default 0) > 0 { print "WARNINGS:" for warning in ($report.warnings? | default []) { print $" ⚠️ ($warning)" } print "" } print "═══════════════════════════════════════════════════════════════" print "" } # Validate all system requirements are met export def validate-requirements [ detection_report: record ]: nothing -> record { let missing_tools = (get-missing-required-tools $detection_report) let all_requirements_met = ($missing_tools | length) == 0 { all_requirements_met: $all_requirements_met missing_tools: $missing_tools internet_available: $detection_report.network.internet_connected recommended_tools: [ "kcl", "sops", "age", "docker" # or kubernetes or ssh ] } }