Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# GitHub Workflows

This directory contains GitHub Actions workflows for the TruffleHog repository.

## PR Approval Check (`pr-approval-check.yml`)

This workflow enforces that at least one PR approver must be a member of the `@trufflesecurity/product-eng` team.

### How it works:

1. **Triggers**: The workflow runs on:
- `pull_request_review` events when a review is submitted
- `pull_request` events when a PR is opened, reopened, or synchronized

2. **Approval Check**: The workflow:
- Fetches all reviews for the PR
- Filters for approved reviews
- Checks if any approver is an active member of `@trufflesecurity/product-eng`
- Sets a commit status accordingly

3. **Status Check**: Creates a commit status named `product-eng-approval` with:
- ✅ **Success**: When at least one approver is a `@trufflesecurity/product-eng` member
- ❌ **Failure**: When no `@trufflesecurity/product-eng` members have approved
- ⏳ **Pending**: When waiting for reviews

### Branch Protection

To make this check required:

1. Go to Settings → Branches
2. Add or edit a branch protection rule for your main branch
3. Enable "Require status checks to pass before merging"
4. Add `product-eng-approval` to the required status checks

### Permissions

The workflow uses the default `GITHUB_TOKEN` which has sufficient permissions to:
- Read PR reviews
- Check team membership (for public teams)
- Create commit statuses

**Note**: If the `product-eng` team is private, you may need to use a personal access token with appropriate permissions.
85 changes: 85 additions & 0 deletions .github/workflows/pr-approval-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: PR Approval Check

on:
pull_request_review:
types: [submitted]
pull_request:
types: [opened, reopened, synchronize]

jobs:
check-product-eng-approval:
name: Check Product Eng Approval
runs-on: ubuntu-latest

steps:
- name: Check for Product Engineering approval
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: reviews } = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});

console.log(`Found ${reviews.length} reviews`);

// Get approved reviews
const approvals = reviews.filter(review => review.state === 'APPROVED');
console.log(`Found ${approvals.length} approvals`);

if (approvals.length === 0) {
console.log('No approvals found');
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state: 'pending',
context: 'product-eng-approval',
description: 'Waiting for approval from @trufflesecurity/product-eng member'
});
return;
}

// Check if any approver is a member of @trufflesecurity/product-eng
let hasProductEngApproval = false;

for (const approval of approvals) {
try {
const { data: membership } = await github.rest.teams.getMembershipForUserInOrg({
org: 'trufflesecurity',
team_slug: 'product-eng',
username: approval.user.login
});

if (membership.state === 'active') {
console.log(`✅ Found active product-eng member approval from: ${approval.user.login}`);
hasProductEngApproval = true;
break;
}
} catch (error) {
// User is not a member of the team (404) or other error
console.log(`❌ ${approval.user.login} is not a member of @trufflesecurity/product-eng`);
}
}

if (hasProductEngApproval) {
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state: 'success',
context: 'product-eng-approval',
description: '✅ Approved by @trufflesecurity/product-eng member'
});
} else {
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.payload.pull_request.head.sha,
state: 'failure',
context: 'product-eng-approval',
description: '❌ Requires approval from @trufflesecurity/product-eng member'
});
}
Loading