Skip to content

Branch Protection, Privileged Access, and Code Review Policy

This guide explains how to configure a GitHub repository so that no single engineer can push untested, unreviewed code to production, and how to document those controls for government auditors. Engineers and technical leads setting up or auditing a repository for a government delivery project will find it most useful. It assumes basic familiarity with Git and GitHub.


TL;DR

  • Branch protection prevents anyone from pushing directly to main without a pull request, passing automated checks, and at least one peer review.
  • In government, this is a compliance requirement — not just good practice. The engineer who writes code cannot be the sole person approving it for production.
  • Configure these settings at the repository level, not just on individual developer accounts.
  • GitHub Enterprise logs every bypass of these protections. That log is your audit trail.
  • Emergency bypasses must follow a pre-approved “break-glass” process and be documented immediately after.

Branch Protection Fundamentals

Every change to production code passes through a branch. Branch protection is a set of rules that controls what must happen before a branch can receive a merge.

Without branch protection, anyone with write access to your repository can push directly to main. That means unreviewed code, failing tests, and security vulnerabilities can reach production without any check. In a typical open-source project, this might be an acceptable risk. In a government system that handles citizen data, it is not.

Branch protection rules live in your repository’s settings. They apply to everyone, including repository administrators — or they can be configured to exclude admins, which is a common mistake covered later in this guide.


Minimum Branch Protections for Government Projects

Every government repository must have the following protections on main (and any other branch that deploys to a production environment).

Pull Request Requirement

No one pushes directly to main. Every change arrives through a pull request. This creates a record of what changed, who changed it, and who reviewed it.

Required sub-settings

  • Require approvals: Set to at least 1. Set to 2 for repositories that handle PII, PHI, financial data, or authentication.
  • Dismiss stale pull request approvals when new commits are pushed: Enabled. If new code is added after someone approves, the approval is voided and a fresh review is required.
  • Require review from Code Owners: Enabled (once you have a CODEOWNERS file in place — see below).

Required Status Checks

Every pull request must pass automated checks before it can be merged. At minimum, require:

  • Lint — catches style errors and obvious code quality issues.
  • Unit and integration tests — confirms the change does not break existing behavior.
  • Security scan — runs a static analysis tool (e.g., CodeQL, Semgrep, Snyk) to flag known vulnerability patterns.
  • Accessibility scan — if the repository contains front-end code, an automated scan (e.g., axe-core) catches obvious WCAG violations.

Mark these checks as required, not optional. Optional status checks provide no enforcement.

Bypass Prevention

This setting is called “Do not allow bypassing the above settings” in GitHub’s UI. Enable it.

Without this setting, repository administrators can bypass branch protection for themselves. This defeats the purpose of the control. Government auditors specifically look for whether admins are exempt from the same rules as everyone else.

Push Restrictions

Limit direct push access to a dedicated service account (used only by your CI/CD system). No human user should be on this list.

Figure 1 (placeholder) — A GitHub repository settings screenshot showing the branch protection rules panel for the ‘main’ branch. Show all required settings enabled: ‘Require a pull request before merging’ (1 required review), ‘Require status checks to pass before merging’ with lint, test, and security-scan checks listed, ‘Do not allow bypassing the above settings’ checked. Show the CODEOWNERS section with a table of path-to-owner mappings.


Separation of Duties

Separation of duties means the person who does a thing cannot also be the person who approves it. In software delivery, this means:

  • The engineer who writes a feature cannot be the only reviewer who approves it for production.
  • The engineer who writes a deployment script cannot be the only person who authorizes the deployment.
  • The engineer who manages user accounts cannot also be the person who audits those accounts.

This is not a best practice. It is a requirement under federal information security standards (NIST SP 800-53 AC-5). It exists because a single person with unchecked authority is a single point of failure for both security and honesty.

In practice, this means your team needs at least two people who can review code in any given area. A team of one cannot satisfy separation of duties. If you are a solo engineer on a government project, escalate this to your program manager — it is a compliance gap.

