Chapter 08Lesson 04~205 minutes

Approvals, CODEOWNERS, Protected Branches and Tags, Push Rules, and Merge Governance: Diagnostics, Failure Modes, Security, and Performance

Diagnose ineffective CODEOWNERS, overlapping protection rules, bypass-capable roles, push-rule rejections, stale approvals, and policy drift using preserved evidence and least-destructive repair.

DiagnosticsRule overlapBypassApproval resetPush rejectionRecovery

Learning objectives

  • Use a repeatable diagnostic sequence for merge-governance failures rather than toggling controls blindly.
  • Diagnose ineffective CODEOWNERS, wrong/wildcard branch matches, and direct-push bypass paths.
  • Interpret push-rule rejection as pre-receive evidence and separate it from branch-permission failures.
  • Explain stale approval state after new commits and the role of approval-reset settings.
  • Repair governance with the least destructive change and verify both expected denial and expected success paths.
Availability baseline (verified 2026-08-21). GitLab Free supports optional merge-request approvals and project-level protected branches and protected tags on GitLab.com, Self-Managed, and Dedicated. Required approval rules, Code Owners/CODEOWNERS, Code Owner approval enforcement, push rules, and group-level protected-branch governance are Premium/Ultimate. The current project UI is moving protected-branch management into Settings → Repository → Branch rules; older Self-Managed releases can expose different labels. Mandatory work in this chapter therefore uses Free protected branch/tag controls, while paid governance is taught with documentation and synthetic fixtures.

1. Diagnostic sequence: preserve evidence before changing policy

Governance failures are tempting to “fix” by granting a broader role or removing the blocker. That destroys the evidence that explains why the control fired. Use a stable sequence instead:

  1. Preserve evidence: exact Git stderr, MR state, source/target SHAs, API response, matching rule names, actor role.
  2. Identify scope: offering, tier, instance/version, namespace, project, branch/tag pattern, MR, and actor.
  3. Classify enforcement point: authentication, branch/tag authorization, approval gate, push validation, CI/merge check, or inherited policy.
  4. Inspect every matching rule and the authority that can edit/bypass it.
  5. Repair minimally: change the smallest incorrect rule rather than removing protection.
  6. Retest both paths: intended action succeeds; unintended action still fails.

2. Failure: CODEOWNERS exists, but nothing is enforced

Symptom: an MR changes infrastructure/prod.tf, the repository contains CODEOWNERS, and the MR can still merge without a platform-owner approval.

Possible causes are different and must not be conflated:

  • The project is on Free, where Code Owners is not available.
  • The file is in a non-selected location because GitLab uses the first recognized CODEOWNERS location.
  • The pattern does not match the changed path.
  • The target branch is not protected.
  • Code Owner approval is not required on the matching branch rule.
  • The named user/group is not an eligible owner/approver.
  • A role has direct push-and-merge authority and bypasses the MR path.

The repair depends on the cause. “Re-add the reviewer” is not a governance repair if the actual missing component is branch protection or tier availability.

3. Intentionally broken example: the strict rule loses to a permissive wildcard

Consider this fixture:

Rule A: release/*
  Allowed to merge: Developers + Maintainers
  Allowed to push and merge: Developers + Maintainers

Rule B: release/prod
  Allowed to merge: Maintainers
  Allowed to push and merge: No one

Observed failure:
  Developer push to release/prod succeeds.

The first impulse is often “Rule B is exact, so GitLab must be ignoring it.” That diagnosis is wrong. Current protection-rule documentation says that when multiple rules match, the most permissive push/merge behavior applies. The permissive wildcard is therefore part of the effective policy.

Least-destructive repair: tighten or remove Rule A so it no longer grants direct push to the sensitive branch family. Then retest a Developer push (must fail) and the intended MR merge role (must still work).

4. Failure: approvals are configured, but Maintainer can bypass them

Symptom: the team configured required approvals on an eligible tier, yet a Maintainer updates the target without an approval.

Inspect whether the actor had Allowed to push and merge on the protected branch. That permission includes direct push and can bypass the merge-request path altogether. Also inspect who may edit/unprotect the branch and who may override MR approval rules. Governance must constrain both the normal path and the ability to rewrite the path.

Incident rule: do not “test” bypass authority on a production branch. Use a disposable project or policy fixture. If an unexpected production bypass occurred, preserve the ref update, actor identity, rule state, and audit evidence before changing policy.

5. Failure: automation push is rejected by a push rule

On Premium/Ultimate, a push rule can reject a syntactically valid, authorized push. Example fixture:

$ git push origin HEAD:automation/generated
remote: GitLab: Commit message does not follow the pattern '^PLAT-[0-9]+: '.
To gitlab.example.invalid:platform-lab/app.git
 ! [remote rejected] HEAD -> automation/generated (pre-receive hook declined)
error: failed to push some refs

Interpret the evidence in order. Authentication succeeded far enough to reach the server. The branch may be writable. The pre-receive policy rejected the commit content. Do not “fix” this by widening branch permissions or logging a token. Inspect the applicable push rule and the generated commit message, then either update the automation to comply or revise an incorrect rule through governance.

Current push rules are templates/copies rather than live inheritance in all scopes. A project can retain an older copied rule even after a group/global template changes, so compare actual project configuration instead of assuming the parent definition is active.

6. Failure: an approval looks valid after the code changed

Symptom: a reviewer approved source SHA A; a new commit produces source SHA B; the approval remains visible or disappears unexpectedly.

On Premium/Ultimate, approval settings determine whether approvals are kept, all removed after commits, or relevant Code Owner approvals removed when owned files change. Diagnose the configured setting first. Then bind evidence to the current MR source SHA. A green approval from an older revision is not sufficient evidence unless policy explicitly permits it and the team accepts that risk.

7. Failure: protection matches the wrong branch or tag

Branch and tag wildcard patterns are case-sensitive. A rule for release/* does not govern Release/1.0. Likewise, a protected tag rule v* does not necessarily describe an organization that creates release-2026.08.

Preserve the exact ref name from git ls-remote or the API, then list all rules and determine which patterns actually match. Do not rename or rewrite history merely to fit a mistaken policy; repair the policy if the naming convention is legitimate.

# Read-only ref evidence.
git ls-remote --heads origin 'refs/heads/release/*'
git ls-remote --tags origin 'refs/tags/*'

glab api "projects/$PROJECT_ID/protected_branches" --paginate   --jq '.[] | {name,push_access_levels,merge_access_levels,allow_force_push}'
glab api "projects/$PROJECT_ID/protected_tags" --paginate   --jq '.[] | {name,create_access_levels}'

8. Security, reliability, and performance where they actually matter

Governance controls mostly affect authorization and delivery reliability, not application runtime performance. Their operational cost appears elsewhere: reviewer queue time, blocked releases, failed bot pushes, CI reruns after new commits, and incident response when a rule is misconfigured.

Security improves when direct mutation is rare and policy changes are attributable. Reliability improves when the team has a tested emergency path instead of disabling controls under pressure. Performance/cost should therefore be discussed as delivery-system latency and operator load, not as generic “security slows everything down.”

9. Repair checklist

  • Exact actor, ref, MR, and SHA are recorded.
  • The failure is classified as auth, ref authorization, approval, push validation, or merge check.
  • All matching local and inherited rules were inspected.
  • The fix changes the smallest incorrect control.
  • No approval/policy bypass was granted merely to clear the failure.
  • The denied path still fails after repair.
  • The intended path succeeds after repair.
  • Exception or policy-edit authority is restored to its original state.

Knowledge check

A push returns “pre-receive hook declined” with a commit-message policy error. Should you change branch permissions first?

Why can an exact branch rule fail to make a branch stricter than a wildcard?

A CODEOWNERS file is correct and the tier supports it, but no owner approval is required. What two hosted controls should you inspect?

Why record the MR source SHA when evaluating stale approvals?

What is wrong with giving a temporary direct-push permission to “get the release out” without evidence?

Summary

Governance diagnostics are evidence-driven. CODEOWNERS can fail through tier, location, matching, eligibility, or protection configuration; overlapping rules can make a branch more permissive than it looks; direct-push authority can bypass MR gates; push rules fail at pre-receive; and approvals can become stale as SHAs change. Repair the responsible control, then prove both intended success and intended denial.

Official references

Next lesson

Checkpoint: prove a complete governance policy

Lesson 5 combines branch/tag protection, rule prediction, a real rejection, paid-feature fixtures, verification, evidence hashing, and targeted cleanup.

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.