# SOPS YAML Generator - Converts Nickel SOPS config to .sops.yaml format let contracts = import "contracts.ncl" in let defaults = import "defaults.ncl" in { # Generate a single SOPS rule as YAML-compatible record rule_to_yaml = fun rule => let base = { age = rule.age, } in let with_path = if std.string.is_empty rule.path_regex then base else base & { path_regex = rule.path_regex } in let with_regex = if std.record.has_field "encrypted_regex" rule then with_path & { encrypted_regex = rule.encrypted_regex } else with_path in with_regex, # Generate creation_rules section generate_creation_rules = fun config => { creation_rules = std.array.map rule_to_yaml config.creation_rules, }, # Generate full .sops.yaml configuration for an environment generate_sops_yaml = fun environment => let env_config = std.record.get environment defaults in let rules_section = generate_creation_rules env_config in rules_section, # Generate all environment configurations generate_all_environments = fun => { dev = generate_sops_yaml "dev", staging = generate_sops_yaml "staging", prod = generate_sops_yaml "prod", }, # Helper: Get Age public key from vault-service response extract_public_key = fun vault_response => vault_response.public_key, # Helper: Update config with actual Age keys from vault-service inject_vault_keys = fun sops_config vault_keys => let update_rule = fun rule environment => rule & { age = std.record.get environment vault_keys, } in sops_config, # Serialize SOPS config to YAML-compatible text serialize_to_yaml = fun config => let serialize_rule = fun rule => let parts = [] in let parts = if std.record.has_field "path_regex" rule then parts @ [ $" - path_regex: {rule.path_regex}" ] else parts @ [ " -" ] in let parts = parts @ [ $" age: '{rule.age}'" ] in let parts = if std.record.has_field "encrypted_regex" rule then parts @ [ $" encrypted_regex: '{rule.encrypted_regex}'" ] else parts in std.string.join "\n" parts in let rules_text = std.array.join "\n" (std.array.map serialize_rule config.creation_rules) in $"# SOPS creation rules - evaluated sequentially, first match wins\ncreation_rules:\n{rules_text}\n", }