Figure 2 (placeholder) — A separation of duties diagram showing three swim lanes: Developer (writes code, opens PR), Reviewer (reviews code, approves PR — different person from developer), CI System (runs automated checks, gates on status). Show the flow from commit → PR → review → CI pass → merge → deploy. Highlight with a red X where one person cannot complete the entire flow alone.


Privileged Access Controls

Not everyone on the team needs the same level of access. Define three levels and stick to them.

RoleGitHub PermissionWhat They Can Do
DeveloperWritePush branches, open pull requests, comment on reviews
Reviewer / ApproverWriteAll of the above, plus approve pull requests
Repository AdminAdminManage settings, branch protection rules, team membership
CI/CD Service AccountWrite (scoped)Merge after all checks pass, via an automated token — no human

Keep admin access to two or three named individuals. Admin rights should not be granted to everyone on the team by default. When someone leaves the project, remove their access promptly — ideally the same day.

Audit team membership quarterly. Review who has admin access. Check whether any accounts have been dormant for more than 90 days.


CODEOWNERS: Routing Reviews to the Right People

A CODEOWNERS file tells GitHub who must review changes to specific paths in the repository. When a pull request modifies a file that matches a CODEOWNERS rule, GitHub automatically requests a review from the designated owner. That review is required before the PR can merge.

Create the file at .github/CODEOWNERS.

Example CODEOWNERS file

# Security configuration files require the security team lead
/infra/security/ @agency-org/security-team
# Authentication and session handling require a senior engineer review
/src/auth/ @agency-org/senior-engineers
# PII-handling code requires the privacy officer's team
/src/services/pii/ @agency-org/privacy-team
/src/models/Applicant.* @agency-org/privacy-team
# CI/CD pipeline changes require a platform engineer
/.github/workflows/ @agency-org/platform-team
# Everything else falls to the default owners
* @agency-org/engineering-leads

Security configuration files, authentication code, and PII-handling logic are high-risk surfaces in government systems. A junior developer making a well-intentioned change to an auth flow can introduce a vulnerability that a security specialist would catch immediately. CODEOWNERS automates the routing so that important files always get the right reviewer — without relying on the pull request author to remember to tag someone.


Code Review Checklist for Government Projects

A code review is not just checking whether the code works. Use this checklist for every pull request that touches production code.

Functional Correctness

  • Does the code do what the ticket or requirement says it should do?
  • Are edge cases handled (empty input, null values, network failure)?
  • Does it break any existing functionality (confirmed by test results)?

Security Review (OWASP Top 10)

  • Does the change introduce any injection vulnerabilities (SQL, HTML, command)?
  • Is any user input sanitized before use?
  • Are authentication and authorization enforced on every new endpoint or function?
  • Are secrets (API keys, credentials) stored in environment variables, not in code?
  • Does any change disable or weaken an existing security control?

Accessibility Review (front-end only)

  • Do new interactive elements have accessible names and keyboard support?
  • Does any change break focus order or screen reader compatibility?
  • Is color used as the only way to convey meaning anywhere?

PII and Data Handling

  • Does this change log, store, or transmit any personally identifiable information?
  • If so, is that data encrypted at rest and in transit?
  • Is PII being sent to any third-party service that is not covered by a data sharing agreement?
  • Does this change require a Privacy Impact Assessment update?

Documentation and Tests

  • Are new tests added for the changed behavior?
  • Are existing tests updated if behavior changed?
  • Is user-facing documentation updated if the feature or behavior is visible to users?
  • Is the code itself readable — would a teammate understand it without asking for an explanation?

Emergency Bypass: The Break-Glass Process

Sometimes there is a production incident that requires an immediate hotfix. The normal review process takes time. A pre-approved break-glass process lets you bypass branch protection in a genuine emergency while still maintaining accountability.

A break-glass process must include:

  1. Dual authorization. Two named individuals must agree that the emergency justifies the bypass — not one.
  2. Pre-approved procedure. The steps are written down before any emergency happens. Improvising during an incident produces bad decisions.
  3. Immediate documentation. Within 24 hours of the bypass, a written record is filed: what was the incident, what was bypassed, who authorized it, what code was pushed, and what follow-up review happened after the fact.
  4. Post-incident review. The bypassed change is reviewed normally as soon as the incident is resolved, and the outcome is documented.

