# Example: Complete Deployment Configuration with Nickel + SOPS Integration # # This example shows the hybrid pattern: # 1. Infrastructure config in .ncl (readable, version-controlled) # 2. Secrets in YAML (encrypted with SOPS) # 3. Merged at deployment time let sops = import "schemas/security/sops/main.ncl" in let secrets_loader = import "schemas/security/secrets-loader.ncl" in let config_merger = import "schemas/security/config-merger.ncl" in { # ============================================ # STEP 1: Default Configuration # ============================================ defaults = { environment = "dev", deployment_mode = "solo", database = { type = "postgresql", host = "localhost", port = 5432, name = "myapp", user = "app_user", # Password placeholder - will be replaced by secrets password = "${secret:database.password}", ssl = false, pool_size = 10, }, redis = { host = "localhost", port = 6379, # Password placeholder - will be replaced by secrets password = "${secret:redis.password}", db = 0, ttl = 3600, }, api = { host = "0.0.0.0", port = 8080, # API key placeholder - will be replaced by secrets api_key = "${secret:api.api_key}", timeout = 30, max_connections = 100, }, tls = { enabled = false, # Certificate placeholders - will be replaced by secrets certificate = "${secret:tls.certificate}", private_key = "${secret:tls.private_key}", }, }, # ============================================ # STEP 2: Environment-Specific Overrides # ============================================ environments = { # All environments inherit these all = { logging = { level = "info", format = "json", }, }, # Development overrides dev = { database = { host = "postgres-dev.local", ssl = false, }, redis = { host = "redis-dev.local", }, api = { port = 8080, }, logging = { level = "debug", }, }, # Staging overrides staging = { database = { host = "postgres-staging.example.com", ssl = true, }, redis = { host = "redis-staging.example.com", }, api = { port = 443, }, tls = { enabled = true, }, logging = { level = "info", }, }, # Production overrides prod = { database = { host = "postgres-prod-cluster.example.com", port = 5432, ssl = true, pool_size = 50, }, redis = { host = "redis-prod-cluster.example.com", }, api = { port = 443, max_connections = 1000, }, tls = { enabled = true, }, logging = { level = "warn", }, }, }, # ============================================ # STEP 3: Deployment Modes # ============================================ deployment_modes = { solo = { replicas = 1, resources = { cpu = "1", memory = "512Mi", }, }, ha = { replicas = 3, resources = { cpu = "2", memory = "2Gi", }, }, enterprise = { replicas = 5, resources = { cpu = "4", memory = "4Gi", }, }, }, # ============================================ # STEP 4: SOPS Configuration # ============================================ sops_config = { dev = (sops.generate_sops_yaml "dev"), staging = (sops.generate_sops_yaml "staging"), prod = (sops.generate_sops_yaml "prod"), }, # ============================================ # STEP 5: Build Final Configuration # ============================================ # This function is called at deployment time with: # - environment: "dev" | "staging" | "prod" # - secrets: loaded from config/secrets/{env}.yaml (SOPS-encrypted) # - deployment_mode: "solo" | "ha" | "enterprise" build_config = fun environment deployment_mode secrets => let env_config = config_merger.by_environment @ { defaults = $.defaults, environments = $.environments } environment in let mode_config = ($.deployment_modes | std.record.get deployment_mode | default {}) in let base = config_merger.compose_config $.defaults env_config {} in let with_mode = config_merger.compose_config base mode_config {} in let final = config_merger.compose_config with_mode secrets {} in # Merge secrets into placeholders secrets_loader.merge final secrets, # ============================================ # Export Configuration for Different Scenarios # ============================================ # Development configuration (for local testing) config_dev = { environment = "dev", deployment_mode = "solo", config = ( config_merger.compose_config $.defaults ($.environments | std.record.get "dev") {} ), }, # Staging configuration (requires secrets) config_staging = { environment = "staging", deployment_mode = "ha", config = ( config_merger.compose_config $.defaults ($.environments | std.record.get "staging") {} ), }, # Production configuration (requires secrets) config_prod = { environment = "prod", deployment_mode = "enterprise", config = ( config_merger.compose_config $.defaults ($.environments | std.record.get "prod") {} ), }, # ============================================ # Validation # ============================================ validate = fun configuration => let required_paths = [ "database.host", "database.user", "redis.host", "api.port", ] in config_merger.validate_complete configuration required_paths, }