fix: address code review feedback

- Replace unsafe JSON string concatenation with jq in cmd_create() and cmd_update()
- Add HTTP status code checking and error message extraction in api_call()
- Prevent JSON injection vulnerabilities from special characters
- Improve error messages with actual API responses
This commit is contained in:
Jason Woltje
2026-01-29 21:24:01 -06:00
parent 10b66ddb4a
commit bbb2ed45ea

View File

@@ -54,13 +54,30 @@ api_call() {
-H "Content-Type: application/json" -H "Content-Type: application/json"
-H "x-workspace-id: ${WORKSPACE_ID}" -H "x-workspace-id: ${WORKSPACE_ID}"
-s -s
-w "\n%{http_code}"
) )
if [[ -n "$data" ]]; then if [[ -n "$data" ]]; then
args+=(-d "$data") args+=(-d "$data")
fi fi
curl "${args[@]}" "$url" local response
response=$(curl "${args[@]}" "$url")
# Extract HTTP status code from last line
local http_code
http_code=$(echo "$response" | tail -n1)
local body
body=$(echo "$response" | sed '$d')
# Check for errors
if [[ "$http_code" -ge 400 ]]; then
local error_msg
error_msg=$(echo "$body" | jq -r '.message // .error // "API request failed"' 2>/dev/null || echo "API request failed")
error "HTTP $http_code: $error_msg"
fi
echo "$body"
} }
# Commands # Commands
@@ -142,20 +159,22 @@ cmd_create() {
[[ -z "$content" ]] && error "Content required" [[ -z "$content" ]] && error "Content required"
# Build JSON payload # Build JSON payload using jq for safety
local payload="{\"content\": \"$content\"" local payload
[[ -n "$title" ]] && payload+=", \"title\": \"$title\"" payload=$(jq -n \
[[ -n "$category" ]] && payload+=", \"category\": \"$category\"" --arg content "$content" \
[[ -n "$status" ]] && payload+=", \"status\": \"$status\"" --arg title "$title" \
[[ -n "$priority" ]] && payload+=", \"priority\": \"$priority\"" --arg category "$category" \
--arg status "$status" \
if [[ -n "$tags" ]]; then --arg priority "$priority" \
local tags_json --arg tags "$tags" \
tags_json=$(echo "$tags" | jq -R 'split(",") | map(gsub("^\\s+|\\s+$";""))') '{content: $content} +
payload+=", \"tags\": $tags_json" (if $title != "" then {title: $title} else {} end) +
fi (if $category != "" then {category: $category} else {} end) +
(if $status != "" then {status: $status} else {} end) +
payload+="}" (if $priority != "" then {priority: $priority} else {} end) +
(if $tags != "" then {tags: ($tags | split(",") | map(gsub("^\\s+|\\s+$";"")))} else {} end)'
)
response=$(api_call POST "/api/ideas" "$payload") response=$(api_call POST "/api/ideas" "$payload")
echo "$response" | jq -r '.id // empty' > /dev/null || error "Failed to create idea" echo "$response" | jq -r '.id // empty' > /dev/null || error "Failed to create idea"
@@ -257,42 +276,20 @@ cmd_update() {
esac esac
done done
# Build update payload # Build update payload using jq for safety
local payload="{" local payload
local first=true payload=$(jq -n \
--arg title "$title" \
if [[ -n "$title" ]]; then --arg content "$content" \
payload+="\"title\": \"$title\"" --arg status "$status" \
first=false --arg category "$category" \
fi --arg tags "$tags" \
'(if $title != "" then {title: $title} else {} end) +
if [[ -n "$content" ]]; then (if $content != "" then {content: $content} else {} end) +
[[ "$first" == false ]] && payload+=", " (if $status != "" then {status: $status} else {} end) +
payload+="\"content\": \"$content\"" (if $category != "" then {category: $category} else {} end) +
first=false (if $tags != "" then {tags: ($tags | split(",") | map(gsub("^\\s+|\\s+$";"")))} else {} end)'
fi )
if [[ -n "$status" ]]; then
[[ "$first" == false ]] && payload+=", "
payload+="\"status\": \"$status\""
first=false
fi
if [[ -n "$category" ]]; then
[[ "$first" == false ]] && payload+=", "
payload+="\"category\": \"$category\""
first=false
fi
if [[ -n "$tags" ]]; then
[[ "$first" == false ]] && payload+=", "
local tags_json
tags_json=$(echo "$tags" | jq -R 'split(",") | map(gsub("^\\s+|\\s+$";""))')
payload+="\"tags\": $tags_json"
first=false
fi
payload+="}"
response=$(api_call PATCH "/api/ideas/${idea_id}" "$payload") response=$(api_call PATCH "/api/ideas/${idea_id}" "$payload")
echo "$response" | jq -r '.id // empty' > /dev/null || error "Failed to update idea" echo "$response" | jq -r '.id // empty' > /dev/null || error "Failed to update idea"