Skip to content

Commit 89ee70c

Browse files
committed
Enable ci for external collaborators
1 parent f8e5d10 commit 89ee70c

File tree

8 files changed

+1069
-0
lines changed

8 files changed

+1069
-0
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# CI Trigger Implementation for External PRs
2+
3+
## Overview
4+
5+
This implementation solves the problem of CI not running for external contributor PRs due to GitHub Actions security restrictions that prevent access to repository secrets.
6+
7+
## Files Created
8+
9+
### 1. `.github/workflows/trigger-ci.yml`
10+
11+
**Purpose:** Main workflow that triggers CI for external PRs
12+
13+
**Trigger:** `issue_comment` event with `/run-ci` command
14+
15+
**Key Features:**
16+
- Permission check: Verifies commenter has admin or write access
17+
- Fetches external PR branch from fork
18+
- Creates a new branch in main repo (pattern: `ci-test/{pr-number}-{timestamp}`)
19+
- Creates a draft PR that triggers all existing CI workflows
20+
- Comments on original PR with status
21+
- Adds labels: `ci-test`, `automated`
22+
23+
**Security:**
24+
- Only admin/write access users can trigger
25+
- Fails gracefully with clear error message for unauthorized users
26+
- Comments on PR to notify unauthorized attempts
27+
28+
### 2. `.github/workflows/cleanup-ci-test-prs.yml`
29+
30+
**Purpose:** Automatic cleanup of CI test PRs
31+
32+
**Trigger:** `workflow_run` event when "Tests" workflow completes
33+
34+
**Key Features:**
35+
- Detects CI test branches (prefix: `ci-test/`)
36+
- Comments on CI test PR with results (✅ or ❌)
37+
- Closes the draft PR automatically
38+
- Deletes the temporary branch
39+
- Comments on original PR with final results
40+
- Links to full test run
41+
42+
### 3. `.github/EXTERNAL_PR_CI.md`
43+
44+
**Purpose:** Comprehensive documentation for the feature
45+
46+
**Contents:**
47+
- Problem statement
48+
- Solution explanation
49+
- How-to guide for admins
50+
- Workflow details
51+
- Security considerations
52+
- Troubleshooting guide
53+
- Limitations
54+
55+
### 4. Updated `README.md`
56+
57+
**Purpose:** Inform external contributors about the process
58+
59+
**Changes:**
60+
- Added "For External Contributors" section
61+
- Links to detailed documentation
62+
- Explains that maintainers will trigger CI
63+
64+
## How It Works
65+
66+
### Flow Diagram
67+
68+
```
69+
1. External Contributor submits PR
70+
71+
2. Admin reviews code
72+
73+
3. Admin comments "/run-ci" on PR
74+
75+
4. trigger-ci.yml workflow runs:
76+
- Checks admin permissions ✓
77+
- Fetches external branch
78+
- Creates ci-test branch
79+
- Creates draft PR
80+
- Comments on original PR
81+
82+
5. All CI workflows run on draft PR
83+
(with full access to secrets)
84+
85+
6. Tests complete (success or failure)
86+
87+
7. cleanup-ci-test-prs.yml workflow runs:
88+
- Comments on draft PR with results
89+
- Closes draft PR
90+
- Deletes ci-test branch
91+
- Comments on original PR with results
92+
```
93+
94+
## Testing the Implementation
95+
96+
### Test Scenario 1: Authorized User
97+
98+
1. Create a test PR from a fork (or ask an external contributor)
99+
2. Comment `/run-ci` on the PR as an admin
100+
3. Expected results:
101+
- New draft PR created with title `[CI Test] {original title}`
102+
- Comment appears on original PR with success message
103+
- CI workflows start running on draft PR
104+
- After CI completes, draft PR is closed
105+
- Original PR receives comment with results
106+
107+
### Test Scenario 2: Unauthorized User
108+
109+
1. Create a test PR from a fork
110+
2. Comment `/run-ci` on the PR as a non-admin user
111+
3. Expected results:
112+
- Comment appears: "❌ Only repository admins..."
113+
- No draft PR created
114+
- Workflow fails with permission error
115+
116+
### Test Scenario 3: Not a PR Comment
117+
118+
1. Comment `/run-ci` on an issue (not a PR)
119+
2. Expected results:
120+
- Workflow doesn't run (filtered by `if` condition)
121+
122+
### Test Scenario 4: CI Cleanup
123+
124+
1. After a CI test PR completes:
125+
2. Expected results:
126+
- Draft PR gets comment with ✅ or ❌ status
127+
- Draft PR is automatically closed
128+
- Branch `ci-test/{number}-{timestamp}` is deleted
129+
- Original PR receives comment with results link
130+
131+
## Security Considerations
132+
133+
### Why This Is Safe
134+
135+
1. **Permission Gating:** Only admin/write users can trigger
136+
2. **Code Review Required:** Admins must manually review before triggering
137+
3. **Audit Trail:** All actions are logged in PR comments
138+
4. **Isolated Branches:** Each test uses a unique branch name
139+
5. **Automatic Cleanup:** Temporary branches are deleted after use
140+
141+
### Risks to Be Aware Of
142+
143+
1. **Secret Exposure:** Malicious code in external PR could attempt to exfiltrate secrets
144+
- Mitigation: Admins MUST review code before triggering
145+
2. **Resource Usage:** Multiple CI runs increase GitHub Actions minutes
146+
- Mitigation: Only trigger when necessary
147+
3. **Branch Spam:** Could create many branches if used excessively
148+
- Mitigation: Automatic cleanup workflow
149+
150+
## Workflow Permissions
151+
152+
Both workflows use these permissions:
153+
```yaml
154+
permissions:
155+
contents: write # Create branches, delete branches
156+
pull-requests: write # Create PRs, update PRs
157+
issues: write # Create comments
158+
```
159+
160+
## Integration with Existing CI
161+
162+
The implementation works seamlessly with existing CI:
163+
- All existing workflows in `tests.yml` run on the draft PR
164+
- E2E tests have access to secrets (VERCEL_LABS_TOKEN, etc.)
165+
- Vercel deployments trigger automatically
166+
- Results are reported back to original PR
167+
168+
## Future Enhancements
169+
170+
Potential improvements:
171+
1. Add `/cancel-ci` command to stop running tests
172+
2. Support for re-running specific failed jobs
173+
3. Automatic retry on flaky test failures
174+
4. Status checks on original PR that mirror draft PR status
175+
5. Configurable retention period for CI branches
176+
6. Support for multiple CI runs per PR with history
177+
178+
## Troubleshooting
179+
180+
### Common Issues
181+
182+
**Issue:** Branch already exists error
183+
- **Cause:** Timestamp collision (very rare)
184+
- **Solution:** Wait 1 second and retry `/run-ci`
185+
186+
**Issue:** Cannot fetch external branch
187+
- **Cause:** Fork is private or deleted
188+
- **Solution:** Ask contributor to make fork public
189+
190+
**Issue:** Draft PR not created
191+
- **Cause:** Base branch protected, insufficient permissions
192+
- **Solution:** Check GitHub Actions logs for specific error
193+
194+
## Monitoring
195+
196+
To monitor usage:
197+
1. Check Actions tab for "Trigger CI for External PRs" runs
198+
2. Search for PRs with label `ci-test`
199+
3. Review comments from `github-actions` bot
200+
201+
## Maintenance
202+
203+
### Updating the Workflows
204+
205+
If you need to modify the workflows:
206+
1. Test changes on a fork first
207+
2. Be careful with permissions
208+
3. Update this documentation
209+
210+
### Dependencies
211+
212+
The workflows depend on:
213+
- `actions/checkout@v4`
214+
- `actions/github-script@v7`
215+
- `git` command-line tool (built-in)
216+
217+
## Questions?
218+
219+
For questions or issues with this implementation:
220+
- Open a GitHub Discussion
221+
- Create an issue with label `ci-automation`
222+
- Contact the repository maintainers
223+

