{"id":49507,"date":"2025-05-28T01:24:59","date_gmt":"2025-05-28T01:24:59","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=49507"},"modified":"2025-05-28T01:24:59","modified_gmt":"2025-05-28T01:24:59","slug":"gitlab-codeowners-file-enforce-code-reviews-approvals-and-accountability","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/gitlab-codeowners-file-enforce-code-reviews-approvals-and-accountability\/","title":{"rendered":"GitLab CODEOWNERS file &#8211; enforce code reviews, approvals, and accountability"},"content":{"rendered":"\n<p>The <code>CODEOWNERS<\/code> file in <strong>GitLab<\/strong> is a special file that lets you define <strong>who is responsible (owner)<\/strong> for specific files, directories, or patterns in your repository. It\u2019s a powerful feature to enforce <strong>code reviews<\/strong>, <strong>approvals<\/strong>, and <strong>accountability<\/strong>\u2014especially for sensitive or critical parts of your codebase.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 What Does the <code>CODEOWNERS<\/code> File Do?<\/h3>\n\n\n\n<p>When a file or directory covered by a <code>CODEOWNERS<\/code> rule is <strong>modified in a merge request<\/strong>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>GitLab <strong>automatically requests approval<\/strong> from the listed owners.<\/li>\n\n\n\n<li>If you enforce <strong>approval rules<\/strong>, the MR <strong>cannot be merged<\/strong> without their review (when configured).<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcc4 Syntax of <code>CODEOWNERS<\/code><\/h3>\n\n\n\n<p>Each line defines a <strong>path pattern<\/strong> followed by one or more <strong>GitLab usernames or groups<\/strong>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Syntax: &lt;file pattern&gt; &lt;usernames or groups&gt;<\/span>\n\/README.md         @john\n\/docs\/             @tech-writers\n\/secrets<span class=\"hljs-comment\">\/*         <span class=\"hljs-doctag\">@security<\/span>-team <span class=\"hljs-doctag\">@admin<\/span>\n*.yml              <span class=\"hljs-doctag\">@devops<\/span>\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcc1 Where to Place <code>CODEOWNERS<\/code><\/h3>\n\n\n\n<p>GitLab looks for the file in one of these locations (in order of priority):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>.gitlab\/CODEOWNERS<\/code><\/li>\n\n\n\n<li><code>docs\/CODEOWNERS<\/code><\/li>\n\n\n\n<li><code>CODEOWNERS<\/code> (root)<\/li>\n<\/ol>\n\n\n\n<p>\ud83d\udc49 Best practice: place it in <code>.gitlab\/CODEOWNERS<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd10 How CODEOWNERS Works with Approval Rules<\/h3>\n\n\n\n<p>To enforce the rules:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to <strong>Project \u2192 Settings \u2192 General \u2192 Merge request approvals<\/strong><\/li>\n\n\n\n<li>Enable: <strong>\u201cRequire approval from Code Owners\u201d<\/strong><\/li>\n\n\n\n<li>GitLab will now <strong>enforce at least one approval from any listed owner<\/strong> if their path is touched.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83e\udde0 Example Use Case<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># Enforce ownership on critical configs<\/span>\n\/config\/production.yml @devops-lead\n\n<span class=\"hljs-comment\"># Only security team can approve secrets file<\/span>\n\/secrets<span class=\"hljs-comment\">\/* <span class=\"hljs-doctag\">@security<\/span>-team\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When someone opens an MR touching <code>\/config\/production.yml<\/code>, GitLab:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Requests approval from <code>@devops-lead<\/code><\/li>\n\n\n\n<li>Blocks merging if approval is required and not yet given<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udd0d Pro Tips<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You can use groups like <code>@my-org\/security<\/code> as owners.<\/li>\n\n\n\n<li>Owners must have <strong>at least Developer<\/strong> access to the repo.<\/li>\n\n\n\n<li>Use together with <strong>merge request approval rules<\/strong> for full control.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The CODEOWNERS file in GitLab is a special file that lets you define who is responsible (owner) for specific files, directories, or patterns in your repository. It\u2019s a powerful feature&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49507","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49507","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=49507"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49507\/revisions"}],"predecessor-version":[{"id":49508,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49507\/revisions\/49508"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=49507"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=49507"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=49507"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}