Skip to content

Commit 7a22e3c

Browse files
committed
feat: enhance validation and payload handling across multiple scripts
1 parent 761a84b commit 7a22e3c

8 files changed

Lines changed: 92 additions & 28 deletions

File tree

‎enterprise/github-dockerfile-discovery/github-dockerfile-discovery.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ validate_token() {
181181
print_error "GITHUB_TOKEN is invalid or lacks required scopes."
182182
exit 1
183183
fi
184-
print_success "Token valid — authenticated as: ${login}"
184+
print_success "Token validated."
185185
}
186186

187187
###

‎enterprise/github-get-public-repos/github-get-public-repos.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ validate_token() {
122122
print_error "GITHUB_TOKEN is invalid or lacks required scopes."
123123
exit 1
124124
fi
125-
print_success "Token valid — authenticated as: ${login}"
125+
print_success "Token validated."
126126
}
127127

128128
###

‎org-admin/github-add-repo-collaborators-by-pattern/github-add-repo-collaborators-by-pattern.sh‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ validate() {
6666
require_env_var ORG "GitHub organization"
6767
require_env_var COLLABORATORS "Collaborators list"
6868
require_env_var REPO_NAME_REGEX "Repo name regex"
69+
case "${PERMISSION}" in
70+
pull|triage|push|maintain|admin) ;;
71+
*)
72+
print_error "Invalid PERMISSION '${PERMISSION}'. Must be one of: pull, triage, push, maintain, admin"
73+
exit 1
74+
;;
75+
esac
6976
require_command jq
7077
validate_github_token
7178
}
@@ -95,8 +102,8 @@ add_collaborators_to_repos() {
95102
while IFS= read -r repo; do
96103
[ -z "${repo}" ] && continue
97104
for collaborator in ${collaborators_space}; do
98-
response=$(curl -s -o /dev/null -w "%{http_code}" -X PUT -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" "${API_URL_PREFIX}/repos/${ORG}/${repo}/collaborators/${collaborator}" -d "{\"permission\": \"${PERMISSION}\"}")
99-
105+
_payload=$(jq -n --arg perm "${PERMISSION}" '{"permission":$perm}')
106+
response=$(curl -s -o /dev/null -w "%{http_code}" -X PUT -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.v3+json" "${API_URL_PREFIX}/repos/${ORG}/${repo}/collaborators/${collaborator}" -d "${_payload}")
100107
if [[ "${response}" =~ ^2 ]]; then
101108
echo "Added '${collaborator}' to '${repo}' with '${PERMISSION}' permission"
102109
else

‎org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,23 @@ case "$ALERT_TYPE" in
8181
;;
8282
esac
8383

84+
# Validate dismiss/resolve reason values
85+
case "${DEPENDABOT_REASON}" in
86+
fix_started|inaccurate|no_bandwidth|not_used|tolerable_risk) ;;
87+
*)
88+
print_error "Invalid DEPENDABOT_REASON '${DEPENDABOT_REASON}'. Must be one of: fix_started, inaccurate, no_bandwidth, not_used, tolerable_risk"
89+
exit 1
90+
;;
91+
esac
92+
93+
case "${SECRET_SCANNING_RESOLUTION}" in
94+
false_positive|wont_fix|revoked|used_in_tests) ;;
95+
*)
96+
print_error "Invalid SECRET_SCANNING_RESOLUTION '${SECRET_SCANNING_RESOLUTION}'. Must be one of: false_positive, wont_fix, revoked, used_in_tests"
97+
exit 1
98+
;;
99+
esac
100+
84101
###
85102
## VALIDATION
86103
###
@@ -193,14 +210,17 @@ close_dependabot_alerts() {
193210
continue
194211
fi
195212

196-
local http_status
213+
local http_status _payload
214+
_payload=$(jq -n \
215+
--arg reason "${DEPENDABOT_REASON}" \
216+
'{"state":"dismissed","dismissed_reason":$reason,"dismissed_comment":"Bulk dismissed by repository automation"}')
197217
http_status=$(curl -s -o /dev/null -w "%{http_code}" \
198218
-X PATCH \
199219
-H "Authorization: token ${GITHUB_TOKEN}" \
200220
-H "Accept: application/vnd.github+json" \
201221
-H "X-GitHub-Api-Version: 2022-11-28" \
202222
-H "Content-Type: application/json" \
203-
-d "{\"state\":\"dismissed\",\"dismissed_reason\":\"${DEPENDABOT_REASON}\",\"dismissed_comment\":\"Bulk dismissed by repository automation\"}" \
223+
-d "${_payload}" \
204224
"${API_URL_PREFIX}/repos/${ORG}/${repo}/dependabot/alerts/${alert_number}")
205225

206226
if [ "${http_status}" -eq 200 ]; then
@@ -302,14 +322,17 @@ close_secret_scanning_alerts() {
302322
continue
303323
fi
304324

305-
local http_status
325+
local http_status _payload
326+
_payload=$(jq -n \
327+
--arg resolution "${SECRET_SCANNING_RESOLUTION}" \
328+
'{"state":"resolved","resolution":$resolution}')
306329
http_status=$(curl -s -o /dev/null -w "%{http_code}" \
307330
-X PATCH \
308331
-H "Authorization: token ${GITHUB_TOKEN}" \
309332
-H "Accept: application/vnd.github+json" \
310333
-H "X-GitHub-Api-Version: 2022-11-28" \
311334
-H "Content-Type: application/json" \
312-
-d "{\"state\":\"resolved\",\"resolution\":\"${SECRET_SCANNING_RESOLUTION}\"}" \
335+
-d "${_payload}" \
313336
"${API_URL_PREFIX}/repos/${ORG}/${repo}/secret-scanning/alerts/${alert_number}")
314337

315338
if [ "${http_status}" -eq 200 ]; then

‎org-admin/github-import-repo/github-import-repo.sh‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,15 @@ SRC_REPO=${1:-''}
4343
DEST_REPO=${2:-''}
4444
OWNER_USERNAME=${OWNER_USERNAME:-''}
4545
WORKDIR=''
46+
_cred_script=''
4647

4748
usage() {
4849
echo "Usage: $0 <source_repo_name> <destination_repo_name>"
4950
echo "Required env vars: GITHUB_TOKEN, ORG, OWNER_USERNAME"
5051
}
5152

5253
cleanup() {
54+
[ -n "${_cred_script}" ] && rm -f "${_cred_script}"
5355
if [ -n "${WORKDIR}" ] && [ -d "${WORKDIR}" ]; then
5456
rm -rf "${WORKDIR}"
5557
fi
@@ -74,10 +76,12 @@ fi
7476

7577
require_env_var OWNER_USERNAME "Owner username"
7678
require_command git
79+
require_command jq
7780
validate_github_token
7881

7982
# Create repo
80-
CREATE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.nebula-preview+json" "${API_URL_PREFIX}/orgs/${ORG}/repos" -d '{"name":"'"${DEST_REPO}"'", "visibility":"internal"}')
83+
_payload=$(jq -n --arg name "${DEST_REPO}" '{"name":$name,"visibility":"internal"}')
84+
CREATE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" "${API_URL_PREFIX}/orgs/${ORG}/repos" -d "${_payload}")
8185

8286
if [ "${CREATE_RESPONSE}" -ne 201 ] && [ "${CREATE_RESPONSE}" -ne 422 ]; then
8387
echo "Error: failed to create repository ${ORG}/${DEST_REPO} (HTTP ${CREATE_RESPONSE})"
@@ -95,11 +99,28 @@ fi
9599
WORKDIR=$(mktemp -d)
96100
cd "${WORKDIR}"
97101

102+
# Set up a GIT_ASKPASS script so the token is read from an env var at runtime
103+
# rather than embedded in the remote URL (which would expose it in ps output)
104+
_cred_script=$(mktemp)
105+
chmod 700 "${_cred_script}"
106+
printf '%s\n' \
107+
'#!/bin/bash' \
108+
'case "$1" in' \
109+
' Username*) echo x-access-token ;;' \
110+
' *) printf "%s" "${GIT_CRED_TOKEN}" ;;' \
111+
'esac' \
112+
> "${_cred_script}"
113+
export GIT_CRED_TOKEN="${GITHUB_TOKEN}"
114+
export GIT_ASKPASS="${_cred_script}"
115+
export GIT_TERMINAL_PROMPT=0
116+
98117
# Clone old repo locally
99118
git clone --bare "${GIT_URL_PREFIX}/${ORG}/${SRC_REPO}.git"
100119

101120
# Push to new repo
102121
cd "${SRC_REPO}.git"
103122
git push --mirror "${GIT_URL_PREFIX}/${ORG}/${DEST_REPO}.git"
104123

124+
unset GIT_ASKPASS GIT_CRED_TOKEN GIT_TERMINAL_PROMPT
125+
105126
echo "Repository import complete: ${SRC_REPO} -> ${DEST_REPO}"

‎org-admin/github-repo-from-template/github-repo-from-template.sh‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ require_env_var CD_GITHUB_TOKEN "CD GitHub token"
7272
validate_token CD_GITHUB_TOKEN
7373

7474
# Create repo from template
75-
CREATE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github.baptiste-preview+json" "${API_URL_PREFIX}/repos/${ORG}/${TEMPLATE_REPO}/generate" -d '{"name":"'"${REPO_NAME}"'", "owner":"'"${ORG}"'", "private":true, "include_all_branches":true}')
75+
_payload=$(jq -n --arg name "${REPO_NAME}" --arg owner "${ORG}" \
76+
'{"name":$name,"owner":$owner,"private":true,"include_all_branches":true}')
77+
CREATE_RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" "${API_URL_PREFIX}/repos/${ORG}/${TEMPLATE_REPO}/generate" -d "${_payload}")
7678

7779
if [ "${CREATE_RESPONSE}" -ne 201 ]; then
7880
echo "Error: failed to create ${ORG}/${REPO_NAME} from template ${TEMPLATE_REPO} (HTTP ${CREATE_RESPONSE})"

‎personal/github-organize-stars/github-organize-stars.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ fetch_stars() {
159159
local cursor="" has_next="true" page=1
160160
local tmp_dir
161161
tmp_dir=$(mktemp -d)
162+
trap 'rm -rf "$tmp_dir"' RETURN
162163

163164
while [[ "$has_next" == "true" ]]; do
164165
printf " Fetching page %d...\r" "$page" >&2
@@ -195,7 +196,6 @@ fetch_stars() {
195196
local total
196197
total=$(jq -s '[.[].data.viewer.starredRepositories.nodes[]] | length' "$tmp_dir"/page*.json)
197198
printf " Fetched %d starred repos. \n" "$total" >&2
198-
rm -rf "$tmp_dir"
199199
}
200200

201201
get_existing_lists() {

‎reporting/github-monthly-issues-report/github-monthly-issues-report.sh‎

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ require_env_var MONTH_END "Month end date (YYYY-MM-DD)"
5050
require_command jq
5151
validate_github_token
5252

53+
# Validate date format to prevent jq filter injection
54+
if ! [[ "${MONTH_START}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
55+
print_error "MONTH_START must be YYYY-MM-DD, got: ${MONTH_START}"
56+
exit 1
57+
fi
58+
if ! [[ "${MONTH_END}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
59+
print_error "MONTH_END must be YYYY-MM-DD, got: ${MONTH_END}"
60+
exit 1
61+
fi
62+
63+
ISSUES_TEMP=$(mktemp)
64+
trap 'rm -f "${ISSUES_TEMP}"' EXIT
65+
5366
get_issue_pagination () {
5467
issue_pages=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" -I "${API_URL_PREFIX}/repos/${ORG}/${REPO}/issues?state=all&labels=Linked%20[AC]&per_page=100" | grep -Eo '&page=[0-9]+' | grep -Eo '[0-9]+' | tail -1;)
5568
echo "${issue_pages:-1}"
@@ -61,49 +74,47 @@ limit_issue_pagination () {
6174

6275
repo_issues () {
6376
for PAGE in $(limit_issue_pagination); do
64-
for i in $(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "${API_URL_PREFIX}/repos/${ORG}/${REPO}/issues?state=all&labels=Linked%20[AC]&page=${PAGE}&per_page=100" | jq -r 'map(select(.created_at | . >= "'"${MONTH_START}"'T00:00" and . <= "'"${MONTH_END}"'T23:59")) | sort_by(.number) | .[] | .number'); do
77+
for i in $(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "${API_URL_PREFIX}/repos/${ORG}/${REPO}/issues?state=all&labels=Linked%20[AC]&page=${PAGE}&per_page=100" | jq -r --arg s "${MONTH_START}" --arg e "${MONTH_END}" 'map(select(.created_at | . >= ($s+"T00:00") and . <= ($e+"T23:59"))) | sort_by(.number) | .[].number'); do
6578
ISSUE_PAYLOAD=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "${API_URL_PREFIX}/repos/${ORG}/${REPO}/issues/${i}" -H "Accept: application/vnd.github.mercy-preview+json")
6679
ISSUE_TIMELINE_PAYLOAD=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" "${API_URL_PREFIX}/repos/${ORG}/${REPO}/issues/${i}/timeline" -H "Accept: application/vnd.github.mockingbird-preview+json" | jq -r '.[] | select(.label.name=="Linked [AC]" or .label.name=="linked")')
6780

6881
ISSUE_AUTHOR=$(echo "${ISSUE_PAYLOAD}" | jq -r .user.login)
69-
ISSUE_TITLE=$(echo "${ISSUE_PAYLOAD}" | jq -r .title | tr '"' "'")
82+
ISSUE_TITLE=$(echo "${ISSUE_PAYLOAD}" | jq -r .title)
7083
ISSUE_HTML_URL=$(echo "${ISSUE_PAYLOAD}" | jq -r .html_url)
7184

7285
ISSUE_TIMELINE_LABELED_BY=$(echo "${ISSUE_TIMELINE_PAYLOAD}" | jq -s 'first(.[]| .actor.login)' | jq -r)
7386

74-
cat >> test.json << EOF
75-
{
76-
"author": "${ISSUE_AUTHOR}",
77-
"title": "${ISSUE_TITLE}",
78-
"issue_url": "${ISSUE_HTML_URL}",
79-
"contributor": "${ISSUE_TIMELINE_LABELED_BY}"
80-
}
81-
EOF
87+
jq -n \
88+
--arg author "${ISSUE_AUTHOR}" \
89+
--arg title "${ISSUE_TITLE}" \
90+
--arg url "${ISSUE_HTML_URL}" \
91+
--arg contrib "${ISSUE_TIMELINE_LABELED_BY}" \
92+
'{"author":$author,"title":$title,"issue_url":$url,"contributor":$contrib}' \
93+
>> "${ISSUES_TEMP}"
8294
done
8395
done
8496
}
8597

8698
author_json () {
87-
AUTHORS=$(cat test.json | jq -r '.author' | sort | uniq -c | awk -F " " '{print "{\"author\":""\""$2"\""",\"count\":" $1"}"}' | jq -r .author)
99+
AUTHORS=$(cat "${ISSUES_TEMP}" | jq -r '.author' | sort | uniq -c | awk -F " " '{print "{\"author\":""\""\ $2"\""",\"count\":" $1"}"}' | jq -r .author)
88100
for AUTHOR in ${AUTHORS}; do
89-
TEST_PAYLOAD=$(cat test.json | jq -r '.author' | sort | uniq -c | awk -F " " '{print "{\"author\":""\""$2"\""",\"count\":" $1"}"}' | jq -r .)
101+
TEST_PAYLOAD=$(cat "${ISSUES_TEMP}" | jq -r '.author' | sort | uniq -c | awk -F " " '{print "{\"author\":""\""\ $2"\""",\"count\":" $1"}"}' | jq -r .)
90102
TEST_PAYLOAD_AUTHOR=$(echo "${TEST_PAYLOAD}" | jq -r --arg AUTHOR "${AUTHOR}" 'select(.author==$AUTHOR) | .author')
91103
TEST_PAYLOAD_AUTHOR_COUNT=$(echo "${TEST_PAYLOAD}" | jq -r --arg AUTHOR "${AUTHOR}" 'select(.author==$AUTHOR) | .count')
92-
TEST_PAYLOAD_AUTHOR_ISSUE_URL=$(cat test.json | jq -r --arg AUTHOR "${AUTHOR}" 'select(.author==$AUTHOR) | .title, .issue_url')
104+
TEST_PAYLOAD_AUTHOR_ISSUE_URL=$(cat "${ISSUES_TEMP}" | jq -r --arg AUTHOR "${AUTHOR}" 'select(.author==$AUTHOR) | .title, .issue_url')
93105
echo -e "<a href=\"https://github.com/${TEST_PAYLOAD_AUTHOR}\">${TEST_PAYLOAD_AUTHOR}</a> - ${TEST_PAYLOAD_AUTHOR_COUNT}"
94106
done | sort -n -k 4,4 -r >> output.txt
95107
}
96108

97109
contributor_json () {
98-
CONTRIBUTORS=$(cat test.json | jq -r '.contributor' | sort | uniq -c | awk -F " " '{print "{\"contributor\":""\""$2"\""",\"count\":" $1"}"}' | jq -r .contributor)
110+
CONTRIBUTORS=$(cat "${ISSUES_TEMP}" | jq -r '.contributor' | sort | uniq -c | awk -F " " '{print "{\"contributor\":""\""\ $2"\""",\"count\":" $1"}"}' | jq -r .contributor)
99111
for CONTRIBUTOR in ${CONTRIBUTORS}; do
100-
TEST_PAYLOAD=$(cat test.json | jq -r '.contributor' | sort | uniq -c | awk -F " " '{print "{\"contributor\":""\""$2"\""",\"count\":" $1"}"}' | jq -r .)
112+
TEST_PAYLOAD=$(cat "${ISSUES_TEMP}" | jq -r '.contributor' | sort | uniq -c | awk -F " " '{print "{\"contributor\":""\""\ $2"\""",\"count\":" $1"}"}' | jq -r .)
101113
TEST_PAYLOAD_CONTRIBUTOR=$(echo "${TEST_PAYLOAD}" | jq -r --arg CONTRIBUTOR "${CONTRIBUTOR}" 'select(.contributor==$CONTRIBUTOR) | .contributor')
102114
TEST_PAYLOAD_CONTRIBUTOR_COUNT=$(echo "${TEST_PAYLOAD}" | jq -r --arg CONTRIBUTOR "${CONTRIBUTOR}" 'select(.contributor==$CONTRIBUTOR) | .count')
103-
TEST_PAYLOAD_CONTRIBUTOR_ISSUE_URL=$(cat test.json | jq -r --arg CONTRIBUTOR "${CONTRIBUTOR}" 'select(.contributor==$CONTRIBUTOR) | .issue_url')
115+
TEST_PAYLOAD_CONTRIBUTOR_ISSUE_URL=$(cat "${ISSUES_TEMP}" | jq -r --arg CONTRIBUTOR "${CONTRIBUTOR}" 'select(.contributor==$CONTRIBUTOR) | .issue_url')
104116
echo -e "<a href=\"https://github.com/${TEST_PAYLOAD_CONTRIBUTOR}\">${TEST_PAYLOAD_CONTRIBUTOR}</a> - ${TEST_PAYLOAD_CONTRIBUTOR_COUNT}"
105117
done | sort -n -k 4,4 -r >> output.txt
106-
rm -Rf test.json
107118
}
108119

109120
repo_issues

0 commit comments

Comments
 (0)