Lesson 10 of 30
A green pipeline means nothing until you tell GitHub to treat it as a merge gate. Required status checks are how CI stops being advisory and starts being enforced.
14 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
By default, a CI pipeline is just informational. It runs, it reports pass or fail, and a reviewer can merge the PR anyway — green checkmark, red X, doesn't matter, the merge button works either way. Required status checks change that: you tell the repo "this named check must pass before the merge button unlocks," and GitHub enforces it mechanically. No amount of reviewer approval overrides a required check that's still red or still pending.
The mechanism underneath is simpler than it sounds: every job in a workflow reports its result back to GitHub as a check run, identified by the job's name. Branch protection doesn't know anything about YAML, triggers, or steps — it just watches for a check run with a specific name to report success on the commit a PR is trying to merge. If that name never appears at all, the rule treats it as permanently unsatisfied, not as "not applicable."
Say this repo's verify job (from the pipeline-anatomy lesson) starts testing against two Node versions instead of one:
jobs:
verify:
name: Type-check, lint, test, validate content, build
strategy:
matrix:
node-version: [20, 24]
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: pnpm
# ...same steps as before
A matrix job doesn't report one check run — it reports one per matrix leg, named by combining the job's name with the matrix value: Type-check, lint, test, validate content, build (20) and Type-check, lint, test, validate content, build (24), as two independent entries. If you go into branch protection and require only the un-suffixed name, it will never match either leg — the rule stays permanently unsatisfied and blocks every merge. You have to require the exact suffixed names, both of them, individually.
Setting that up via the GitHub CLI instead of clicking through Settings — useful because it's scriptable and reviewable as a diff, unlike a UI change:
gh api repos/adeshukla/praxis/branches/main/protection \
--method PUT \
--field required_status_checks='{"strict":true,"contexts":["Type-check, lint, test, validate content, build (20)","Type-check, lint, test, validate content, build (24)"]}' \
--field enforce_admins=true \
--field required_pull_request_reviews='{"required_approving_review_count":1}' \
--field restrictions=null
strict: true is "require branches to be up to date before merging" — a passing check only counts if it ran against a commit that already includes the latest main, not a stale branch point.
if: skipped the job — reads to branch protection as "still waiting," not "not applicable." The merge stays blocked with no obviously wrong signal to debug.main would look like after merging — catching a break that only shows up when your change combines with something someone else merged five minutes ago, which a same-PR-only rerun can't catch.How GitHub turns "an approving review" and "a passing check" into a locked merge button — the review-side mechanics, the admin-bypass gotcha, the fact that none of this lives in git history at all — belongs to GitHub's own hosting policy layer, covered elsewhere. This lesson is the other half: shaping the pipeline itself so that it produces a check run worth requiring in the first place, and getting that check run's exact name right in the rule that references it.