CODEOWNERS Guardrails
Enforce code ownership standards including CODEOWNERS file presence, syntax validity, catch-all rules, minimum owner counts, and team-based ownership. Ensure every file has a responsible owner.
codeowners to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/codeowners@v1.0.0
Included Guardrails
This policy includes 8 guardrails that enforce standards for your repository and ownership.
exists
Requires a CODEOWNERS file to be present in the repository. Checks standard locations: root, .github/, or docs/.
valid
Validates that the CODEOWNERS file has correct syntax. Checks that all owner references use valid formats (@user, @org/team, or email).
catchall
Requires a default catch-all rule (*) in CODEOWNERS so that every file in the repository has at least one owner.
min-owners
Ensures each CODEOWNERS rule has a minimum number of owners for redundancy. Configurable via the min_owners_per_rule input.
team-owners
Requires at least one team-based owner (@org/team) in the CODEOWNERS file for better ownership continuity.
no-individuals-only
Ensures each CODEOWNERS rule includes at least one team owner, not just individual users. Stricter than team-owners which only checks that teams exist somewhere in the file.
no-empty-rules
Flags CODEOWNERS rules that have no owners assigned, which effectively un-assigns ownership for matching files.
max-owners
Flags CODEOWNERS rules with too many owners. Excessive owners often means diffused responsibility where nobody truly owns the code. Configurable via the max_owners_per_rule input.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
min_owners_per_rule
|
Optional |
2
|
Minimum number of owners required per CODEOWNERS rule (for min-owners check) |
max_owners_per_rule
|
Optional |
10
|
Maximum number of owners allowed per CODEOWNERS rule (for max-owners check) |
Documentation
View on GitHubCODEOWNERS Guardrails
Enforce code ownership standards via CODEOWNERS file validation
Overview
These policies validate the CODEOWNERS file to ensure code ownership is properly defined across the repository. They check for file presence, syntax validity, catch-all coverage, owner counts, and team-based ownership. Development teams should use this policy to maintain clear ownership of every file in their repository. Requires the codeowners collector to be configured.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description |
|---|---|
exists |
CODEOWNERS file must be present |
valid |
CODEOWNERS syntax must be valid (no invalid owner formats) |
catchall |
Must have a default catch-all * rule |
min-owners |
Each rule must have at least N owners (configurable via min_owners_per_rule, default: 2) |
team-owners |
At least one team owner (@org/team) must be present |
no-individuals-only |
Each rule must include at least one team owner |
no-empty-rules |
No rules should un-assign ownership (0 owners) |
max-owners |
No rule should have more than N owners (configurable via max_owners_per_rule, default: 10) |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.ownership.codeowners.exists |
boolean | codeowners collector |
.ownership.codeowners.valid |
boolean | codeowners collector |
.ownership.codeowners.errors |
array | codeowners collector |
.ownership.codeowners.rules |
array | codeowners collector |
.ownership.codeowners.owners |
array | codeowners collector |
.ownership.codeowners.team_owners |
array | codeowners collector |
.ownership.codeowners.individual_owners |
array | codeowners collector |
Note: Ensure the codeowners collector is configured before enabling this policy.
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/codeowners@v1.0.0
on: ["domain:your-domain"]
policies:
- uses: github://earthly/lunar-lib/policies/codeowners@v1.0.0
on: ["domain:your-domain"]
enforcement: report-pr
# with:
# min_owners_per_rule: "2"
# max_owners_per_rule: "10"
Examples
Passing Example
A repository with a well-structured CODEOWNERS file:
{
"ownership": {
"codeowners": {
"exists": true,
"valid": true,
"errors": [],
"owners": ["@acme/platform", "@acme/backend", "@jane"],
"team_owners": ["@acme/platform", "@acme/backend"],
"individual_owners": ["@jane"],
"rules": [
{"pattern": "*", "owners": ["@acme/platform", "@jane"], "owner_count": 2, "line": 2},
{"pattern": "/src/", "owners": ["@acme/backend", "@jane"], "owner_count": 2, "line": 4}
]
}
}
}
This passes because: file exists, syntax is valid, catch-all * rule present, every rule has >= 2 owners, team owners are used in every rule.
Failing Example
A repository with ownership gaps:
{
"ownership": {
"codeowners": {
"exists": true,
"valid": true,
"errors": [],
"owners": ["@alice"],
"team_owners": [],
"individual_owners": ["@alice"],
"rules": [
{"pattern": "/src/", "owners": ["@alice"], "owner_count": 1, "line": 1}
]
}
}
}
Failure messages:
catchall: "CODEOWNERS has no default catch-all rule (). Add a ' @your-team' rule so every file has an owner."team-owners: "CODEOWNERS has no team-based owners (@org/team)."min-owners: "Rule '/src/' has 1 owner(s), minimum is 2"
Remediation
When these policies fail, update your CODEOWNERS file:
- Missing file: Create a
CODEOWNERSfile in the repository root,.github/, ordocs/directory - No catch-all rule: Add a
* @your-org/your-teamline as the first rule so every file has an owner - Too few owners: Add additional owners to rules — at least 2 per rule reduces bus factor risk
- No team owners: Use
@org/team-namereferences instead of only individual@usernamereferences, so ownership survives team changes - Empty rules: Remove or add owners to rules that have no owners assigned (these un-assign ownership for matching files)
- Invalid syntax: Fix owner references to use valid formats:
@user,@org/team, oremail@example.com
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 100+ built-in guardrails.