# Configuration Validation Guide ## Overview The new configuration system includes comprehensive schema validation to catch errors early and ensure configuration correctness. ## Schema Validation Features ### 1. Required Fields Validation Ensures all required fields are present: ```toml # Schema definition [required] fields = ["name", "version", "enabled"] # Valid config name = "my-service" version = "1.0.0" enabled = true # Invalid - missing 'enabled' name = "my-service" version = "1.0.0" # Error: Required field missing: enabled ``` ### 2. Type Validation Validates field types: ```toml # Schema [fields.port] type = "int" [fields.name] type = "string" [fields.enabled] type = "bool" # Valid port = 8080 name = "orchestrator" enabled = true # Invalid - wrong type port = "8080" # Error: Expected int, got string ``` ### 3. Enum Validation Restricts values to predefined set: ```toml # Schema [fields.environment] type = "string" enum = ["dev", "staging", "prod"] # Valid environment = "prod" # Invalid environment = "production" # Error: Must be one of: dev, staging, prod ``` ### 4. Range Validation Validates numeric ranges: ```toml # Schema [fields.port] type = "int" min = 1024 max = 65535 # Valid port = 8080 # Invalid - below minimum port = 80 # Error: Must be >= 1024 # Invalid - above maximum port = 70000 # Error: Must be <= 65535 ``` ### 5. Pattern Validation Validates string patterns using regex: ```toml # Schema [fields.email] type = "string" pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" # Valid email = "admin@example.com" # Invalid email = "not-an-email" # Error: Does not match pattern ``` ### 6. Deprecated Fields Warns about deprecated configuration: ```toml # Schema [deprecated] fields = ["old_field"] [deprecated_replacements] old_field = "new_field" # Config using deprecated field old_field = "value" # Warning: old_field is deprecated. Use new_field instead. ``` ## Using Schema Validator ### Command Line ```bash # Validate workspace config provisioning workspace config validate # Validate provider config provisioning provider validate aws # Validate platform service config provisioning platform validate orchestrator # Validate with detailed output provisioning workspace config validate --verbose ``` ### Programmatic Usage ```nushell use provisioning/core/nulib/lib_provisioning/config/schema_validator.nu * # Load config let config = (open ~/workspaces/my-project/config/provisioning.yaml | from yaml) # Validate against schema let result = (validate-workspace-config $config) # Check results if $result.valid { print "✅ Configuration is valid" } else { print "❌ Configuration has errors:" for error in $result.errors { print $" • ($error.message)" } } # Display warnings if ($result.warnings | length) > 0 { print "⚠️ Warnings:" for warning in $result.warnings { print $" • ($warning.message)" } } ``` ### Pretty Print Results ```nushell # Validate and print formatted results let result = (validate-workspace-config $config) print-validation-results $result ``` ## Schema Examples ### Workspace Schema File: `/Users/Akasha/project-provisioning/provisioning/config/workspace.schema.toml` ```toml [required] fields = ["workspace", "paths"] [fields.workspace] type = "record" [fields.workspace.name] type = "string" pattern = "^[a-z][a-z0-9-]*$" [fields.workspace.version] type = "string" pattern = "^\\d+\\.\\d+\\.\\d+$" [fields.paths] type = "record" [fields.paths.base] type = "string" [fields.paths.infra] type = "string" [fields.debug] type = "record" [fields.debug.enabled] type = "bool" [fields.debug.log_level] type = "string" enum = ["debug", "info", "warn", "error"] ``` ### Provider Schema (AWS) File: `/Users/Akasha/project-provisioning/provisioning/extensions/providers/aws/config.schema.toml` ```toml [required] fields = ["provider", "credentials"] [fields.provider] type = "record" [fields.provider.name] type = "string" enum = ["aws"] [fields.provider.region] type = "string" pattern = "^[a-z]{2}-[a-z]+-\\d+$" [fields.provider.enabled] type = "bool" [fields.credentials] type = "record" [fields.credentials.type] type = "string" enum = ["environment", "file", "iam_role"] [fields.compute] type = "record" [fields.compute.default_instance_type] type = "string" [fields.compute.default_ami] type = "string" pattern = "^ami-[a-f0-9]{8,17}$" [fields.network] type = "record" [fields.network.vpc_id] type = "string" pattern = "^vpc-[a-f0-9]{8,17}$" [fields.network.subnet_id] type = "string" pattern = "^subnet-[a-f0-9]{8,17}$" [deprecated] fields = ["old_region_field"] [deprecated_replacements] old_region_field = "provider.region" ``` ### Platform Service Schema (Orchestrator) File: `/Users/Akasha/project-provisioning/provisioning/platform/orchestrator/config.schema.toml` ```toml [required] fields = ["service", "server"] [fields.service] type = "record" [fields.service.name] type = "string" enum = ["orchestrator"] [fields.service.enabled] type = "bool" [fields.server] type = "record" [fields.server.host] type = "string" [fields.server.port] type = "int" min = 1024 max = 65535 [fields.workers] type = "int" min = 1 max = 32 [fields.queue] type = "record" [fields.queue.max_size] type = "int" min = 100 max = 10000 [fields.queue.storage_path] type = "string" ``` ### KMS Service Schema File: `/Users/Akasha/project-provisioning/provisioning/core/services/kms/config.schema.toml` ```toml [required] fields = ["kms", "encryption"] [fields.kms] type = "record" [fields.kms.enabled] type = "bool" [fields.kms.provider] type = "string" enum = ["aws_kms", "gcp_kms", "azure_kv", "vault", "local"] [fields.encryption] type = "record" [fields.encryption.algorithm] type = "string" enum = ["AES-256-GCM", "ChaCha20-Poly1305"] [fields.encryption.key_rotation_days] type = "int" min = 30 max = 365 [fields.vault] type = "record" [fields.vault.address] type = "string" pattern = "^https?://.*$" [fields.vault.token_path] type = "string" [deprecated] fields = ["old_kms_type"] [deprecated_replacements] old_kms_type = "kms.provider" ``` ## Validation Workflow ### 1. Development ```bash # Create new config vim ~/workspaces/dev/config/provisioning.yaml # Validate immediately provisioning workspace config validate # Fix errors and revalidate vim ~/workspaces/dev/config/provisioning.yaml provisioning workspace config validate ``` ### 2. CI/CD Pipeline ```yaml # GitLab CI validate-config: stage: validate script: - provisioning workspace config validate - provisioning provider validate aws - provisioning provider validate upcloud - provisioning platform validate orchestrator only: changes: - "*/config/**/*" ``` ### 3. Pre-Deployment ```bash # Validate all configurations before deployment provisioning workspace config validate --verbose provisioning provider validate --all provisioning platform validate --all # If valid, proceed with deployment if [[ $? -eq 0 ]]; then provisioning deploy --workspace production fi ``` ## Error Messages ### Clear Error Format ``` ❌ Validation failed Errors: • Required field missing: workspace.name • Field port type mismatch: expected int, got string • Field environment must be one of: dev, staging, prod • Field port must be >= 1024 • Field email does not match pattern: ^[a-zA-Z0-9._%+-]+@.*$ ⚠️ Warnings: • Field old_field is deprecated. Use new_field instead. ``` ### Error Details Each error includes: - **field**: Which field has the error - **type**: Error type (missing_required, type_mismatch, invalid_enum, etc.) - **message**: Human-readable description - **Additional context**: Expected values, patterns, ranges ## Common Validation Patterns ### Pattern 1: Hostname Validation ```toml [fields.hostname] type = "string" pattern = "^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$" ``` ### Pattern 2: Email Validation ```toml [fields.email] type = "string" pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" ``` ### Pattern 3: Semantic Version ```toml [fields.version] type = "string" pattern = "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?$" ``` ### Pattern 4: URL Validation ```toml [fields.url] type = "string" pattern = "^https?://[a-zA-Z0-9.-]+(:[0-9]+)?(/.*)?$" ``` ### Pattern 5: IPv4 Address ```toml [fields.ip_address] type = "string" pattern = "^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$" ``` ### Pattern 6: AWS Resource ID ```toml [fields.instance_id] type = "string" pattern = "^i-[a-f0-9]{8,17}$" [fields.ami_id] type = "string" pattern = "^ami-[a-f0-9]{8,17}$" [fields.vpc_id] type = "string" pattern = "^vpc-[a-f0-9]{8,17}$" ``` ## Testing Validation ### Unit Tests ```nushell # Run validation test suite nu provisioning/tests/config_validation_tests.nu ``` ### Integration Tests ```bash # Test with real configs provisioning test validate --workspace dev provisioning test validate --workspace staging provisioning test validate --workspace prod ``` ### Custom Validation ```nushell # Create custom validation function def validate-custom-config [config: record] { let result = (validate-workspace-config $config) # Add custom business logic validation if ($config.workspace.name | str starts-with "prod") { if not $config.debug.enabled == false { $result.errors = ($result.errors | append { field: "debug.enabled" type: "custom" message: "Debug must be disabled in production" }) } } $result } ``` ## Best Practices ### 1. Validate Early ```bash # Validate during development provisioning workspace config validate # Don't wait for deployment ``` ### 2. Use Strict Schemas ```toml # Be explicit about types and constraints [fields.port] type = "int" min = 1024 max = 65535 # Don't leave fields unvalidated ``` ### 3. Document Patterns ```toml # Include examples in schema [fields.email] type = "string" pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$" # Example: user@example.com ``` ### 4. Handle Deprecation ```toml # Always provide replacement guidance [deprecated_replacements] old_field = "new_field" # Clear migration path ``` ### 5. Test Schemas ```nushell # Include test cases in comments # Valid: "admin@example.com" # Invalid: "not-an-email" ``` ## Troubleshooting ### Schema File Not Found ```bash # Error: Schema file not found: /path/to/schema.toml # Solution: Ensure schema exists ls -la /Users/Akasha/project-provisioning/provisioning/config/*.schema.toml ``` ### Pattern Not Matching ```bash # Error: Field hostname does not match pattern # Debug: Test pattern separately echo "my-hostname" | grep -E "^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$" ``` ### Type Mismatch ```bash # Error: Expected int, got string # Check config cat ~/workspaces/dev/config/provisioning.yaml | yq '.server.port' # Output: "8080" (string) # Fix: Remove quotes vim ~/workspaces/dev/config/provisioning.yaml # Change: port: "8080" # To: port: 8080 ``` ## Additional Resources - [Migration Guide](./MIGRATION_GUIDE.md) - [Workspace Guide](./WORKSPACE_GUIDE.md) - [Schema Files](../config/*.schema.toml) - [Validation Tests](../tests/config_validation_tests.nu)