|
| 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 | + |
0 commit comments