Chapter 10Lesson 05~210 minutes

Checkpoint Lab — Protected Branches, Repository Rulesets, Push Rules, Required Checks, and Bypass Governance

Build, verify, break, satisfy, and recover a minimal repository policy. Then rehearse an emergency PR-only bypass in a throwaway repository with explicit evidence and immediate recovery so bypass remains exceptional.

Checkpoint labChange controlBreak glassAudit evidence

Checkpoint outcomes

  • Apply a minimal branch ruleset to a disposable default branch after producing a real required check.
  • Predict and capture one forbidden direct update without changing the hosted branch.
  • Complete the same class of change through a compliant PR and verify the required evidence independently.
  • Rehearse a PR-only emergency bypass once, with a failing mock gate, recorded reason, recovery PR, and removal of bypass access.
  • Write a short production policy covering normal flow, check ownership, exception triggers, audit evidence, and cleanup.
  • Finish with the repository either cleanly archived or restored to an unprotected disposable state.
Required assumptions: GitHub.com, GitHub Free, a personal account, a public repository you own/administer, GitHub Actions enabled, Git and gh installed. Ruleset creation and bypass-list changes require repository admin access. No second identity, paid plan, organization, secret, external CI service, or self-hosted runner is required.
Security-sensitive lab: this checkpoint intentionally rejects a direct push and later exercises one repository-admin PR-only bypass. Use the exact disposable repository github-governance-checkpoint. Do not adapt the bypass rehearsal to a valuable repository. If your current UI does not offer the documented PR-only bypass mode, use the supplied simulation instead of broadening privileges.

1. Setup and baseline

Shell portability: commands shown with trailing \, $(...), printf, cat <<'EOF', or rm are Git Bash/Bash/zsh syntax. In PowerShell, keep the same Git/gh arguments but use the backtick for line continuation and Set-Content/Add-Content/Remove-Item for file operations. GitHub ruleset and branch-policy semantics do not depend on the shell.
gh auth status --active --hostname github.com
gh repo create github-governance-checkpoint --public --add-readme --clone
cd github-governance-checkpoint

gh repo view --json nameWithOwner,visibility,defaultBranchRef,viewerPermission
gh ruleset list --parents
gh ruleset check --default
git status --short --branch

Write down the repository owner/name and default branch. If inherited/parent policy exists, do not stack the checkpoint on top of policy you do not control; recreate the lab under your personal account.

2. Create the evidence producer and observe its real check identity

Create this no-secret workflow before protection:

# .github/workflows/policy-gate.yml
name: policy-gate
on:
  pull_request:
permissions:
  contents: read
jobs:
  policy-gate:
    runs-on: ubuntu-latest
    steps:
      - name: Fail only the named emergency rehearsal
        if: ${{ github.event.pull_request.title == 'Emergency bypass rehearsal' }}
        run: |
          echo "intentional checkpoint failure for bypass rehearsal"
          exit 1
      - name: Pass normal pull requests
        if: ${{ github.event.pull_request.title != 'Emergency bypass rehearsal' }}
        run: echo "policy gate passed"
mkdir -p .github/workflows
# Save the workflow above.
git add .github/workflows/policy-gate.yml
git commit -m "ci: add checkpoint policy gate"
git push origin main

git switch -c observe-check
printf 'observe check
' > observe.txt
git add observe.txt
git commit -m "test: observe required check"
git push -u origin observe-check
gh pr create --base main --head observe-check --title "Observe policy gate" --body "Pre-policy check identity run."
gh pr checks --watch
gh pr merge --squash --delete-branch
git switch main && git pull --ff-only

Record the exact passing check name. Prediction 1: after the warm-up merge, main contains the workflow and observe.txt, but no ruleset yet constrains future updates.

3. Stage a minimal branch ruleset

Create checkpoint-main-policy in repository Rulesets with these properties:

  • Target: default branch.
  • Enforcement: Disabled while configuring.
  • Bypass list: empty initially.
  • Rule: require a pull request before merging, zero required approvals for this one-account lab.
  • Rule: require the observed policy-gate check.
  • Keep force pushes blocked and deletion restricted using the normal ruleset defaults where shown.

Verify the object while Disabled, then edit only enforcement to Active.

gh ruleset list -R OWNER/github-governance-checkpoint --parents