.github/EXTERNAL_PR_CI.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Running CI for External Contributor PRs
2+
3+
## Problem
4+
5+
When external contributors (non-members) submit pull requests, GitHub Actions has security restrictions that prevent:
6+
7+
1. Vercel deployments from automatically running
8+
2. Secret environment variables (like `VERCEL_LABS_TOKEN`, `TURBO_TOKEN`) from being injected into workflows
9+
10+
This means E2E tests and other CI checks that depend on these secrets will fail or not run at all.
11+
12+
## Solution
13+
14+
We've implemented a `/run-ci` command that repository admins can use to trigger CI for external PRs.
15+
16+
## How It Works
17+
18+
### For Repository Admins
19+
20+
When an external contributor submits a PR:
21+
22+
1. Review the PR code for any malicious content (this is important for security!)
23+
2. Comment `/run-ci` on the PR
24+
3. The workflow will:
25+
- Verify you have admin/write permissions
26+
- Create a new branch in the main repository based on the external PR's branch
27+
- Create a draft PR from that branch
28+
- Run all CI checks with full access to secrets
29+
4. Once CI completes, you'll get a notification on the original PR with the results
30+
5. The draft PR will be automatically closed and the branch deleted
31+
32+
### Workflow Details
33+
34+
**Trigger Workflow** (`.github/workflows/trigger-ci.yml`):
35+
- Triggered by: PR comments containing `/run-ci`
36+
- Permissions required: Admin or Write access
37+
- Creates: A draft PR with the naming pattern `[CI Test] {original PR title}`
38+
- Labels: `ci-test`, `automated`
39+
40+
**Cleanup Workflow** (`.github/workflows/cleanup-ci-test-prs.yml`):
41+
- Triggered by: Completion of the "Tests" workflow
42+
- Automatically closes CI test PRs
43+
- Deletes the temporary CI test branches
44+
- Comments on both the CI test PR and original PR with results
45+
46+
## Security Considerations
47+
48+
⚠️ **Important Security Notes:**
49+
50+
1. **Only admins/maintainers should trigger CI** - The `/run-ci` command requires admin or write permissions
51+
2. **Review code before triggering** - Always review the PR code before running CI, as it will have access to repository secrets
52+
3. **Malicious code risk** - External PRs could contain malicious code that attempts to exfiltrate secrets
53+
4. **Branch protection** - The main branch should have branch protection rules enabled
54+
55+
## Example Usage
56+
57+
```markdown
58+
Comment on PR #123:
59+
60+
/run-ci
61+
```
62+
63+
Response:
64+
65+
```markdown
66+
✅ CI test triggered by @admin-username!
67+
68+
CI is now running in draft PR #456. You can monitor the progress there.
69+
70+
Once the tests complete, you can review the results and the draft PR will be automatically closed.
71+
```
72+
73+
## Branch Naming Convention
74+
75+
CI test branches follow the pattern:
76+
```
77+
ci-test/{original-pr-number}-{timestamp}
78+
```
79+
80+
Example: `ci-test/123-1699876543210`
81+
82+
## Troubleshooting
83+
84+
### "Insufficient permissions" error
85+
86+
Only repository admins and members with write access can trigger CI. If you see this error, you don't have the required permissions.
87+
88+
### CI test PR not created
89+
90+
1. Check that the comment was on a pull request (not an issue)
91+
2. Verify the exact text `/run-ci` was in the comment
92+
3. Check the GitHub Actions logs for the "Trigger CI for External PRs" workflow
93+
94+
### Branch conflicts
95+
96+
If the external PR's branch has conflicts with the base branch, the CI test PR will also have those conflicts. The contributor should resolve conflicts in their original PR first.
97+
98+
## Limitations
99+
100+
1. The external contributor's branch must be accessible (public fork or within the same organization)
101+
2. CI tests will run against the code at the time `/run-ci` was triggered. If the contributor pushes new commits, you'll need to run `/run-ci` again
102+
3. Only one CI test can be running per PR at a time (subsequent `/run-ci` commands will create new test PRs)
103+

0 commit comments

Comments
 (0)