fix: [nomad-step-2] S2.2 — Fix KV v2 overwrite for incremental updates and secure jq interpolation (#880)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/nomad-validate Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/secret-scan Pipeline was successful
ci/woodpecker/pr/smoke-init Pipeline was successful

This commit is contained in:
dev-qwen2 2026-04-16 17:22:02 +00:00
parent 197716ed5c
commit 428fa223d8

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"
printf '\n'
((unchanged++)) || true
else
# Add to paths_to_write for this vault_path
if [ -z "${paths_to_write[$vault_path]:-}" ]; then if [ -z "${paths_to_write[$vault_path]:-}" ]; then
paths_to_write[$vault_path]="${vault_key}=${source_value}" paths_to_write[$vault_path]="${vault_key}=${source_value}"
else else
paths_to_write[$vault_path]="${paths_to_write[$vault_path]}|${vault_key}=${source_value}" paths_to_write[$vault_path]="${paths_to_write[$vault_path]}|${vault_key}=${source_value}"
fi fi
# Track status for counting (use last status for the path)
path_statuses[$vault_path]="$status" # Track if this path has any changes (for status reporting)
if [ "$status" != "unchanged" ]; then
path_has_changes[$vault_path]=1
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 ""