gh api -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  repos/OWNER/github-governance-checkpoint/rulesets --paginate \
  --jq '.[] | {id,name,enforcement,target}'

# After activation:
gh ruleset check --default -R OWNER/github-governance-checkpoint

Prediction 2: activating the policy changes hosted governance state but does not move any Git ref by itself.

4. Attempt one forbidden direct change and capture rejection evidence

Expected failure: the next direct push should be rejected. Preserve stderr and the local rejected commit OID. Do not disable the rule to make the push work.
git switch main
git pull --ff-only
BASE_BEFORE=$(git rev-parse origin/main)
printf 'forbidden direct path
' > forbidden.txt
git add forbidden.txt
git commit -m "test: forbidden direct update"
REJECTED_OID=$(git rev-parse HEAD)

git push origin main   # expected rejection

git fetch origin
printf 'remote_main=%s
expected_unchanged=%s
' "$(git rev-parse origin/main)" "$BASE_BEFORE"

# Discard only this intentionally rejected disposable local commit.
git reset --hard origin/main

Verification: origin/main must still equal BASE_BEFORE. Your evidence record should say which rule blocked the push, not merely “push failed.”

5. Open a compliant PR and satisfy required evidence

git switch -c normal-policy-change
printf 'normal governed change
' > normal.txt
git add normal.txt
git commit -m "docs: normal governed change"
git push -u origin normal-policy-change

gh pr create --base main --head normal-policy-change \
  --title "Normal governed change" \
  --body "Checkpoint normal path."

gh pr view --json number,baseRefOid,headRefOid,mergeStateStatus,statusCheckRollup
gh pr checks --watch
gh pr merge --squash --delete-branch

git switch main
git pull --ff-only
git log --oneline --decorate -5

Independent verification: query the active branch rules again and compare the resulting main OID with the PR merge evidence. The successful merge proves the policy permits compliant flow; it does not prove bypass is safe.

6. Prepare the emergency-bypass runbook before using bypass

Create a local evidence note outside the repository (or on paper) with:

  • Reason: Chapter 10 isolated bypass rehearsal.
  • Allowed actor: repository administrator.
  • Mode: For pull requests only.
  • Trigger: failing mock policy-gate caused solely by the exact disposable PR title Emergency bypass rehearsal.
  • Scope: one PR only.
  • Recovery: immediate PR deleting EMERGENCY_HOLD.
  • Closure: remove bypass actor and inspect Rule Insights/history if available.

Edit the ruleset bypass list: add Repository administrators and choose For pull requests only. This mode still blocks direct pushes but permits an eligible actor to choose an explicit PR bypass.

7. Rehearse one controlled PR-only bypass

Break-glass rehearsal: this step intentionally merges a PR whose mock check is failing. The content is harmless and the repository disposable. If the current GitHub UI does not expose the documented PR-only bypass control for your repository, stop before merging and use the simulation box below.
git switch -c emergency-rehearsal
printf 'intentional mock hold
' > EMERGENCY_HOLD
printf 'This is a disposable bypass rehearsal.
' > emergency-note.md
git add EMERGENCY_HOLD emergency-note.md
git commit -m "test: create emergency bypass rehearsal"
git push -u origin emergency-rehearsal

gh pr create --base main --head emergency-rehearsal \
  --title "Emergency bypass rehearsal" \
  --body "Reason: Chapter 10 isolated bypass rehearsal. Recovery PR will remove EMERGENCY_HOLD."

gh pr checks

Expected: policy-gate fails because the workflow deliberately recognizes the exact rehearsal PR title. The title is evaluated by GitHub expression syntax and is not interpolated into a shell command. Confirm a direct push is still not the bypass path. In the PR merge box, GitHub should identify that your eligible admin role can bypass the branch rules through the PR-only exception. Capture the PR number, failing check, actor, reason, and current main OID. Then, and only in this disposable lab, execute the explicit bypass merge action GitHub presents. UI wording can change; do not search for a hidden API shortcut.

Simulation fallback: if no PR-only bypass action is available, record this fixture instead: {actor: repository-admin, mode: pull_request, check: policy-gate=failure, decision: bypass-approved-for-lab, expected audit: bypass event}. Then remove the marker from the branch, let the check pass, and merge normally. Never widen bypass just to complete the exercise.

8. Recover immediately through the normal path

