Skip to content
This repository was archived by the owner on Feb 21, 2025. It is now read-only.

Commit 374220a

Browse files
authored
Protect against script injection attacks (#8)
1 parent af79cb9 commit 374220a

File tree

3 files changed

+141
-38
lines changed

3 files changed

+141
-38
lines changed

.github/workflows/backport-action.yml

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
name: Launch Backport Job
2-
32
on:
43
workflow_call:
54
inputs:
@@ -40,40 +39,65 @@ on:
4039
github_account_pat:
4140
description: PAT for a github account that has write access to source repository
4241
required: true
43-
4442
jobs:
4543
launch_ado_build:
4644
runs-on: ubuntu-latest
45+
env:
46+
# Protect against script injection attacks via input variables (i.e., the content of the variables could be executed at the time of evaluation/expansion within a script)
47+
# Scripts must consume the environment variable settings instead
48+
GITHUB_REPOSITORY: "${{ inputs.github_repository }}"
49+
GITHUB_ACCOUNT_PAT: "${{ secrets.github_account_pat }}"
50+
COMMENT_AUTHOR: "${{ inputs.comment_author }}"
51+
PULL_REQUEST_URL: "${{ inputs.pull_request_url }}"
52+
TARGET_BRANCH: "${{ inputs.target_branch }}"
53+
USE_FORK: "${{ inputs.use_fork }}"
54+
ADO_ORGANIZATION: "${{ secrets.ado_organization }}"
55+
ADO_PROJECT: "${{ secrets.ado_project }}"
56+
ADO_PIPELINE_ID: "${{ secrets.backport_pipeline_id }}"
57+
ADO_BUILD_PAT: "${{ secrets.ado_build_pat }}"
4758
steps:
4859
- name: Gather Parameters
4960
id: get_parameters
5061
run: |
5162
$statusCode = 0
5263
$message = ""
5364
try {
54-
($repoOwner, $repoName) = "${{ inputs.github_repository }}".Split("/")
55-
$headers = $headers = @{ Authorization = "token ${{ secrets.github_account_pat }}"}
56-
$uri = "https://api.github.com/repos/$repoOwner/$repoName/collaborators/${{ inputs.comment_author }}/permission"
57-
Write-Host "Checking $repoOwner membership for ${{ inputs.comment_author }} via $uri"
65+
$gitHubRepository = $env:GITHUB_REPOSITORY
66+
$gitHubAccountPAT = $env:GITHUB_ACCOUNT_PAT
67+
$commentAuthor = $env:COMMENT_AUTHOR
68+
$pullRequestUrl = $env:PULL_REQUEST_URL
69+
$backportTargetBranch = $env:TARGET_BRANCH
70+
$useFork = $env:USE_FORK
71+
72+
Write-Host "GITHUB_REPOSITORY: ${gitHubRepository}"
73+
Write-Host "COMMENT_AUTHOR: ${commentAuthor}"
74+
Write-Host "PULL_REQUEST_URL: ${pullRequestUrl}"
75+
Write-Host "TARGET_BRANCH: ${backportTargetBranch}"
76+
Write-Host "USE_FORK: ${useFork}"
77+
78+
($repoOwner, $repoName) = $gitHubRepository.Split("/")
79+
$headers = $headers = @{ Authorization = "token ${gitHubAccountPAT}"}
80+
$uri = "https://api.github.com/repos/${repoOwner}/${repoName}/collaborators/${commentAuthor}/permission"
81+
Write-Host "Checking ${repoOwner} membership for ${commentAuthor} via $uri"
5882
$response = Invoke-WebRequest -Headers $headers -Uri $uri
5983
$content = $response.Content | ConvertFrom-Json
6084
$accessType = $content.permission
6185
Write-Host "Found membership: $accessType"
6286
if (-not ($accessType.Equals("admin") -or $accessType.Equals("write"))) {
63-
throw "${{ inputs.comment_author }}/permission does not have sufficient permissions for ${{ inputs.github_repository }}"
87+
throw "${commentAuthor}/permission does not have sufficient permissions for ${gitHubRepository}"
6488
}
6589
66-
Write-Host "Grabbing PR details from ${{ inputs.pull_request_url }}"
67-
$response = Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "${{ inputs.pull_request_url }}" | ConvertFrom-Json
90+
Write-Host "Grabbing PR details from ${pullRequestUrl}"
91+
$response = Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "${pullRequestUrl}" | ConvertFrom-Json
6892
$backportPRNumber = $response.number
6993
7094
$parameters = @{
7195
BackportRepoName = "$repoName";
7296
BackportRepoOrg = "$repoOwner";
73-
BackportTargetBranch = "${{ inputs.target_branch }}";
97+
BackportTargetBranch = "$backportTargetBranch";
7498
BackportPRNumber = "$backportPRNumber";
7599
BackportHeadSHA = "$($response.head.sha)";
76-
UseFork = "${{ inputs.use_fork }}" -eq "true";
100+
UseFork = $useFork -eq "true";
77101
} | ConvertTo-Json -Compress
78102
79103
$json = $parameters.Replace("`"","'")
@@ -88,10 +112,22 @@ jobs:
88112
shell: pwsh
89113

90114
- run: |
115+
$adoOrganization = $env:ADO_ORGANIZATION
116+
$adoProject = $env:ADO_PROJECT
117+
$adoPipelineId = $env:ADO_PIPELINE_ID
118+
$adoBuildPAT = $env:ADO_BUILD_PAT
119+
$gitHubRepository = $env:GITHUB_REPOSITORY
120+
$gitHubAccountPAT = $env:GITHUB_ACCOUNT_PAT
121+
122+
Write-Host "ADO_ORGANIZATION: ${adoOrganization}"
123+
Write-Host "ADO_PROJECT: ${adoProject}"
124+
Write-Host "ADO_PIPELINE_ID: ${adoPipelineId}"
125+
Write-Host "GITHUB_REPOSITORY: ${gitHubRepository}"
126+
91127
$message = ""
92128
$statusCode = 0
93129
try {
94-
$launchURI = "https://dev.azure.com/${{ secrets.ado_organization }}/${{ secrets.ado_project }}/_apis/pipelines/${{ secrets.backport_pipeline_id }}/runs?api-version=6.0-preview.1"
130+
$launchURI = "https://dev.azure.com/${adoOrganization}/${adoProject}/_apis/pipelines/${adoPipelineId}/runs?api-version=6.0-preview.1"
95131
Write-Host "Grabbing parameters from prior step"
96132
$parameters = ConvertFrom-Json "${{ steps.get_parameters.outputs.parameters }}"
97133
Write-Host "$parameters"
@@ -109,13 +145,13 @@ jobs:
109145
110146
Write-Host "Posting to $launchURI"
111147
Write-Host $jsonBody
112-
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":${{ secrets.ado_build_pat }}"))
148+
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":${adoBuildPAT}"))
113149
$headers = @{ Authorization = "Basic $encoded"}
114150
115151
$response = Invoke-WebRequest -UseBasicParsing -Method POST -Headers $headers -ContentType "application/json" -Uri $launchURI -Body $jsonBody
116152
$responseJson = ConvertFrom-Json $response.Content
117153
echo "Job successfully launched"
118-
$message = "Backport Job to branch **$($parameters.BackportTargetBranch)** Created! The magic is happening [here](https://dev.azure.com/${{ secrets.ado_organization }}/${{ secrets.ado_project }}/_build/results?buildId=$($responseJson.id))"
154+
$message = "Backport Job to branch **$($parameters.BackportTargetBranch)** Created! The magic is happening [here](https://dev.azure.com/${adoOrganization}/${adoProject}/_build/results?buildId=$($responseJson.id))"
119155
} catch {
120156
Write-Host $_.Exception.Message
121157
$message = "I couldn't create a backport to **$($parameters.BackportTargetBranch)** for you. :( Please check the Action logs for more details."
@@ -125,8 +161,8 @@ jobs:
125161
body = $message
126162
} | ConvertTo-Json
127163
128-
$headers = @{ Authorization = "token ${{ secrets.github_account_pat }}"}
129-
$uri = "https://api.github.com/repos/${{ inputs.github_repository }}/issues/${{ steps.get_parameters.outputs.pr_number }}/comments"
164+
$headers = @{ Authorization = "token ${gitHubAccountPAT}"}
165+
$uri = "https://api.github.com/repos/${gitHubRepository}/issues/${{ steps.get_parameters.outputs.pr_number }}/comments"
130166
131167
132168
Write-Host "Posting to $uri"