Store your break-glass procedure in your team’s runbook. Test it at least once before you need it in a real incident.


Audit Logs and Evidence for Government Reviews

GitHub Enterprise and GitHub.com (with appropriate plans) maintain an organization-level audit log of every administrative action. This log records:

  • Branch protection rule changes (who changed what, when)
  • Pull request approvals, dismissals, and merges
  • Any bypass of a required status check or approval
  • Repository permission changes
  • Team membership changes

For government programs, this log is primary evidence that your change management controls work. Auditors will ask for it. Know where to find it: Organization settings → Audit log.

Relevant NIST SP 800-53 controls that branch protection satisfies:

  • AC-2 (Account Management): Privileged access is scoped and reviewed.
  • AC-5 (Separation of Duties): Writers and approvers are different people.
  • AC-6 (Least Privilege): Access is limited to what each role needs.
  • AU-2 (Event Logging): Repository events are logged automatically.
  • CM-3 (Configuration Change Control): Changes require approval before deployment.
  • CM-4 (Security Impact Analysis): Security review is part of the code review checklist.
  • SA-10 (Developer Configuration Management): Developers cannot unilaterally modify production configurations.

If your program is pursuing a FedRAMP authorization, document each of these control implementations in your System Security Plan (SSP) with screenshots from your GitHub organization settings as supporting evidence.


Government-Specific Considerations

FISMA Change Management Evidence

FISMA requires documented evidence of change management. Your pull request history, required approvals, and audit log together form this evidence. Keep pull requests descriptive — a PR titled “fix stuff” provides less auditable evidence than “Fix SQL injection vulnerability in applicant search endpoint (fixes CVE-2026-XXXXX).”

Common Audit Findings

These show up repeatedly in government repository audits:

FindingRoot CauseFix
Admins bypass their own branch protection”Do not allow bypassing” not enabledEnable it in branch protection settings
Staging branch has no protectionsProtections only set on mainApply the same rules to every branch that deploys to any environment
CI checks are optional, not requiredStatus checks not marked as requiredMark every check as required in branch protection settings
Approvals are not dismissed after new commitsStale approval dismissal not enabledEnable “Dismiss stale pull request approvals when new commits are pushed”
Former team members still have accessNo offboarding processConduct quarterly access reviews; automate deprovisioning where possible
Service account has admin rightsCI/CD account provisioned with excess privilegeScope CI/CD service accounts to write-only; use short-lived tokens where possible

State-Level Requirements

Some state agencies have their own change management standards that go beyond federal requirements. Check with your agency’s ISSO (Information System Security Officer) before finalizing your policy.


Common Mistakes

Protecting Only the Main Branch

If staging or release deploys to real infrastructure with real data, it needs the same protections as main. Map all branches to environments, then protect each one.

Optional CI Checks

A developer can merge a pull request with failing optional checks. Required checks block the merge. Every check that matters for security or correctness must be required.

Broadly Granted Admin Rights

Admin rights let someone change branch protection rules, add themselves to teams, and approve their own pull requests. Keep admin access to the smallest possible set of people — typically two or three technical leads.

Overly Scoped Personal Access Tokens

CI/CD pipelines frequently use personal access tokens (PATs) tied to an individual’s account. If that person leaves, the token stops working. Use GitHub Apps or organization-level service accounts instead. Scope tokens to the minimum permissions needed.

Temporarily Lowered Approvals Never Reset

This sometimes happens when a team lowers the required approval count during an incident and the setting is not restored. Set a calendar reminder or automate a periodic check of your branch protection configuration.


Next Steps

  • CI/CD from Zero — Once your branch protections are in place, build the automated pipeline that enforces them.
  • Environment Parity — Understand how to keep staging and production consistent so that changes reviewed in staging actually represent what ships.

External References