Skip to content

feat: Fork PR Support with Manual Approval #2581

@DerekRoberts

Description

@DerekRoberts

UPDATE: Change as little as possible, keeping fork and standard PR handling identical. Do not add approvals for safe functions, like PR validation (conventional commits).

[FEATURE] Add Fork PR Support with Manual Approval

🎯 Problem Statement

Currently, our GitHub Actions workflows only support pull requests from the same repository. Fork PRs cannot run workflows because:

  1. No access to secrets: Fork PRs don't have access to repository secrets by default (GitHub security feature)
  2. Limited permissions: Fork PRs have restricted permissions for security reasons
  3. Workflow limitations: Our current workflows use pull_request trigger which doesn't work for forks

This prevents contributors from:

  • Using Background Agents on their forks (Cursor, GitHub Copilot, etc.)
  • Getting full CI/CD validation on their fork PRs
  • Testing deployments before merging

💡 Proposed Solution

Implement dual-trigger workflow support that:

  1. Same-repo PRs: Continue using pull_request trigger (no approval needed, immediate execution)
  2. Fork PRs: Use pull_request_target trigger with environment protection (requires manual approval)

Key Features

  • Security: Fork PRs require explicit approval before running
  • Full functionality: After approval, fork PRs get same workflows as same-repo PRs
  • Transparency: Clear separation and logging of fork vs same-repo PRs
  • Flexibility: Approvers can quickly approve trusted forks (e.g., your own fork)

📋 Implementation Details

Workflow Changes Required

Update the following workflows to support both same-repo and fork PRs:

1. .github/workflows/pr-open.yml

  • Add pull_request_target trigger
  • Add check-fork job to detect fork PRs
  • Add conditional logic to jobs:
    • Same-repo PRs: Run via pull_request trigger (no approval)
    • Fork PRs: Run via pull_request_target trigger (requires approval)
  • Add environment: fork-pr-approval to fork PR jobs
  • Ensure fork code is checked out correctly using github.event.pull_request.head.sha

2. .github/workflows/analysis.yml

  • Add pull_request_target trigger
  • Add check-fork job
  • Add conditional logic and environment protection for fork PRs
  • Update checkout steps to handle fork code

3. .github/workflows/pr-validate.yml

  • Add pull_request_target trigger
  • Add check-fork job
  • Add conditional logic and environment protection for fork PRs

Environment Setup Required

Create a GitHub Environment named fork-pr-approval:

  1. Navigate to: Settings → Environments → New environment
  2. Name: fork-pr-approval
  3. Configuration:
    • Required reviewers: Add yourself and other trusted approvers
    • Wait timer: Optional (0 minutes recommended)
    • Deployment branches: All branches (or restrict as needed)
  4. Save environment

Detection Logic

Fork detection uses:
```yaml
github.event.pull_request.head.repo.full_name != github.repository
```

Conditional Execution

Jobs will run based on:

  • Same-repo PRs: github.event_name == 'pull_request' && is_fork == 'false'
  • Fork PRs: github.event_name == 'pull_request_target' && is_fork == 'true'

Code Checkout

For fork PRs via pull_request_target, explicitly checkout the fork's code:
```yaml

  • uses: actions/checkout@v6
    if: github.event_name == 'pull_request_target'
    with:
    ref: ${{ github.event.pull_request.head.sha }}
    fetch-depth: 0
    ```

🔒 Security Considerations

Why pull_request_target?

  • Runs in the base repository context (has access to secrets)
  • Requires environment protection (manual approval)
  • Checks out fork code explicitly (controlled)

Security Benefits

  1. No automatic execution: Fork PRs cannot run workflows without approval
  2. Explicit approval: Required reviewers must approve before workflows run
  3. Audit trail: All approvals are logged in GitHub
  4. Controlled access: Secrets only available after approval

Best Practices

  • ✅ Always use environment protection for fork PRs
  • ✅ Explicitly checkout fork code (don't trust default checkout)
  • ✅ Review fork PR code before approving
  • ✅ Limit required reviewers to trusted team members

🧪 Testing Plan

Test Cases

  1. Same-repo PR (should work as before)

    • Create PR from branch in same repo
    • Verify workflows run immediately (no approval needed)
    • Verify all jobs complete successfully
  2. Fork PR (new functionality)

    • Create PR from fork repository
    • Verify workflows show "waiting for approval"
    • Approve via GitHub Environment
    • Verify workflows run after approval
    • Verify fork code is checked out correctly
    • Verify all jobs complete successfully
  3. Fork PR rejection

    • Create PR from fork
    • Verify workflows are blocked without approval
    • Verify no secrets are exposed

Validation Checklist

  • Same-repo PRs work exactly as before
  • Fork PRs require approval before running
  • Fork PRs can access secrets after approval
  • Fork code is checked out correctly
  • All workflow jobs run for approved fork PRs
  • Environment protection is properly configured
  • Documentation is updated

📚 References

✅ Acceptance Criteria

  • All three workflows (pr-open.yml, analysis.yml, pr-validate.yml) support fork PRs
  • Fork PRs require manual approval via environment protection
  • Same-repo PRs continue to work without approval
  • Fork code is correctly checked out and tested
  • Environment fork-pr-approval is created and configured
  • Documentation is updated (if needed)
  • All tests pass for both same-repo and fork PRs

🚀 Implementation Priority

Priority: Medium
Effort: ~2-3 hours
Impact: Enables fork-based contributions and Background Agent workflows

📝 Notes

  • This feature enables Background Agents (Cursor, GitHub Copilot) to work on forks
  • Useful for contributors who can't install GitHub Apps on organization repos
  • Maintains security through environment protection
  • No breaking changes to existing same-repo PR workflows

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Next

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions