"Is branch protection enabled?" is a reasonable question about one repository. Asked across five hundred, it does not have an answer — it has a distribution, and nobody has measured it.
That gap is the whole subject. The controls are not hard. Keeping them true across an estate that grows every week is.
The problem: settings drift, defaults do not
A per-repository setting is a decision made once by whoever created the repository. It reflects what that person knew and cared about that afternoon.
Multiply by five hundred, across teams that joined at different times under different standards, and the estate stops having a configuration at all. It has a history. Some repositories are protected because someone was diligent in 2023, some because a template happened to include it, and some are wide open because they started as a proof of concept that quietly became a production service.
Meanwhile the number keeps growing. Every repository created tomorrow starts with whatever the platform defaults are, which is usually nothing.
You are not maintaining a configuration. You are losing a slow race against repository creation.
What actually goes wrong
Nobody can distinguish the exception from the standard. This is the real damage, and it is not that teams disable protections — sometimes there are good reasons. It is that an estate with no measured baseline makes a deliberate exception and an accidental gap look identical. You cannot govern what you cannot tell apart.
Abandoned repositories keep their access. Most organisations have a large tail of repositories nobody has touched in years, still readable by everyone who ever had access, still containing credentials in their history, still not covered by any scanning that was rolled out afterwards.
Ownership is unrecorded, so findings have nowhere to go. Every security tool you deploy across the estate produces output that needs to reach a human. Without a machine-readable owner, that routing is done by someone guessing from commit history — which does not scale past the first hundred findings.
Audit questions become projects. "Which repositories can deploy to production?" should be a query. When controls live per repository, it becomes an exercise with a deadline and a spreadsheet.
What to do
1. Archive the dead repositories first
Before governing anything, shrink what you are governing. In most organisations somewhere between a third and a half of repositories are abandoned.
Archiving makes them read-only, keeps the history, removes them from the active estate, and takes minutes. It is the cheapest risk reduction available in this whole list, and it makes every subsequent number honest — a coverage figure computed over an estate that is half-dead tells you nothing.
Rule of thumb: no commits in eighteen months and no linked deployment. Announce it, archive it, and let anyone who objects say so.
2. Move controls from repositories to the organisation
Use organisation-level rulesets rather than per-repository branch protection. The point is not that they are more powerful — it is that they apply to repositories that do not exist yet.
That single property changes the shape of the problem. A rule defined centrally covers the repository someone creates next Tuesday; a per-repository setting never will.
3. Define three tiers, not five hundred configurations
Resist per-repository bespoke rules. Something like:
- Production — protected branches, required review, required checks, deploy credentials, signed commits if you have them
- Internal — protected default branch, required review, scanning on
- Sandbox — scanning on, no deploy access, cannot be promoted without moving tier
Every repository is in a tier, and the tier is a property you can query. The value is not the specific rules; it is that "which tier is this in, and why" becomes a five-second question.
4. Make CODEOWNERS the routing table
Treat it as infrastructure rather than a review convenience. It is the only machine-readable statement of who owns what code, which makes it the thing every scanner, every alert and every dependency update depends on to reach the right team.
An estate with reliable CODEOWNERS can automate finding distribution. One without it will hand-route findings forever, and the hand-routing is what breaks first.
5. Turn on organisation audit logging and stream it
Not because you will read it, but because the questions that need it arrive after the fact and cannot be answered retroactively. Who changed that ruleset, who added that deploy key, who made that repository public.
6. Report coverage, and report drift
One number: the percentage of active repositories in a defined tier with that tier's controls in place.
Report it monthly alongside the change since last month. The absolute figure starts uncomfortable and improves slowly; the delta tells you whether governance is holding or eroding. A coverage number that is flat at 94% and a coverage number falling one point a month are very different situations that look the same on a single slide.
The thing to avoid
Do not build an exception process before you have coverage. It sounds prudent and it is backwards: an exception process applied to an estate you have not measured will simply document the current state as approved.
Measure first, tier second, then handle exceptions — by then you will know how many you actually have, which is usually far fewer than the objections during planning suggested.
Where to start
If you are staring at a large estate: archive the dead repositories, then compute the coverage number once, however roughly. Almost nobody knows it, and it is difficult to argue with.
Everything after that is a matter of sequencing, and it is much easier to sequence when you know how far you have to go.
Want help putting this into practice?
We work alongside your team to design, build, and operate the controls described above.