git: 3ab8697d9e45 - main - git-arc: Do not echo unescaped literals to jq

From: Mateusz Piotrowski <0mp_at_FreeBSD.org>
Date: Fri, 25 Oct 2024 13:23:27 UTC
The branch main has been updated by 0mp:

URL: https://cgit.FreeBSD.org/src/commit/?id=3ab8697d9e45adc504142a4aa06d2b5c9245f4e6

commit 3ab8697d9e45adc504142a4aa06d2b5c9245f4e6
Author:     Jose Luis Duran <jlduran@gmail.com>
AuthorDate: 2024-10-25 13:20:53 +0000
Commit:     Mateusz Piotrowski <0mp@FreeBSD.org>
CommitDate: 2024-10-25 13:23:02 +0000

    git-arc: Do not echo unescaped literals to jq
    
    Store the json blobs in temporary files instead of variables, and feed
    them to jq for parsing.
    
    When echoing "\n", the new line will become a literal new line, and
    therefore, invalid json input:
    
    ```
    jq: parse error: Invalid string: control characters from U+0000 through U+001F must be escaped ...
    ```
    
    To reproduce:
    
        % git arc patch -c D12345
    
    Reviewed by:    0mp, imp, markj
    Approved by:    markj (mentor)
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D46767
---
 tools/tools/git/git-arc.sh | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/tools/tools/git/git-arc.sh b/tools/tools/git/git-arc.sh
index 3261f4461dc6..cca70f61a4cd 100644
--- a/tools/tools/git/git-arc.sh
+++ b/tools/tools/git/git-arc.sh
@@ -548,32 +548,32 @@ patch_commit()
     diff=$1
     reviewid=$(diff2phid "$diff")
     # Get the author phid for this patch
-    review_data=$(echo '{
-                  "constraints": {"phids": ["'"$reviewid"'"]}
-		}' |
-        arc_call_conduit -- differential.revision.search)
-    authorid=$(echo "$review_data" | jq -r '.response.data[].fields.authorPHID' )
+    review_data=$(mktemp)
+    echo '{"constraints": {"phids": ["'"$reviewid"'"]}}' | \
+        arc_call_conduit -- differential.revision.search > "$review_data"
+    authorid=$(jq -r '.response.data[].fields.authorPHID' "$review_data")
     # Get metadata about the user that submitted this patch
-    user_data=$(echo '{
-                  "constraints": {"phids": ["'"$authorid"'"]}
-		}' |
-            arc call-conduit -- user.search | grep -v ^Warning: |
-            jq -r '.response.data[].fields')
-    user_addr=$(echo "$user_data" | jq -r '.username')
-    user_name=$(echo "$user_data" | jq -r '.realName')
+    user_data=$(mktemp)
+    echo '{"constraints": {"phids": ["'"$authorid"'"]}}' | \
+        arc_call_conduit -- user.search | \
+        jq -r '.response.data[].fields' > "$user_data"
+    user_addr=$(jq -r '.username' "$user_data")
+    user_name=$(jq -r '.realName' "$user_data")
+    rm "$user_data"
     # Dig the data out of querydiffs api endpoint, although it's deprecated,
     # since it's one of the few places we can get email addresses. It's unclear
     # if we can expect multiple difference ones of these. Some records don't
     # have this data, so we remove all the 'null's. We sort the results and
     # remove duplicates 'just to be sure' since we've not seen multiple
     # records that match.
-    diff_data=$(echo '{
-		"revisionIDs": [ '"${diff#D}"' ]
-		}' | arc_call_conduit -- differential.querydiffs |
-	     jq -r '.response | flatten | .[]')
-    author_addr=$(echo "$diff_data" | jq -r ".authorEmail?" | sort -u)
-    author_name=$(echo "$diff_data" | jq -r ".authorName?" | sort -u)
+    diff_data=$(mktemp)
+    echo '{"revisionIDs": [ '"${diff#D}"' ]}' | \
+        arc_call_conduit -- differential.querydiffs |
+        jq -r '.response | flatten | .[]' > "$diff_data"
+    author_addr=$(jq -r ".authorEmail?" "$diff_data" | sort -u)
+    author_name=$(jq -r ".authorName?" "$diff_data" | sort -u)
     author=$(find_author "$user_addr" "$user_name" "$author_addr" "$author_name")
+    rm "$diff_data"
 
     # If we had to guess, and the user didn't want to guess, abort
     if [ "${author}" = "ABORT" ]; then
@@ -582,10 +582,11 @@ patch_commit()
     fi
 
     tmp=$(mktemp)
-    echo "$review_data" | jq -r '.response.data[].fields.title' > $tmp
+    jq -r '.response.data[].fields.title' "$review_data" > $tmp
     echo >> $tmp
-    echo "$review_data" | jq -r '.response.data[].fields.summary' >> $tmp
+    jq -r '.response.data[].fields.summary' "$review_data" >> $tmp
     echo >> $tmp
+    rm "$review_data"
     # XXX this leaves an extra newline in some cases.
     reviewers=$(diff2reviewers "$diff" | sed '/^$/d' | paste -sd ',' - | sed 's/,/, /g')
     if [ -n "$reviewers" ]; then