Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXXI · CODEOWNERS and Ownership ControlsOwners

Team and individual owners — @user, @org/team, and the security boundary

Advanced⏱ ~20 mingit

What you'll learn

  • Distinguish individual owners from team owners and explain when each is appropriate
  • Explain why team membership is the security boundary that makes CODEOWNERS a control
  • Predict the failure mode when a team handle does not exist or has no members with merge rights
  • Identify why CODEOWNERS is a routing layer that depends on access control underneath

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

A CODEOWNERS entry names one or more owners. The form of the owner - a person, a team, an email - is not cosmetic. The form determines whether the rule survives the next reorganisation, the next resignation, and the next incident. Teams are the production-grade form; individual accounts are a transition tool that should be replaced before the team grows.

The three forms of owner

CODEOWNERS accepts three forms across the major forges:

  • @username - a personal account. @alice assigns the rule to Alice specifically.
  • @org/team-name - a team handle. @platform/platform-infra assigns the rule to every member of the team.
  • user@example.com (GitLab, with an OWNERS extension) - an email address. Rare in production.
*                @platform/platform-infra
/terraform/      @platform/platform-infra
/secrets/        @security-team

A single line can list multiple owners:

/terraform/prod/ @platform/platform-infra @security-team

When two teams are listed, both must approve in GitLab semantics; in GitHub semantics, at least one of them must approve when configured for “any one owner”.

Why team handles are the production form

The team handle survives organisational change. A team is a group of users that the org admin maintains; adding and removing members is an administrative action that does not require a CODEOWNERS change.

flowchart LR
    A[Team handle in CODEOWNERS] --> B[Org-admin maintains membership]
    B --> C[Engineer joins or leaves]
    C --> D[Handle reflects new membership automatically]
    D --> E[CODEOWNERS rule unchanged]

Contrast with a personal handle:

flowchart LR
    A[Personal handle in CODEOWNERS] --> B[Engineer leaves org]
    B --> C[Handle now points to a former employee]
    C --> D[CODEOWNERS rule references a non-member]
    D --> E[PR blocked or silently bypassed]

A personal handle becomes a problem the day the engineer leaves. The forge can no longer find a member named Alice; the rule fails in one of two ways:

  • Hard failure: the merge is blocked because no owner can approve. Safer outcome; the team must rewrite the rule.
  • Silent failure: the forge drops the unknown owner, the rule matches with fewer owners than expected, and the PR merges with insufficient review. Dangerous outcome.
cat .github/CODEOWNERS
git ls-files | grep CODEOWNERS

Team membership is the security boundary

CODEOWNERS does not define who can merge code; the forge’s access control does. CODEOWNERS defines who is required to review code that touches a given path. The security boundary is therefore team membership itself:

  • A CODEOWNERS rule saying @platform/platform-infra is required to review only works if at least one member has merge rights.
  • A team with members but no merge rights is a team that can rubber-stamp approvals that count for CODEOWNERS but cannot actually push.
  • A team handle with no members is a handle that matches no one, and the rule is unsatisfiable.

The operations team maintaining CODEOWNERS must coordinate with the IAM team maintaining team membership. A CODEOWNERS change without an IAM change is half a change.

Production discipline

Three rules. All production CODEOWNERS references team handles, never personal accounts. Every team handle has at least one member with merge rights, verified by a CI check on every PR that touches the file. Team membership changes go through the same review as code changes - adding a stranger to a CODEOWNERS team is a privilege change that deserves the same scrutiny.

Cross-course references

  • Linux for Production Sysadmins - Part XXV (GroupMgmtBasics) covers Unix groups, the access boundary that CODEOWNERS teams mirror at the Git layer.

Quiz

Knowledge check · 4 questions

  1. Q1. A CODEOWNERS rule references @alice, a personal account. Alice leaves the company. What happens on the next PR that touches her owned path?

  2. Q2. A team handle in CODEOWNERS such as @platform/platform-infra survives the departure of an individual engineer without any CODEOWNERS change.

  3. Q3. Why is a team handle the production-grade form of CODEOWNERS owner rather than a personal account?

  4. Q4. Diagnose why a CODEOWNERS rule is silently dropping a required approval.

    A team writes CODEOWNERS referencing @sre/oncall. The team exists in the org and has five members, but none has merge rights because the team was originally created as a notification-only group. A junior engineer opens a PR to a CODEOWNERS-owned path; the on-call team is auto-assigned; their approvals count; but no one can actually approve. The forge silently drops the requirement and the PR merges with no CODEOWNERS review.

Passing score: 75%. Answers are checked in this browser.