# SOPS Integration Module - Manage encrypted secrets with Age keys let contracts = import "contracts.ncl" in let defaults = import "defaults.ncl" in let generator = import "generator.ncl" in { # Type exports SopsRule = contracts.SopsRule, SopsConfig = contracts.SopsConfig, SopsEnvironmentConfig = contracts.SopsEnvironmentConfig, # Configuration exports defaults = defaults, # Generator exports generate_creation_rules = generator.generate_creation_rules, generate_sops_yaml = generator.generate_sops_yaml, generate_all_environments = generator.generate_all_environments, serialize_to_yaml = generator.serialize_to_yaml, # Initialize SOPS configuration for an environment with Age keys init_environment = fun environment age_public_key => let config = generator.generate_sops_yaml environment in let update_rules = fun rules => std.array.map (fun rule => rule & { age = age_public_key }) rules in config & { creation_rules = update_rules config.creation_rules }, # Merge user SOPS rules with defaults (user rules take precedence) merge_with_defaults = fun environment user_config => let default_config = generator.generate_sops_yaml environment in { creation_rules = (user_config.creation_rules or default_config.creation_rules), }, # Validate SOPS configuration has required fields validate_config = fun config => let has_rules = std.array.length config.creation_rules > 0 in let all_rules_valid = std.array.all (fun rule => not (std.string.is_empty rule.age) && std.string.length rule.age > 10 # Basic Age key format check ) config.creation_rules in has_rules && all_rules_valid, # Generate complete .sops.yaml file content generate_file = fun environment age_public_key => let config = init_environment environment age_public_key in generator.serialize_to_yaml config, }