How to identify GitHub merge commits that bypassed mandatory status checks

I can successfully retrieve merged commits from the past day, but I need help finding the specific command or method to identify merges that were pushed through while bypassing mandatory status checks in GitHub.

I’ve attempted several different commands and approaches, but none of them seem to include information about whether the required validation checks were satisfied or overridden during the merge process.

By “mandatory status checks” I’m referring to the branch protection rules that require certain CI/CD pipelines, tests, or other automated checks to pass before allowing a merge. Sometimes administrators or users with appropriate permissions can force a merge even when these checks haven’t passed or are still running.

Is there a Git command, GitHub CLI option, or API endpoint that can help me identify these specific types of forced merges where the required validations were bypassed?

Use GitHub CLI: gh pr list --state merged --json number,mergedAt then run gh pr view {number} --json statusCheckRollup,mergeable for each PR. If mergeable shows CONFLICTING or UNKNOWN but it merged anyway, you’ve found your bypassed merge. Works well from what I’ve seen.

To identify GitHub merge commits that bypassed mandatory status checks, you can utilize the GitHub REST API. By querying the endpoint /repos/{owner}/{repo}/pulls/{pull_number}, inspect the merged_by field along with the status check data. If any required checks were bypassed, the merge will be visible, but the status contexts for those checks might indicate failures or pendings. Another useful endpoint is /repos/{owner}/{repo}/commits/{commit_sha}/status, which will indicate if a merge was allowed despite any failures or pending checks. Additionally, setting up webhook listeners for pull_request events can assist in monitoring future merges that occur without fully satisfied checks.

The GitHub Events API gives you another way to catch these bypasses. Hit /repos/{owner}/{repo}/events and look for PushEvent types on your protected branches. Then check those push times against your CI status completion times from /repos/{owner}/{repo}/commits/{sha}/check-runs. If you see merges that happened before required checks finished or while they were failing, you’ve got a bypass. This catches edge cases where admins push directly to protected branches or use emergency merge permissions. The events API keeps data for 90 days, so you can analyze way more than just the past day. Also check bypass_required_status_checks in your org’s audit logs to see who has override permissions - gives you the full picture.

The Problem:

You need a way to automatically identify GitHub merge commits that bypassed mandatory status checks, going beyond simply retrieving merged commits from the past day. You’re looking for a solution that can detect when merges occurred despite failures or pending required CI/CD pipelines, tests, or other automated checks.

:thinking: Understanding the “Why” (The Root Cause):

Manually checking for bypassed merges through the GitHub UI or with individual API calls is inefficient, especially across multiple repositories and with frequent merges. This process is prone to human error and doesn’t scale well. An automated solution is needed to continuously monitor merges and alert you to those that bypassed checks, ensuring better security and CI/CD integrity.

:gear: Step-by-Step Guide:

  1. Automate Merge Bypass Detection with a Custom Script: The most effective approach is to create a script (the example below is conceptual; adapt it to your specific needs and programming language) that regularly checks for bypassed merges. This script will leverage GitHub’s APIs to compare the status of merged pull requests against the required status checks defined in your branch protection rules.
import requests
import os
from datetime import datetime, timedelta

# GitHub API credentials (replace with your actual tokens)
GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
REPO_OWNER = "your_repo_owner"
REPO_NAME = "your_repo_name"

# Function to fetch pull requests merged in the last day
def get_merged_prs():
    url = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/pulls?state=closed&sort=updated&direction=desc"
    headers = {"Authorization": f"token {GITHUB_TOKEN}"}
    response = requests.get(url, headers=headers)
    return response.json()

# Function to check pull request status against required checks
def check_pr_status(pr_number):
    url = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/pulls/{pr_number}"
    headers = {"Authorization": f"token {GITHUB_TOKEN}"}
    response = requests.get(url, headers=headers)
    pr_data = response.json()
    # Logic to compare pr_data['status_check_rollup'] against required checks defined in branch protection rules
    # This section needs to be tailored to your specific branch protection rules and status check names.
    # ... (Your logic here to compare and determine if checks were bypassed) ...
    return bypassed

# Main script
if __name__ == "__main__":
    merged_prs = get_merged_prs()
    one_day_ago = datetime.now() - timedelta(days=1)
    for pr in merged_prs:
        merged_at = datetime.strptime(pr['merged_at'], '%Y-%m-%dT%H:%M:%SZ')
        if merged_at > one_day_ago:
            if check_pr_status(pr['number']):
                print(f"Pull request #{pr['number']} bypassed status checks!")

  1. Schedule the Script: Use a task scheduler (like cron on Linux/macOS or Task Scheduler on Windows) to run your script regularly (e.g., every hour).

  2. Alerting Mechanism: Implement an alerting system (email, Slack, etc.) to notify you when the script detects a bypassed merge. The script above already includes a print statement that can be adapted to send alerts through various channels.

:mag: Common Pitfalls & What to Check Next:

  • Rate Limiting: GitHub’s API has rate limits. If you’re monitoring many repositories, consider using pagination and implementing error handling to avoid hitting the limits.
  • Authentication: Ensure your GitHub Personal Access Token (GITHUB_TOKEN) has the necessary permissions to access the required API endpoints.
  • Branch Protection Rules: Your script’s logic must accurately reflect your branch protection rules. Any changes to these rules require corresponding updates to your script.
  • Error Handling: Implement robust error handling in your script to gracefully manage potential API errors or network issues.

:speech_balloon: Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!

I work in enterprise environments and found a simpler way to spot bypassed checks - just look at the merge commit metadata directly instead of wrestling with complex API queries. Run git show --format=fuller <merge-commit-sha> to get the full commit details, then scan the commit message patterns. GitHub automatically adds specific text when admins override branch protection rules. Also check for merges where the timestamp comes before your CI logs show the required checks actually finished. You can also hit the protection endpoint /repos/{owner}/{repo}/branches/{branch}/protection to see what checks were supposed to run at merge time, then compare that against the actual status data for that commit. This approach is great for auditing old merges where the API event data’s already gone.

GitHub’s GraphQL API works better than REST for this. Query the pullRequest object and check mergeStateStatus alongside statusCheckRollup. When someone bypasses required checks, you’ll see BEHIND, DIRTY, or UNSTABLE in mergeStateStatus even though the merge went through. I’ve had good luck checking commit status directly with git log --merges --oneline and cross-referencing each merge commit’s SHA against required status checks through GitHub’s API. Look for mismatches between what branch protection rules required and what actually passed. If you’ve got enterprise access, GitHub’s audit log API tracks bypassed branch protection rules during merges - perfect for automated monitoring.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.