Skip to content

Commit 2eeb596

Browse files
authored
docs: explain usage to manage PR created from forked repositories (#320)
1 parent cf2de98 commit 2eeb596

1 file changed

Lines changed: 158 additions & 5 deletions

File tree

README.md

Lines changed: 158 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
permissions:
3434
pull-requests: write # allow surge-preview to create/update PR comments
3535
steps:
36-
- uses: actions/checkout@v2
36+
- uses: actions/checkout@v4
3737
- uses: afc163/surge-preview@v1
3838
id: preview_step
3939
with:
@@ -62,7 +62,7 @@ jobs:
6262
preview-job-1:
6363
runs-on: ubuntu-latest
6464
steps:
65-
- uses: actions/checkout@v2
65+
- uses: actions/checkout@v4
6666
- uses: afc163/surge-preview@v1
6767
with:
6868
surge_token: ${{ secrets.SURGE_TOKEN }}
@@ -73,7 +73,7 @@ jobs:
7373
preview-job-2:
7474
runs-on: ubuntu-latest
7575
steps:
76-
- uses: actions/checkout@v2
76+
- uses: actions/checkout@v4
7777
- uses: afc163/surge-preview@v1
7878
with:
7979
surge_token: ${{ secrets.SURGE_TOKEN }}
@@ -97,7 +97,7 @@ name: 🔂 Surge PR Preview
9797
9898
on:
9999
pull_request:
100-
# when using teardown: 'true', add default event types + closed event type
100+
# when using teardown: 'true', add default event types + closed event type (for teardown)
101101
types: [opened, synchronize, reopened, closed]
102102
push:
103103
@@ -107,7 +107,7 @@ jobs:
107107
permissions:
108108
pull-requests: write # allow surge-preview to create/update PR comments
109109
steps:
110-
- uses: actions/checkout@v2
110+
- uses: actions/checkout@v4
111111
- uses: afc163/surge-preview@v1
112112
with:
113113
surge_token: ${{ secrets.SURGE_TOKEN }}
@@ -118,6 +118,159 @@ jobs:
118118
npm run build
119119
```
120120

121+
122+
### Usage to deal with PRs created from forked repositories
123+
124+
When someone creates a PR from a forked repository, there is a security challenge: workflows triggered by `pull_request` events do not have access to your to repository secrets (like your surge token) for security reasons.
125+
126+
**Why this is a problem:** Without access to the surge token, the preview deployment will fail.
127+
128+
**Why not use `pull_request_target`?** While this event does provide access to secrets, it executes code from the PR branch with your secrets, creating a security risk. Attackers could potentially steal your secrets by submitting malicious PRs.
129+
Resources:
130+
- https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/
131+
- https://github.com/afc163/surge-preview/commit/4931cbc38d650f631f91974da3ccd4809c88aa1b and https://github.com/afc163/surge-preview/issues/99
132+
133+
134+
**Solution: Use a three-workflow Approach**
135+
136+
This approach separates the build and deployment steps for improved security:
137+
138+
1. **Build workflow**: Builds the site without needing secrets
139+
2. **Deploy workflow**: Deploys the pre-built site using your secrets
140+
3. **Teardown workflow**: Removes the preview when a PR is closed
141+
142+
#### How it works
143+
144+
1. First workflow builds the site and saves it as an artifact
145+
2. Second workflow retrieves the artifact and deploys it to Surge
146+
3. Third workflow handles cleanup when PRs are closed
147+
148+
#### Example Workflows
149+
150+
Here is an example of how to set up these workflows in your repository:
151+
152+
**Build workflow** (triggered by `pull_request`):
153+
154+
```yaml
155+
name: Surge PR Preview - Build Stage
156+
157+
on:
158+
pull_request:
159+
160+
jobs:
161+
build-preview:
162+
runs-on: ubuntu-latest
163+
164+
steps:
165+
- uses: actions/checkout@v4
166+
- name: Build site
167+
env:
168+
PR_NUMBER: ${{ github.event.pull_request.number }}
169+
# Generate a random page, containing the number of the PR
170+
# Replace with your actual build command
171+
run: |
172+
mkdir site
173+
cp -r public/surge/* site/
174+
sed -i "s/@PR_NUMBER@/${PR_NUMBER}/g" site/index.html
175+
176+
- name: Upload site artifact
177+
uses: actions/upload-artifact@v4
178+
with:
179+
name: pr-build-dist # Important: use this same name in the deploy workflow
180+
path: site/
181+
```
182+
183+
**Deploy workflow** (triggered by `workflow_run`, when the build workflow completes):
184+
185+
```yaml
186+
name: Surge PR Preview - Deploy Stage
187+
188+
on:
189+
workflow_run:
190+
workflows: ["Surge PR Preview - Build Stage"]
191+
types:
192+
- completed
193+
194+
permissions:
195+
pull-requests: write # Needed to comment on PRs
196+
197+
jobs:
198+
# Important - the job id:
199+
# MUST be unique across all surge preview deployments for a repository as the job id is used in the deployment URL
200+
# MUST be kept in sync with the job id of the teardown stage (this id is used by the surge-preview action to forge the deployment URL)
201+
deploy:
202+
runs-on: ubuntu-latest
203+
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }}
204+
205+
steps:
206+
- name: Download built site
207+
uses: dawidd6/action-download-artifact@v8
208+
with:
209+
workflow: ${{ github.event.workflow_run.workflow_id }}
210+
run_id: ${{ github.event.workflow_run.id }}
211+
name: pr-build-dist # Must match the name from build workflow
212+
path: site/
213+
214+
- name: Deploy to Surge
215+
uses: afc163/surge-preview@v1
216+
with:
217+
surge_token: ${{ secrets.SURGE_TOKEN }}
218+
github_token: ${{ secrets.GITHUB_TOKEN }}
219+
build: echo done
220+
dist: site
221+
failOnError: true
222+
teardown: false # Teardown is handled by the separate workflow
223+
```
224+
225+
**Teardown workflow** (triggered when a PR is closed):
226+
227+
```yaml
228+
name: Surge PR Preview - Teardown Stage
229+
230+
on:
231+
pull_request_target:
232+
types: [closed]
233+
234+
permissions:
235+
pull-requests: write # Needed to comment on PRs
236+
237+
jobs:
238+
deploy: # Must match the job ID from the deploy workflow
239+
runs-on: ubuntu-latest
240+
steps:
241+
- name: Teardown preview site
242+
uses: afc163/surge-preview@v1
243+
with:
244+
surge_token: ${{ secrets.SURGE_TOKEN }}
245+
github_token: ${{ secrets.GITHUB_TOKEN }}
246+
failOnError: true
247+
teardown: true
248+
build: echo "Cleaning up preview"
249+
```
250+
251+
252+
#### Troubleshooting
253+
254+
When running the workflow triggered by `workflow_run` event, the surge-preview action retrieves the number of the Pull Request associated with the workflow run by doing API calls.
255+
256+
Occasionally, the API call may hit rate limits, as the search API can use many calls internally. In this case, the error is caught and a warning is logged. Re-running the workflow should resolve the issue.
257+
258+
As a workaround, you can use a [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#about-personal-access-tokens) instead of the GITHUB_TOKEN: this PAT has a higher rate limit errors, so the API calls are more likely to succeed.
259+
260+
**Note**: Using a PAT as github_token input of the surge-preview action has a side effect: the PR comment created by the action will be created by the account to which the PAT belongs.
261+
When using GITHUB_TOKEN, the PR comments are created by the GitHub Actions bot.
262+
263+
264+
#### Limitations
265+
266+
In some situations, it is hard to know if the surge deployment has been done.
267+
268+
When a workflow is triggered by `workflow_run`, it does not appear in the PR checks, so you cannot see whether the workflow has run or if it has failed.
269+
By default, there is no status on the commit. It is possible to add this manually in the workflow, for example by using [set-commit-status-action](https://github.com/myrotvorets/set-commit-status-action).
270+
271+
However, when the workflow runs, the usual comment is updated by the `surge-preview` action to indicate whether the deployment is in progress or if the Surge deployment succeeded or failed.
272+
273+
121274
### Inputs
122275

123276
| Parameter | Description | Default |

0 commit comments

Comments
 (0)