fix: [nomad-step-2] S2.2 — tools/vault-import.sh (import .env + sops into KV) (#880) #889

Merged
dev-qwen2 merged 6 commits from fix/issue-880 into main 2026-04-16 17:39:06 +00:00
Showing only changes of commit 428fa223d8 - Show all commits

View file

@ -133,8 +133,8 @@ _kv_put_secret() {
for kv in "${kv_pairs[@]}"; do for kv in "${kv_pairs[@]}"; do
local k="${kv%%=*}" local k="${kv%%=*}"
local v="${kv#*=}" local v="${kv#*=}"
# Use jq to merge the new pair into the data object # Use jq with --arg for safe string interpolation (handles quotes/backslashes)
payload="$(printf '%s' "$payload" | jq ". * {\"data\": {\"$k\": \"$v\"}}")" payload="$(printf '%s' "$payload" | jq --arg k "$k" --arg v "$v" '. * {"data": {($k): $v}}')"
done done
# Use curl directly for KV v2 write with versioning # Use curl directly for KV v2 write with versioning
@ -499,8 +499,11 @@ EOF
done done
# Second pass: group by vault_path and write # Second pass: group by vault_path and write
# IMPORTANT: Always write ALL keys for a path, not just changed ones.
# KV v2 POST replaces the entire document, so we must include unchanged keys
# to avoid dropping them. The idempotency guarantee comes from KV v2 versioning.
declare -A paths_to_write declare -A paths_to_write
declare -A path_statuses declare -A path_has_changes
for key in "${!ops_data[@]}"; do for key in "${!ops_data[@]}"; do
local data="${ops_data[$key]}" local data="${ops_data[$key]}"
@ -509,25 +512,26 @@ EOF
local vault_path="${key%:*}" local vault_path="${key%:*}"
local vault_key="${key#*:}" local vault_key="${key#*:}"
if [ "$status" = "unchanged" ]; then # Always add to paths_to_write (all keys for this path)
_format_status "$status" "$vault_path" "$vault_key" if [ -z "${paths_to_write[$vault_path]:-}" ]; then
printf '\n' paths_to_write[$vault_path]="${vault_key}=${source_value}"
((unchanged++)) || true
else else
# Add to paths_to_write for this vault_path paths_to_write[$vault_path]="${paths_to_write[$vault_path]}|${vault_key}=${source_value}"
if [ -z "${paths_to_write[$vault_path]:-}" ]; then fi
paths_to_write[$vault_path]="${vault_key}=${source_value}"
else # Track if this path has any changes (for status reporting)
paths_to_write[$vault_path]="${paths_to_write[$vault_path]}|${vault_key}=${source_value}" if [ "$status" != "unchanged" ]; then
fi path_has_changes[$vault_path]=1
# Track status for counting (use last status for the path)
path_statuses[$vault_path]="$status"
fi fi
done done
# Write each path with all its key-value pairs # Write each path with all its key-value pairs
for vault_path in "${!paths_to_write[@]}"; do for vault_path in "${!paths_to_write[@]}"; do
local status="${path_statuses[$vault_path]}" # Determine effective status for this path (updated if any key changed)
local effective_status="unchanged"
if [ "${path_has_changes[$vault_path]:-}" = "1" ]; then
effective_status="updated"
fi
# Read pipe-separated key-value pairs and write them # Read pipe-separated key-value pairs and write them
local pairs_string="${paths_to_write[$vault_path]}" local pairs_string="${paths_to_write[$vault_path]}"
@ -543,14 +547,14 @@ EOF
# Output status for each key in this path # Output status for each key in this path
for kv in "${pairs_array[@]}"; do for kv in "${pairs_array[@]}"; do
local kv_key="${kv%%=*}" local kv_key="${kv%%=*}"
_format_status "$status" "$vault_path" "$kv_key" _format_status "$effective_status" "$vault_path" "$kv_key"
printf '\n' printf '\n'
done done
case "$status" in # Count only if path has changes
updated) ((updated++)) || true ;; if [ "$effective_status" = "updated" ]; then
created) ((created++)) || true ;; ((updated++)) || true
esac fi
done done
_log "" _log ""