Why we grade pull requests, not your main branch
A green check on your main branch proves the code passed after it shipped. The control asks whether it was checked before it could ship. Those are different claims, and only one of them is a gate.
That's the whole answer. Code review, integration testing, dependency testing and static application security testing (SAST) read your pull requests for exactly that reason — not because a pipeline that runs on main is doing anything wrong. If your checks already run on every push to main, you're most of the way there. Here's the part that's missing, and why an auditor asks for it.
A gate has to be able to say no
A check that runs on main runs on code that is already in. It can tell you something broke. It cannot stop it going in.
A check on a pull request is the only one that can block the merge — and could this change have been stopped? is precisely what a change-management control is asking.
| - | Check on a pull request | Check on main after merge |
|---|---|---|
What it can do | Refuse the merge | Tell you something is already wrong |
What it proves | The change was verified before it could ship | The code passed once it had shipped |
Question it answers | Was this change controlled? | Is the system healthy right now? |
Post-merge checks are monitoring. Pre-merge checks are control. Both are worth having — only one of them satisfies the control.
Your auditor samples changes, not pipelines
An auditor doesn't test a control by asking "does your pipeline run?" They test it by looking for the exceptions rather than the successes: show me the changes that reached production in this period, and show me each one was reviewed and tested first.
That question is answered one change at a time. A pull request is a per-change record with a before and an after — who wrote it, who approved it, which checks ran on it, and when it merged. Everything the sample needs sits on one object, already timestamped.
A branch history of green ticks has no "before". It shows that main was healthy on a given day. It can't reconstruct which check ran on which change while that change could still be rejected — and that window is the entire thing being evidenced.
Evidence has to cover a period, not a moment
Most certifications these tests feed are assessed over a stretch of time — typically three to twelve months of your operation, not the day the auditor logs in. The evidence has to show the control operated throughout it.
A currently-green main branch says something true about today. A run of pull requests, each carrying its approval and its checks, says the gate held for six months. That second statement is the one being certified. It's also why the record reads the way it does — how version control tests are graded covers what that means in practice.
Why code review reads merged pull requests
Code review, specifically, reads merged pull requests. A merged pull request is a change that reached production, so that's the population it grades: for each one, does it carry an approval from someone other than the author?
A pull request that was never merged never affected anything. Holding it to the standard would mean grading work you correctly threw away — and closing a bad change is the control working, not failing.
Why the default branch is the boundary
Your default branch is the one these tests treat as production — it's the branch the branch protection test reads, and the one your auditor will ask you to point at.
So make the branch you actually ship from your repository's default branch. That one alignment keeps the line these tests draw and the line your auditor draws the same line.
Keep running the checks on main
Running the same suite on main after every merge is good practice, and none of this is an argument against it.
It catches what per-pull-request checks structurally can't: merge-order problems, drift, and the case where two changes that were each safe on their own break each other once both are in. A pull request is tested against the codebase as it was when that branch was cut. Main is tested against the codebase as it actually is.
So keep it. The answer here is both — the pull request check is the control, the main branch check is the safety net.
The change that produces the evidence
If your test suite, dependency scan and security scan already run on every push to main, you're usually one setting away: the same workflow, triggered on pull requests as well as on pushes.
Building a release process when you don't have one covers turning that into a gate, and telling UprootSecurity which CI checks to look for covers the name each test matches on.
From then on every pull request carries its own evidence, and the conversation with your auditor stops being about your pipeline and becomes a list of changes you can hand over.