README.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,37 @@ Contains an action that's responsible for running an Azure DevOps build which ba
66

77
## Trademarks
88

9-
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
10-
trademarks or logos is subject to and must follow
9+
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
10+
trademarks or logos is subject to and must follow
1111
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
1212
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
1313
Any use of third-party trademarks or logos are subject to those third-party's policies.
1414

1515

16-
## Deploying
16+
## Testing
17+
18+
You can test changes from your topic branch (PR branch) by using the `v1.0-test` tag. Associate the tag with your latest changes by performing the following steps
19+
20+
```
21+
git checkout [TOPIC_BRANCH_NAME]
22+
git tag -f v1.0-test
23+
git push --tags --force
24+
```
25+
26+
To excercise your changes associated with the `v1.0-test` tag, use the following test PR
27+
https://github.com/xamarin/backport-bot-action/pull/11
28+
29+
Apply the following comment to the PR
30+
31+
```
32+
@gitbot backport backport-target
33+
```
1734

18-
Release management of the backport bot action is done though git tags. At present, the current release can be found at `v1.0`.
35+
See the [test PR](https://github.com/xamarin/backport-bot-action/pull/11) for additional guidance & details
36+
37+
## Deploying
1938

20-
For Staging, please use the `v1.0-alpha` tag or create a new tag specific to your PR, especially if there are multiple changes in flight.
39+
Release management of the backport bot action is done though git tags. At present, the current release can be found at `v1.1`.
2140

2241
To deploy your changes, please:
2342

@@ -30,7 +49,7 @@ git tag -f $TAG_NAME
3049
```bash
3150
git push --tags
3251
```
33-
Please note that for updating the `v1.0` tag (or any other tag you want to push if it already exists), you will need to `push --force` to overwrite the existing tag.
52+
Please note that for updating the `v1.1` tag (or any other tag you want to push if it already exists), you will need to `push --force` to overwrite the existing tag.
3453

3554
In order to pick up the changes for Staging, make sure that the backport trigger YAML in your target repo (usually found at https://github.com/xamarin/$REPO_NAME/blob/main/.github/workflows/backport-trigger.yml) points to your desired tag.
3655

@@ -39,3 +58,9 @@ For example, https://github.com/xamarin/.github/blob/main/.github/workflows/back
3958
- uses: xamarin/backport-bot-action@$TAG_NAME
4059
```
4160
where `$TAG_NAME` is filled in with the actual name of the tag.
61+
62+
You can list tags by executing the following command
63+
64+
```
65+
git tag
66+
```

action.yml

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
name: Backport Pull Request from Comment
22
description: Launches a Backport Job from a GitHub Comment on an Issue
3-
author: Connor Adsit <cadsit@microsoft.com>
43
inputs:
54
pull_request_url:
65
description: URL of the pull request from the issue comment event
@@ -34,32 +33,63 @@ inputs:
3433
required: false
3534
default: 'false'
3635

36+
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs
3737
runs:
3838
using: "composite"
39+
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runsenv
40+
env:
41+
# Protect against script injection attacks via input variables (i.e., the content of the variables could be executed at the time of evaluation/expansion within a script)
42+
# Scripts must consume the environment variable settings instead
43+
GITHUB_REPOSITORY: "${{ inputs.github_repository }}"
44+
GITHUB_ACCOUNT_PAT: "${{ inputs.github_account_pat }}"
45+
COMMENT_AUTHOR: "${{ inputs.comment_author }}"
46+
COMMENT_BODY: "${{ inputs.comment_body }}"
47+
PULL_REQUEST_URL: "${{ inputs.pull_request_url }}"
48+
USE_FORK: "${{ inputs.use_fork }}"
49+
ADO_ORGANIZATION: "${{ inputs.ado_organization }}"
50+
ADO_PROJECT: "${{ inputs.ado_project }}"
51+
ADO_PIPELINE_ID: "${{ inputs.backport_pipeline_id }}"
52+
ADO_BUILD_PAT: "${{ inputs.ado_build_pat }}"
3953
steps:
4054
- name: Gather Parameters
4155
id: get_parameters
4256
run: |
4357
$statusCode = 0
4458
$message = ""
4559
try {
46-
($repoOwner, $repoName) = "${{ inputs.github_repository }}".Split("/")
47-
$headers = $headers = @{ Authorization = "token ${{ inputs.github_account_pat }}"}
48-
$uri = "https://api.github.com/repos/$repoOwner/$repoName/collaborators/${{ inputs.comment_author }}/permission"
49-
Write-Host "Checking $repoOwner membership for ${{ inputs.comment_author }} via $uri"
60+
$gitHubRepository = $env:GITHUB_REPOSITORY
61+
$gitHubAccountPAT = $env:GITHUB_ACCOUNT_PAT
62+
$commentAuthor = $env:COMMENT_AUTHOR
63+
$pullRequestUrl = $env:PULL_REQUEST_URL
64+
$useFork = $env:USE_FORK
65+
66+
Write-Host "GITHUB_REPOSITORY: ${gitHubRepository}"
67+
Write-Host "COMMENT_AUTHOR: ${commentAuthor}"
68+
Write-Host "PULL_REQUEST_URL: ${pullRequestUrl}"
69+
Write-Host "USE_FORK: ${useFork}"
70+
71+
($repoOwner, $repoName) = $gitHubRepository.Split("/")
72+
$headers = $headers = @{ Authorization = "token ${gitHubAccountPAT}"}
73+
$uri = "https://api.github.com/repos/${repoOwner}/${repoName}/collaborators/${commentAuthor}/permission"
74+
Write-Host "Checking ${repoOwner} membership for ${commentAuthor} via $uri"
5075
$response = Invoke-WebRequest -Headers $headers -Uri $uri
5176
$content = $response.Content | ConvertFrom-Json
5277
$accessType = $content.permission
5378
Write-Host "Found membership: $accessType"
5479
if (-not ($accessType.Equals("admin") -or $accessType.Equals("write"))) {
55-
throw "${{ inputs.comment_author }}/permission does not have sufficient permissions for ${{ inputs.github_repository }}"
80+
throw "${commentAuthor}/permission does not have sufficient permissions for ${gitHubRepository}"
5681
}
5782
58-
Write-Host "Parsing ${{ inputs.comment_body }}"
59-
($botName, $backport, $backportTargetBranch) = [System.Text.RegularExpressions.Regex]::Split("${{ inputs.comment_body }}", "\s+")
83+
$commentBody = $env:COMMENT_BODY
84+
Write-Host "--------------------------------------------------------------------------------"
85+
Write-Host "COMMENT_BODY"
86+
Write-Host "--------------------------------------------------------------------------------"
87+
Write-Host $commentBody
88+
89+
($botName, $backport, $backportTargetBranch) = [System.Text.RegularExpressions.Regex]::Split($commentBody, "\s+")
6090
61-
Write-Host "Grabbing PR details from ${{ inputs.pull_request_url }}"
62-
$response = Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "${{ inputs.pull_request_url }}" | ConvertFrom-Json
91+
Write-Host "Grabbing PR details from ${pullRequestUrl}"
92+
$response = Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri "${pullRequestUrl}" | ConvertFrom-Json
6393
$backportPRNumber = $response.number
6494
6595
$parameters = @{
@@ -68,7 +98,7 @@ runs:
6898
BackportTargetBranch = "$backportTargetBranch";
6999
BackportPRNumber = "$backportPRNumber";
70100
BackportHeadSHA = "$($response.head.sha)";
71-
UseFork = "${{ inputs.use_fork }}" -eq "true";
101+
UseFork = $useFork -eq "true";
72102
} | ConvertTo-Json -Compress
73103
74104
$json = $parameters.Replace("`"","'")
@@ -85,10 +115,22 @@ runs:
85115
- name: Launch ADO Build
86116
id: ado_build
87117
run: |
118+
$adoOrganization = $env:ADO_ORGANIZATION
119+
$adoProject = $env:ADO_PROJECT
120+
$adoPipelineId = $env:ADO_PIPELINE_ID
121+
$adoBuildPAT = $env:ADO_BUILD_PAT
122+
$gitHubRepository = $env:GITHUB_REPOSITORY
123+
$gitHubAccountPAT = $env:GITHUB_ACCOUNT_PAT
124+
125+
Write-Host "ADO_ORGANIZATION: ${adoOrganization}"
126+
Write-Host "ADO_PROJECT: ${adoProject}"
127+
Write-Host "ADO_PIPELINE_ID: ${adoPipelineId}"
128+
Write-Host "GITHUB_REPOSITORY: ${gitHubRepository}"
129+
88130
$message = ""
89131
$statusCode = 0
90132
try {
91-
$launchURI = "https://dev.azure.com/${{ inputs.ado_organization }}/${{ inputs.ado_project }}/_apis/pipelines/${{ inputs.backport_pipeline_id }}/runs?api-version=6.0-preview.1"
133+
$launchURI = "https://dev.azure.com/${adoOrganization}/${adoProject}/_apis/pipelines/${adoPipelineId}/runs?api-version=6.0-preview.1"
92134
Write-Host "Grabbing parameters from prior step"
93135
$parameters = ConvertFrom-Json "${{ steps.get_parameters.outputs.parameters }}"
94136
Write-Host "$parameters"
@@ -106,13 +148,13 @@ runs:
106148
107149
Write-Host "Posting to $launchURI"
108150
Write-Host $jsonBody
109-
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":${{ inputs.ado_build_pat }}"))
151+
$encoded = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(":${adoBuildPAT}"))
110152
$headers = @{ Authorization = "Basic $encoded"}
111153
112154
$response = Invoke-WebRequest -UseBasicParsing -Method POST -Headers $headers -ContentType "application/json" -Uri $launchURI -Body $jsonBody
113155
$responseJson = ConvertFrom-Json $response.Content
114156
echo "Job successfully launched"
115-
$message = "Backport Job to branch **$($parameters.BackportTargetBranch)** Created! The magic is happening [here](https://dev.azure.com/${{ inputs.ado_organization }}/${{ inputs.ado_project }}/_build/results?buildId=$($responseJson.id))"
157+
$message = "Backport Job to branch **$($parameters.BackportTargetBranch)** Created! The magic is happening [here](https://dev.azure.com/${adoOrganization}/${adoProject}/_build/results?buildId=$($responseJson.id))"
116158
} catch {
117159
Write-Host $_.Exception.Message
118160
$message = "I couldn't create a backport to **$($parameters.BackportTargetBranch)** for you. :( Please check the Action logs for more details."
@@ -122,8 +164,8 @@ runs:
122164
body = $message
123165
} | ConvertTo-Json
124166
125-
$headers = @{ Authorization = "token ${{ inputs.github_account_pat }}"}
126-
$uri = "https://api.github.com/repos/${{ inputs.github_repository }}/issues/${{ steps.get_parameters.outputs.pr_number }}/comments"
167+
$headers = @{ Authorization = "token ${gitHubAccountPAT}"}
168+
$uri = "https://api.github.com/repos/${gitHubRepository}/issues/${{ steps.get_parameters.outputs.pr_number }}/comments"
127169
128170
129171
Write-Host "Posting to $uri"

0 commit comments

Comments
 (0)