fix(framework/tools): eval injection, broken JSON, tmpfile leak (#548)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful

F-01 (HIGH): issue-edit.sh and issue-assign.sh used string interpolation
+ eval to build CLI commands. Replace all eval sites with Bash arrays so
user-supplied values (title, body, labels) are never shell-expanded.
For the Gitea path, replace get_gitea_repo_args() (which emits %q-escaped
strings designed for eval) with get_repo_slug() + get_gitea_login() so
repo/login are passed as properly-quoted array elements.

F-07 (MED): milestone-create.sh built the GitHub API JSON payload by
string interpolation — a title containing " or $ broke the JSON. Rebuild
with jq -n --arg so all values are safely serialised. Optional description
key is omitted when empty, preserving existing behaviour.

F-13 (LOW): pr-metadata.sh created a mktemp tmpfile inside
curl_gitea_pull() but only removed it in success paths. Add
trap 'rm -f "$body_file"' EXIT immediately after mktemp so early-exit
paths (set -e, SIGINT) also clean up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Kt2D8TsnDwhtzEAPijsNmR
This commit is contained in:
Hermes Agent
2026-06-18 13:51:18 -05:00
parent b8807e60df
commit b0b2c20da0
4 changed files with 42 additions and 26 deletions

View File

@@ -98,27 +98,32 @@ case "$PLATFORM" in
;;
gitea)
# tea issue edit syntax
REPO_ARGS=$(get_gitea_repo_args) || {
echo "Error: Could not resolve Gitea repo/login args for remote host" >&2
REPO_SLUG=$(get_repo_slug) || {
echo "Error: Could not resolve Gitea repo slug from remote" >&2
exit 1
}
CMD="tea issue edit $ISSUE $REPO_ARGS"
REPO_LOGIN=$(get_gitea_login) || {
echo "Error: Could not resolve Gitea login for remote host" >&2
exit 1
}
REPO_ARGS=(--repo "$REPO_SLUG" --login "$REPO_LOGIN")
CMD=(tea issue edit "$ISSUE" "${REPO_ARGS[@]}")
NEEDS_EDIT=false
if [[ -n "$ASSIGNEE" ]]; then
# tea uses --assignees flag
CMD="$CMD --assignees \"$ASSIGNEE\""
CMD+=(--assignees "$ASSIGNEE")
NEEDS_EDIT=true
fi
if [[ -n "$LABELS" ]]; then
# tea uses --labels flag (replaces existing)
CMD="$CMD --labels \"$LABELS\""
CMD+=(--labels "$LABELS")
NEEDS_EDIT=true
fi
if [[ -n "$MILESTONE" ]]; then
MILESTONE_ID=$(tea milestones list $REPO_ARGS 2>/dev/null | grep -E "^\s*[0-9]+" | grep "$MILESTONE" | awk '{print $1}' | head -1)
MILESTONE_ID=$(tea milestones list "${REPO_ARGS[@]}" 2>/dev/null | grep -E "^\s*[0-9]+" | grep "$MILESTONE" | awk '{print $1}' | head -1)
if [[ -n "$MILESTONE_ID" ]]; then
CMD="$CMD --milestone $MILESTONE_ID"
CMD+=(--milestone "$MILESTONE_ID")
NEEDS_EDIT=true
else
echo "Warning: Could not find milestone '$MILESTONE'" >&2
@@ -126,7 +131,7 @@ case "$PLATFORM" in
fi
if [[ "$NEEDS_EDIT" == true ]]; then
eval "$CMD"
"${CMD[@]}"
echo "Issue #$ISSUE updated successfully"
else
echo "No changes specified"