A GitHub Action that enforces conditional approval rules on pull requests. Require different approval counts based on branch names or PR authors.
API design is inspired by policy-bot.
- Define multiple approval rules
- Conditional rules (branch name patterns, author lists, changed file patterns)
- Uses only the latest review status per user
- Creates Commit Status to show approval status
[
{
"name": "release-branch",
"if": {
"from_branch": {
"pattern": "^release/.*"
}
},
"requires": {
"count": 3
}
},
{
"name": "junior-developer",
"if": {
"has_author_in": {
"users": ["junior1", "junior2"]
}
},
"requires": {
"count": 2
}
},
{
"name": "docs-only",
"if": {
"only_changed_files": {
"paths": ["^docs/", "^\\.github/"]
}
},
"requires": {
"count": 1
}
},
{
"name": "default",
"requires": {
"count": 1
}
}
]The file is read from the base branch (e.g. main) via the GitHub API.
name: PR Approval Check
on:
pull_request_review:
types: [submitted, dismissed]
pull_request:
types: [opened, synchronize]
jobs:
check-approvals:
runs-on: ubuntu-latest
steps:
- name: Check Approval Rules
uses: WinTicket/approval-rules@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}| Input | Description | Required | Default |
|---|---|---|---|
github-token |
GitHub token for API access | No | ${{ github.token }} |
Each rule has the following structure:
{
"name": "string",
"if": {
"from_branch": {
"pattern": "string(regex)"
},
"has_author_in": {
"users": ["string"]
},
"only_changed_files": {
"paths": ["string (regex)"]
}
},
"requires": {
"count": 0
}
}name: Rule name (string)if: Conditions (optional, omit to match all PRs)from_branch.pattern: Regex pattern for branch namehas_author_in.users: List of usernamesonly_changed_files.paths: List of regex patterns matched against changed file paths
requires.count: Required number of approvals
ifomitted or empty: Matches all PRsfrom_branchonly: Applies when branch name matches the patternhas_author_inonly: Applies when PR author is in the listonly_changed_filesonly: Applies when all changed files match at least one of the patterns- Multiple conditions set: Applies when all conditions are met
Rules are evaluated in array order. The first rule that meets the approval condition creates a Commit Status.
Require 3 approvals for release branches:
{
"name": "release",
"if": {
"from_branch": {
"pattern": "^release/.*"
}
},
"requires": {
"count": 3
}
}Require 2 approvals for specific users:
{
"name": "junior",
"if": {
"has_author_in": {
"users": ["intern1", "intern2"]
}
},
"requires": {
"count": 2
}
}Require 1 approval for docs-only changes:
{
"name": "docs-only",
"if": {
"only_changed_files": {
"paths": ["^docs/", "\\.md$"]
}
},
"requires": {
"count": 1
}
}Default requires 1 approval:
{
"name": "default",
"requires": {
"count": 1
}
}This action uses Commit Status to enforce approval rules. Since GITHUB_TOKEN has permission to create commit statuses, a PR author could potentially bypass the check by directly writing a success status via the API. If you need stronger guarantees against this, consider using policy-bot, which runs as a separate GitHub App with its own credentials.
# Install dependencies
pnpm install
# Run tests
pnpm test
# Build
pnpm build
# Lint & format check
pnpm checkMIT