Skip to content

Commit 67289c6

Browse files
Sanitize branch names before checkout (#5970)
1 parent 55cb839 commit 67289c6

File tree

2 files changed

+103
-24
lines changed

2 files changed

+103
-24
lines changed

.github/workflows/update-chat-snapshots.yml

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jobs:
1717
pull-requests: write
1818
outputs:
1919
met: ${{ steps.label.outputs.found || steps.workflow_dispatch.outputs.found }}
20+
active_branch_name_sanitized: ${{ steps.sanitize.outputs.branch }}
2021
steps:
2122
- uses: actions/checkout@v4
2223
with:
@@ -26,15 +27,40 @@ jobs:
2627
# This machine account is only for this PAT, pwd was created and thrown away
2728
# If an update is needed, create a new account, add access to the repo and generate a new PAT
2829
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
30+
# Sanitize branch name for any subsequent git checkout to prevent branch name exploits
31+
- name: Sanitize branch name
32+
id: sanitize
33+
if: ${{ github.event_name == 'pull_request' }}
34+
env:
35+
BRANCH_REF: ${{ github.event.pull_request.head.ref }}
36+
run: |
37+
# Sanitize branch name to prevent command injection
38+
SAFE_BRANCH=$(echo "$BRANCH_REF" | sed 's/[^a-zA-Z0-9._\/-]//g')
39+
echo "branch=$SAFE_BRANCH" >> $GITHUB_OUTPUT
40+
# After sanitizing the branchname, confirm it exists (it won't if exploit code was stripped)
41+
- name: Check sanitized branchname exists
42+
if: ${{ github.event_name == 'pull_request' }}
43+
env:
44+
SAFE_BRANCH: ${{ steps.sanitize.outputs.branch }}
45+
run: |
46+
if [ -z "$SAFE_BRANCH" ]; then
47+
echo "No branch specified; skipping existence check"
48+
elif git ls-remote --heads origin "$SAFE_BRANCH" | grep -q "$SAFE_BRANCH"; then
49+
echo "Branch '$SAFE_BRANCH' found."
50+
else
51+
echo "Error: Branch '$SAFE_BRANCH' not found on origin" >&2
52+
exit 1
53+
fi
2954
- name: Found required label
3055
id: label
3156
if: ${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'update_chat_snapshots') }}
3257
env:
3358
# Required for running `gh`.
3459
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60+
PR_NUMBER: ${{ github.event.number }}
3561
run: |
3662
echo "found=true" >> $GITHUB_OUTPUT
37-
gh pr edit ${{ github.event.number }} --remove-label update_chat_snapshots
63+
gh pr edit "$PR_NUMBER" --remove-label update_chat_snapshots
3864
3965
get_matrix:
4066
name: Set CI flavors
@@ -74,9 +100,12 @@ jobs:
74100
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
75101
- name: Checkout branch if on a PR
76102
if: ${{ github.event_name != 'workflow_dispatch' }}
103+
# Use sanitized branch name from precondition job
104+
env:
105+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
77106
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
78107
# Explicitly checkout the target branch so we can push later.
79-
run: git checkout ${{ github.event.pull_request.head.ref }}
108+
run: git checkout "$SAFE_BRANCH"
80109
- name: Setup bot git information
81110
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
82111
run: |
@@ -130,6 +159,8 @@ jobs:
130159
fi
131160
- name: Push new snapshots, if any
132161
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
162+
env:
163+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
133164
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
134165
# This allows multiple snapshot update jobs in this action to run concurrently.
135166
# - The only files updated locally are UI snapshots
@@ -143,7 +174,7 @@ jobs:
143174
run: |
144175
git add packages/react-composites/*.png
145176
git commit -m 'Update packages/react-composites ChatComposite browser test snapshots'
146-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
177+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
147178
git push
148179
149180
push_updated_snapshots:

.github/workflows/update-snapshots.yml

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
pull-requests: write
1919
outputs:
2020
met: ${{ steps.label.outputs.found || steps.workflow_dispatch.outputs.found }}
21+
active_branch_name_sanitized: ${{ steps.sanitize.outputs.branch }}
2122
steps:
2223
- uses: actions/checkout@v4
2324
with:
@@ -27,6 +28,29 @@ jobs:
2728
# This machine account is only for this PAT, pwd was created and thrown away
2829
# If an update is needed, create a new account, add access to the repo and generate a new PAT
2930
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
31+
# Sanitize branch name for any subsequent git checkout to prevent branch name exploits
32+
- name: Sanitize branch name
33+
id: sanitize
34+
if: ${{ github.event_name == 'pull_request' }}
35+
env:
36+
BRANCH_REF: ${{ github.event.pull_request.head.ref }}
37+
run: |
38+
# Sanitize branch name to prevent command injection
39+
SAFE_BRANCH=$(echo "$BRANCH_REF" | sed 's/[^a-zA-Z0-9._\/-]//g')
40+
echo "branch=$SAFE_BRANCH" >> $GITHUB_OUTPUT
41+
# After sanitizing the branchname, confirm it exists (it won't if exploit code was stripped)
42+
# After sanitizing the branchname, confirm it exists (it won't if exploit code was stripped)
43+
- name: Check sanitized branchname exists
44+
if: ${{ github.event_name == 'pull_request' }}
45+
env:
46+
SAFE_BRANCH: ${{ steps.sanitize.outputs.branch }}
47+
run: |
48+
if git ls-remote --heads origin "$SAFE_BRANCH" | grep -q "$SAFE_BRANCH"; then
49+
echo "Branch '$SAFE_BRANCH' found."
50+
else
51+
echo "Error: Branch '$SAFE_BRANCH' not found on origin" >&2
52+
exit 1
53+
fi
3054
- name: Found workflow disptach
3155
id: workflow_dispatch
3256
if: ${{ github.event_name == 'workflow_dispatch' }}
@@ -37,9 +61,10 @@ jobs:
3761
env:
3862
# Required for running `gh`.
3963
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64+
PR_NUMBER: ${{ github.event.number }}
4065
run: |
4166
echo "found=true" >> $GITHUB_OUTPUT
42-
gh pr edit ${{ github.event.number }} --remove-label update_snapshots
67+
gh pr edit "$PR_NUMBER" --remove-label update_snapshots
4368
4469
get_matrix:
4570
name: Set CI flavors
@@ -79,9 +104,12 @@ jobs:
79104
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
80105
- name: Checkout branch if on a PR
81106
if: ${{ github.event_name != 'workflow_dispatch' }}
107+
# Use sanitized branch name from precondition job
108+
env:
109+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
82110
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
83111
# Explicitly checkout the target branch so we can push later.
84-
run: git checkout ${{ github.event.pull_request.head.ref }}
112+
run: git checkout "$SAFE_BRANCH"
85113
- name: Setup bot git information
86114
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
87115
run: |
@@ -136,11 +164,12 @@ jobs:
136164
echo "hasChanged=false" >> $GITHUB_OUTPUT
137165
else
138166
echo "hasChanged=true" >> $GITHUB_OUTPUT
139-
exit
140167
fi
141168
- name: Push new snapshots, if any
142169
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
143-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
170+
env:
171+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
172+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
144173
# This allows multiple snapshot update jobs in this action to run concurrently.
145174
# - The only files updated locally are UI snapshots
146175
# - Each job is responsible for a unique set of UI snapshots
@@ -153,7 +182,7 @@ jobs:
153182
run: |
154183
git add samples/tests/*.png
155184
git commit -m 'Update component examples snapshots'
156-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
185+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
157186
git push
158187
159188
html_bundle:
@@ -175,9 +204,11 @@ jobs:
175204
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
176205
- name: Checkout branch if on a PR
177206
if: ${{ github.event_name != 'workflow_dispatch' }}
207+
env:
208+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
178209
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
179210
# Explicitly checkout the target branch so we can push later.
180-
run: git checkout ${{ github.event.pull_request.head.ref }}
211+
run: git checkout "$SAFE_BRANCH"
181212
- name: Setup bot git information
182213
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
183214
run: |
@@ -232,11 +263,12 @@ jobs:
232263
echo "hasChanged=false" >> $GITHUB_OUTPUT
233264
else
234265
echo "hasChanged=true" >> $GITHUB_OUTPUT
235-
exit
236266
fi
237267
- name: Push new snapshots, if any
238268
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
239-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
269+
env:
270+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
271+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
240272
# This allows multiple snapshot update jobs in this action to run concurrently.
241273
# - The only files updated locally are UI snapshots
242274
# - Each job is responsible for a unique set of UI snapshots
@@ -249,7 +281,7 @@ jobs:
249281
run: |
250282
git add samples/tests/*.png
251283
git commit -m 'Update embed html bundle snapshots'
252-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
284+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
253285
git push
254286
255287
call_composite:
@@ -271,9 +303,11 @@ jobs:
271303
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
272304
- name: Checkout branch if on a PR
273305
if: ${{ github.event_name != 'workflow_dispatch' }}
306+
env:
307+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
274308
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
275309
# Explicitly checkout the target branch so we can push later.
276-
run: git checkout ${{ github.event.pull_request.head.ref }}
310+
run: git checkout "$SAFE_BRANCH"
277311
- name: Setup bot git information
278312
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
279313
run: |
@@ -332,7 +366,9 @@ jobs:
332366
fi
333367
- name: Push new snapshots, if any
334368
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
335-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
369+
env:
370+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
371+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
336372
# This allows multiple snapshot update jobs in this action to run concurrently.
337373
# - The only files updated locally are UI snapshots
338374
# - Each job is responsible for a unique set of UI snapshots
@@ -345,7 +381,7 @@ jobs:
345381
run: |
346382
git add packages/react-composites/*.png
347383
git commit -m 'Update packages/react-composites CallComposite browser test snapshots'
348-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
384+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
349385
git push
350386
351387
chat_composite:
@@ -367,9 +403,11 @@ jobs:
367403
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
368404
- name: Checkout branch if on a PR
369405
if: ${{ github.event_name != 'workflow_dispatch' }}
406+
env:
407+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
370408
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
371409
# Explicitly checkout the target branch so we can push later.
372-
run: git checkout ${{ github.event.pull_request.head.ref }}
410+
run: git checkout "$SAFE_BRANCH"
373411
- name: Setup bot git information
374412
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
375413
run: |
@@ -428,7 +466,9 @@ jobs:
428466
fi
429467
- name: Push new snapshots, if any
430468
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
431-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
469+
env:
470+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
471+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
432472
# This allows multiple snapshot update jobs in this action to run concurrently.
433473
# - The only files updated locally are UI snapshots
434474
# - Each job is responsible for a unique set of UI snapshots
@@ -441,7 +481,7 @@ jobs:
441481
run: |
442482
git add packages/react-composites/*.png
443483
git commit -m 'Update packages/react-composites ChatComposite browser test snapshots'
444-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
484+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
445485
git push
446486
447487
callwithchat_composite:
@@ -463,9 +503,11 @@ jobs:
463503
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
464504
- name: Checkout branch if on a PR
465505
if: ${{ github.event_name != 'workflow_dispatch' }}
506+
env:
507+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
466508
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
467509
# Explicitly checkout the target branch so we can push later.
468-
run: git checkout ${{ github.event.pull_request.head.ref }}
510+
run: git checkout "$SAFE_BRANCH"
469511
- name: Setup bot git information
470512
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
471513
run: |
@@ -524,7 +566,9 @@ jobs:
524566
fi
525567
- name: Push new snapshots, if any
526568
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
527-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
569+
env:
570+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
571+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
528572
# This allows multiple snapshot update jobs in this action to run concurrently.
529573
# - The only files updated locally are UI snapshots
530574
# - Each job is responsible for a unique set of UI snapshots
@@ -537,7 +581,7 @@ jobs:
537581
run: |
538582
git add packages/react-composites/*.png
539583
git commit -m 'Update packages/react-composites CallWithChatComposite browser test snapshots'
540-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
584+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
541585
git push
542586
543587
components:
@@ -559,9 +603,11 @@ jobs:
559603
token: ${{ secrets.MACHINE_ACCOUNT_PAT }}
560604
- name: Checkout branch if on a PR
561605
if: ${{ github.event_name != 'workflow_dispatch' }}
606+
env:
607+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
562608
# On the `pull_request` event, actions/checkout@v4 leaves the local checkout in a detached head state.
563609
# Explicitly checkout the target branch so we can push later.
564-
run: git checkout ${{ github.event.pull_request.head.ref }}
610+
run: git checkout "$SAFE_BRANCH"
565611
- name: Setup bot git information
566612
# User id of github actions bot. See https://api.github.com/users/better-informatics%5Bbot%5D
567613
run: |
@@ -617,7 +663,9 @@ jobs:
617663
fi
618664
- name: Push new snapshots, if any
619665
if: ${{ steps.changescheck.outputs.hasChanged == 'true' }}
620-
# Before pushing changes to origin, merge any intervening changes on the upstream branch.
666+
env:
667+
SAFE_BRANCH: ${{ needs.precondition.outputs.active_branch_name_sanitized }}
668+
# Before pushing changes to origin, merge any intervening changes on the upstream branch
621669
# This allows multiple snapshot update jobs in this action to run concurrently.
622670
# - The only files updated locally are UI snapshots
623671
# - Each job is responsible for a unique set of UI snapshots
@@ -630,7 +678,7 @@ jobs:
630678
run: |
631679
git add packages/react-components/*.png
632680
git commit -m 'Update packages/react-components browser test snapshots'
633-
git pull origin ${{ needs.get_target_branch.outputs.target }} --no-rebase --no-edit
681+
git pull origin "$SAFE_BRANCH" --no-rebase --no-edit
634682
git push
635683
636684
push_updated_snapshots:

0 commit comments

Comments
 (0)