After a live bypass, main now contains the harmless EMERGENCY_HOLD marker, but the mock gate fails only for the exact rehearsal PR title. Recovery is deliberately a normal compliant PR, not a second bypass, and removes the marker to restore the repository state.

git switch main
git pull --ff-only
git switch -c emergency-recovery
git rm EMERGENCY_HOLD
printf '
Recovered through normal governed PR.
' >> emergency-note.md
git add emergency-note.md
git commit -m "recovery: remove emergency hold"
git push -u origin emergency-recovery

gh pr create --base main --head emergency-recovery \
  --title "Recover after bypass rehearsal" \
  --body "Removes the intentional checkpoint hold and returns to normal policy."
gh pr checks --watch
gh pr merge --squash --delete-branch

Now remove the Repository administrators bypass entry from checkpoint-main-policy. Verify the normal policy remains active and direct bypass authority is no longer configured.

9. Verify policy, bypass evidence, and cleanup

git switch main
git pull --ff-only
git status --short --branch

gh ruleset check --default -R OWNER/github-governance-checkpoint
gh ruleset list -R OWNER/github-governance-checkpoint --parents

gh api -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  repos/OWNER/github-governance-checkpoint/rulesets --paginate \
  --jq '.[] | {id,name,enforcement,target}'

Where the current ruleset UI exposes Rule Insights, inspect the failed direct action and bypass event. The exercise is incomplete if the technical change succeeded but no one can explain who bypassed what and why.

10. Write the operating policy

Your checkpoint deliverable should be a short policy with these headings:

Policy element Minimum statement
Protected scope Default/release branches governed by named ruleset(s); test patterns before rollout
Normal change path PR required; exact CI checks/reviews must pass
Check ownership Each required name/source has an owning team and rename/change procedure
Bypass trigger Only declared production emergency or policy-system outage
Bypass actor/mode Minimum actor set; prefer PR-only for humans
Evidence Incident/PR, actor, reason, blocked gate, before/after SHA, rule insight/audit record
Recovery Return through normal PR path and remove temporary bypass access
Review Retrospective asks why normal path failed and whether policy/evidence producer needs repair

11. Final cleanup / rollback

Remove the checkpoint ruleset after evidence collection, or disable it if you want to inspect it briefly. Confirm no bypass actor remains. Then archive the disposable repository:

gh ruleset check --default -R OWNER/github-governance-checkpoint
# After deleting/disabling the lab ruleset, verify again.
gh ruleset list -R OWNER/github-governance-checkpoint --parents

gh repo archive OWNER/github-governance-checkpoint

Permanent repository deletion is not required. Archiving is reversible and keeps the lab evidence available for later study.

12. Checkpoint verification

  • You predicted that activation changes policy, not a Git ref, and verified it.
  • You predicted that the direct push would fail and verified that hosted main did not move.
  • You completed a normal PR whose required check passed.
  • You configured bypass as PR-only, not unrestricted direct-push permission.
  • Any live bypass was one harmless disposable PR with explicit reason.
  • You recovered with a normal passing PR and removed bypass authority.
  • You can identify the active policy through both gh ruleset and versioned REST inspection.
  • You produced an operating policy suitable for adapting to a real protected branch.

Knowledge check

Why was the bypass actor added only after the normal compliant path was proven?

The emergency PR has a failing mock check. What evidence must be captured before bypass?

Why is the recovery PR required to pass the normal gate?

If PR-only bypass is unavailable, should you switch to “always allow” to finish the lab?

A check is renamed next month. What production process prevents a delivery outage?

What does Chapter 10 add to the production GitHub operating model?

13. Production handoff and bridge to Chapter 11

You can now explain not only how a PR merges, but why a protected release branch accepted or rejected a change and how an emergency exception is governed. Chapter 11 moves from protected integration state to tags and releases: immutable-ish names, release notes, assets, changelogs, and release governance. The same principle continues—identify the exact Git ref/object, hosted metadata, policy owner, and evidence before publishing something users may treat as a release.

Next chapter

Tags, Releases, Release Notes, Assets, Changelogs, and Release Governance: Concepts, Architecture, and Mental Model

Authoritative references

 About rulesets

 Creating rulesets for a repository

 Available rules for rulesets

 About protected branches

 REST API endpoints for rules

 GitHub CLI: gh ruleset

 Managing rulesets for a repository

 Repository rules REST API, version 2026-03-10

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.