Building PR Risk Gates with GitHub Actions and Buildpathio
CI/CD

Building PR Risk Gates with GitHub Actions and Buildpathio

A PR risk gate is a GitHub required status check that blocks merge when a risk score exceeds a defined threshold — requiring either a risk score below the threshold, or an explicit senior engineer override. This walkthrough covers the full configuration from GitHub App install to enforced gate.

Required status checks: the mechanism

GitHub's branch protection rules allow you to designate a check as "required" — the PR cannot merge until that check passes. Buildpathio posts a check named buildpath/risk-score on every PR. When the risk score is below your block_merge threshold (default: 70), the check passes. When it exceeds the threshold, the check fails and merge is blocked by GitHub's branch protection enforcement.

This means the gate is enforced by GitHub, not by Buildpathio or by convention. Developers cannot bypass it by dismissing a review or skipping a step — they have to either lower the risk score or use the Buildpathio override workflow.

Configuring the gate in GitHub

Step 1: Install the Buildpathio GitHub App on your organization. Grant it read access to your repos and write access to commit statuses.

Step 2: Add a buildpath.yaml to your repo root with your risk threshold:

version: "1"
scan_targets:
  - path: ./services/
    type: auto-detect
risk_threshold:
  block_merge: 70
  require_review: 40

Step 3: In GitHub, navigate to your repo's Settings → Branches → Branch protection rules for your default branch. Enable "Require status checks to pass before merging" and add buildpath/risk-score to the required checks list.

After that, any PR that scores 70 or above will fail the required check and cannot merge until either the risk is addressed or an override is submitted.

Override workflow for senior engineers

Hard blocks on every HIGH-risk PR are not always appropriate — sometimes a change is genuinely necessary despite its blast radius, and a senior engineer should be able to make that call. Buildpathio's override workflow handles this:

$ buildpath override --pr 1847 --reason "Hotfix for payment processing failure, blast radius reviewed"
Override recorded. PR check re-evaluated. Score: 87 → APPROVED (override by @senior-eng)

The override clears the failing check and allows the PR to merge. The override reason and approver are logged to the audit trail. The risk score itself is not changed — the override is a deliberate bypass, not a score correction.

"The gate blocks accidentally high-risk merges. The override acknowledges intentionally high-risk merges. Both outcomes are better than no awareness at all."

Audit trail and compliance use

Every override is recorded with timestamp, PR ID, approver identity, and the reason string. This audit trail is accessible via the Buildpathio web dashboard and via the API (GET /overrides?repo={repo}&since={timestamp}).

For engineering organizations subject to change management requirements, the combination of a gate plus an auditable override record covers the "documented exception" requirement that most change management frameworks expect. The gate itself functions as a control; the override log functions as the exception documentation.

Calibrating thresholds before enforcement

One pattern that works well for teams adopting risk gates for the first time: run in observation mode for two to four weeks before enabling enforcement. In observation mode, the check runs and posts a score comment on every PR, but it never fails — it reports as neutral rather than failed or passed. This lets you see what the score distribution looks like across your actual PR volume before you decide where to set the enforcement threshold.

If you enable enforcement immediately at threshold 70 and find that 40% of your PRs score above 70, you've created too much friction. Engineers will route around it — or request that it be removed entirely. Score distributions that cluster high usually indicate that one of the scoring factors is being over-weighted for your specific graph topology. Look at the breakdown in the Buildpathio dashboard: if blast radius is driving most of the score on nearly every PR, your graph probably has a hub-and-spoke architecture where one or two central services have very high dependent counts, and the threshold for those services should be tuned separately.

Running via GitHub Actions

If you prefer managing the gate through GitHub Actions rather than the Buildpathio GitHub App, the workflow file approach gives you more control over the gate's behavior in your CI pipeline:

name: Risk Gate
on:
  pull_request:
    branches: [main]
jobs:
  gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: buildpathio/buildpath-action@v1
        with:
          api-token: ${{ secrets.BUILDPATH_API_TOKEN }}
          fail-on: HIGH
          post-comment: true

After this workflow has run once, navigate to Settings → Branches → Branch protection rules and add the step's check name as a required status check. The merge button will remain unavailable for PRs that score HIGH until either the risk is addressed or an authorized override is recorded. We're not saying teams should block on every HIGH score permanently — the threshold and override permissions should be reviewed quarterly and adjusted as your graph topology and deploy patterns evolve.