use std def find_file [ start_path: string match_path: string only_first: bool ] { mut found_path = "" mut search_path = $start_path let home_root = ($env.HOME | path dirname) while $found_path == "" and $search_path != "/" and $search_path != $home_root { if $search_path == "" { break } let res = if $only_first { (^find $search_path -type f -name $match_path -print -quit | complete) } else { (^find $search_path -type f -name $match_path err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | complete) } if $res.exit_code == 0 { $found_path = ($res.stdout | str trim ) } $search_path = ($search_path | path dirname) } $found_path } export def run_cmd_sops [ task: string cmd: string source_path: string error_exit: bool ]: nothing -> string { let str_cmd = $"-($cmd)" let res = if ($env.PROVISIONING_USE_SOPS | str contains "age") { if $env.SOPS_AGE_RECIPIENTS? != null { # print $"SOPS_AGE_KEY_FILE=($env.PROVISIONING_KAGE) ; sops ($str_cmd) --config ($env.PROVISIONING_SOPS) --age ($env.SOPS_AGE_RECIPIENTS) ($source_path)" (^bash -c SOPS_AGE_KEY_FILE=($env.PROVISIONING_KAGE) ; sops $str_cmd --config $env.PROVISIONING_SOPS --age $env.SOPS_AGE_RECIPIENTS $source_path | complete ) } else { if $error_exit { (throw-error $"πŸ›‘ Sops with age error" $"(_ansi red)no AGE_RECIPIENTS(_ansi reset) for (_ansi green)($source_path)(_ansi reset)" "on_sops decrypt" --span (metadata $task).span) } else { _print $"πŸ›‘ Sops with age error (_ansi red)no AGE_RECIPIENTS(_ansi reset) for (_ansi green_bold)($source_path)(_ansi reset)" return "" } } } else { (^sops $str_cmd --config $env.PROVISIONING_SOPS $source_path | complete ) } if $res.exit_code != 0 { if $error_exit { (throw-error $"πŸ›‘ Sops error" $"(_ansi red)($source_path)(_ansi reset) ($res.stdout)" $"on_sops ($task)" --span (metadata $res).span) } else { _print $"πŸ›‘ Sops error (_ansi red)($source_path)(_ansi reset) ($res.exit_code)" return "" } } return $res.stdout } export def on_sops [ task: string # source_path: string # output_path?: string # ...args # Args for create command --check (-c) # Only check mode no servers will be created --error_exit --quiet ]: nothing -> string { #[ -z "$PROVIISONING_SOPS" ] && echo "PROVIISONING_SOPS not defined on_sops $sops_task for $source to $target" && return # if [ -z "$PROVIISONING_SOPS" ] && [ -z "$($YQ -er '.sops' < "$source" 2>(if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | sed 's/null//g')" ]; then # [ -z "$source" ] && echo "Error not source file found" && return # [ -z "$target" ] && cat "$source" && return # [ "$source" != "$target" ] && cat "$source" > "$target" # return # fi # [ -n "$PROVIISONING_SOPS" ] && cfg_ops="--config $PROVIISONING_SOPS" # [ -n "$target" ] && output="--output $target" match $task { "sed" => { # check is a sops file or error if (is_sops_file $source_path) { ^sops $source_path } else { (throw-error $"πŸ›‘ File (_ansi green_italic)($source_path)(_ansi reset) exists" $"No (_ansi yellow_bold)sops(_ansi reset) content found " "on_sops sed" --span (metadata $source_path).span ) } }, "is_sops" | "i" => { return (is_sops_file $source_path) }, "encrypt" | "encode" | "e" => { if not ( $source_path | path exists ) { if not $quiet { _print $"πŸ›‘ No file ($source_path) found to decrypt with sops " } return "" } if (is_sops_file $source_path) { if not $quiet { _print $"πŸ›‘ File ($source_path) alredy with sops " } return (open -r $source_path) } let result = (run_cmd_sops "encrypt" "e" $source_path $error_exit) if ($output_path | is-not-empty) { $result | save -f $output_path if not $quiet { _print $"Result saved in ($output_path) " } } return $result }, "generate" | "gen" | "g" => { generate_sops_file $source_path $output_path $quiet }, "decrypt" | "decode" | "d" => { if not ( $source_path | path exists ) { if not $quiet { _print $"πŸ›‘ No file ($source_path) found to decrypt with sops " } return "" } if not (is_sops_file $source_path) { if not $quiet { _print $"πŸ›‘ File ($source_path) does not have sops info " } return (open -r $source_path) } let result = (run_cmd_sops "decrypt" "d" $source_path $error_exit) if ($output_path | is-not-empty) { $result | save -f $output_path if not $quiet { _print $"Result saved in ($output_path) " } } return $result }, _ => { (throw-error $"πŸ›‘ Option " $"(_ansi red)($task)(_ansi reset) undefined") return "" } } } export def generate_sops_file [ source_path: string target_path: string quiet: bool ]: nothing -> bool { let result = (on_sops "encrypt" $source_path --error_exit) if result == "" { _print $"πŸ›‘ File ($source_path) not sops generated" return false } $result | save -f $target_path if not $quiet { _print $"($source_path) generated for 'sops' " } return true } export def generate_sops_settings [ mode: string target: string file: string ]: nothing -> nothing { _print "" # [ -z "$ORG_MAIN_SETTINGS_FILE" ] && return # [ -r "$PROVIISONING_KEYS_PATH" ] && [ -n "$PROVIISONING_USE_KCL" ] && _on_sops_item "$mode" "$PROVIISONING_KEYS_PATH" "$target" # file=$($YQ -er < "$ORG_MAIN_SETTINGS_FILE" ".defaults_path" | sed 's/null//g') # [ -n "$file" ] && _on_sops_item "$mode" "$file" "$target" # _on_sops_item "$mode" "$ORG_MAIN_SETTINGS_FILE" "$target" # list=$($YQ -er < "$ORG_MAIN_SETTINGS_FILE" ".servers_paths[]" 2>(if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | sed 's/null//g') # [ -n "$list" ] && for item_file in $list ; do _on_sops_item "$mode" "$item_file" "$target" ; done # list=$($YQ -er < "$ORG_MAIN_SETTINGS_FILE" ".services_paths[]" 2> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" })| sed 's/null//g') # [ -n "$list" ] && for item_file in $list ; do _on_sops_item "$mode" "$item_file" "$target" ; done } export def edit_sop [ items: list ]: nothing -> nothing { _print "" # [ -z "$PROVIISONING_USE_SOPS" ] && echo "πŸ›‘ No PROVIISONING_USE_SOPS value foud review environment settings or provisioning installation " && return 1 # [ ! -r "$1" ] && echo "❗Error no file $1 found " && exit 1 # if [ -z "$($YQ e '.sops' < "$1" 2>(if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) | sed 's/null//g')" } # echo "❗File $1 not 'sops' signed with $PROVIISONING_USE_SOPS " # exit # } # _check_sops # [ -z "$PROVIISONING_SOPS" ] && return 1 # for it in $items { # [ -r "$it" ] && sops "$it" # } } # TODO migrate all SOPS code from bash export def is_sops_file [ target: string ]: nothing -> bool { if not ($target | path exists) { (throw-error $"πŸ›‘ File (_ansi green_italic)($target)(_ansi reset)" $"(_ansi red_bold)Not found(_ansi reset)" $"is_sops_file ($target)" --span (metadata $target).span ) } let file_sops = (open $target --raw ) if ($file_sops | find "sops" | length) == 0 { return false } if ($file_sops | find "ENC[" | length) == 0 { return false } #let sops = ($file_sops | from json).sops? | default "") #($sops.mac? != null and $sops.mac != "") return true } export def decode_sops_file [ source: string target: string quiet: bool ]: nothing -> nothing { if $quiet { on_sops "decrypt" $source --quiet } else { on_sops "decrypt" $source } | save --force $target } export def get_def_sops [ current_path: string ]: nothing -> string { if $env.PROVISIONING_USE_SOPS == "" { return ""} let start_path = if ($current_path | path exists) { $current_path } else { $"($env.PROVISIONING_KLOUD_PATH)/($current_path)" } let sops_file = "sops.yaml" # use ../lib_provisioning/utils/files.nu find_file mut provisioning_sops = (find_file $start_path $sops_file true ) if $provisioning_sops == "" and ($env.HOME | path join ".config"| path join "provisioning" | path join $sops_file | path exists ) { $provisioning_sops = ($env.HOME | path join ".config"| path join "provisioning" | path join $sops_file ) } if $provisioning_sops == "" and ($env.HOME | path join ".provisioning"| path join $sops_file | path exists ) { $provisioning_sops = ($env.HOME | path join ".provisioning"| path join $sops_file ) } if $provisioning_sops == "" { _print $"❗Error no (_ansi red_bold)($sops_file)(_ansi reset) file for secure operations found " exit 1 } ($provisioning_sops | default "") } export def get_def_age [ current_path: string ]: nothing -> string { # Check if SOPS is configured for age encryption let use_sops = ($env.PROVISIONING_USE_SOPS? | default "age") if not ($use_sops | str contains "age") { return "" } let kage_file = ".kage" let start_path = if ($current_path | path exists) { $current_path } else { ($env.PROVISIONING_INFRA_PATH | path join $current_path) } #use utils/files.nu find_file let provisioning_kage = (find_file $start_path $kage_file true) let provisioning_kage = if $provisioning_kage == "" and ($env.HOME | path join ".config" | path join "provisioning "| path join $kage_file | path exists ) { ($env.HOME | path join ".config" | path join "provisioning "| path join $kage_file ) } else { $provisioning_kage } let provisioning_kage = if $provisioning_kage == "" and ($env.HOME | path join ".provisioning "| path join $kage_file | path exists ) { ($env.HOME | path join ".provisioning "| path join $kage_file ) } else { $provisioning_kage } let provisioning_kage = if $provisioning_kage == "" and ($env.PROVISIONING_KLOUD_PATH? != null) and (($env.PROVISIONING_KLOUD_PATH | path join ".provisioning" | path join $kage_file) | path exists ) { ($env.PROVISIONING_KLOUD_PATH | path join ".provisioning" | path join $kage_file ) } else { $provisioning_kage } if $provisioning_kage == "" { _print $"❗Error no (_ansi red_bold)($kage_file)(_ansi reset) file for secure operations found " exit 1 } ($provisioning_kage | default "") }