Service 07

Branch-Protection Drift Detector

Your live ruleset matches your spec — or the gate fails. Branch protection as code, with drift detection that catches GUI edits within ≤7 days.


The problem

GUI-edited branch protection drifts silently.

GitHub branch protection is GUI-edited. Anyone with repo admin can toggle off "require status checks" or remove a required check name. The change leaves no PR. There's no diff. The next time the rules matter — a security-relevant PR, an audit — the customer assumes the guarantees are in place. They might not be.

Even with the best intentions, drift accumulates. An incident demands a temporary relaxation. The fix-up commit never lands. Six months later, the relaxation is still live and forgotten.


How it works

Per-PR drift check + weekly cron reconciliation.

tools/branch-protection/spec.yaml declares the desired state for every branch + ruleset + required check. audit_branch_protection.py reads the live state via GitHub Ruleset API and diffs against the spec. Any divergence — missing check, wrong enforcement, modified actor allowlist — fails the audit and the gate.

The audit runs as a required PR status, so drift fails fast on the next PR. A weekly cron handles the case where the repo is quiet — drift is caught within 7 days regardless. The output is a structured diff: which fields drift, what's expected, what's live. Fix the spec or fix the live config — either way, the next PR re-runs the audit.

  • spec.yaml is the source of truth — every protection rule + required check listed
  • Per-PR drift check runs as a required status — fails closed on any divergence
  • Weekly cron reconciles even on quiet weeks; catches drift within 7 days max
  • Diff output is human-readable + machine-actionable — fix the spec or fix the live config
  • GitHub Ruleset API target; supports Rulesets + legacy Branch Protection Rules
spec.yaml + audit output yaml
# tools/branch-protection/spec.yaml
branches:
  main:
    ruleset: main1
    enforcement: enforced
    required_status_checks:
      - Agent Critic
      - Cycle Doc Validation
      - Branch Protection Audit
      - Quality Gate
    required_review_thread_resolution: true
    required_approving_review_count: 0
    allow_force_pushes: false
    allow_deletions: false
    bypass_actors:
      - actor_id: 12345        # @chief-engineer
        bypass_mode: pull_request
        actor_type: User

# Drift detector output (CI):
# AUDIT FAILED — drift detected on branch 'main':
#   - required_status_checks: missing "Branch Protection Audit"
#                              found:    [Agent Critic, Cycle Doc Validation, Quality Gate]
#                              expected: [Agent Critic, Cycle Doc Validation,
#                                         Branch Protection Audit, Quality Gate]
#   - bypass_actors:           drift in allowlist
#                              found:    [12345, 67890]
#                              expected: [12345]
# Fix the spec or fix the live ruleset; re-run.

Pricing relevance

Branch-Protection Drift Detector is platform-default. Fleet-level drift dashboards (across many repos) are Business+. Auto-remediation (apply spec to live) is Enterprise-tier.

Open-source posture

audit_branch_protection.py + spec.yaml schema are OSS. The auto-remediation runner stays hosted (algorithm IP).

Get Started

Branch protection is code. Drift is a regression.

Stop hoping nobody flipped that checkbox. The drift detector runs on every PR + a weekly cron — closes the silent-drift attack surface for any GitHub repo.