Set Up OWNERS and Review Rules
The webhook server does not use GitHub's CODEOWNERS. It reads its own OWNERS files from
your repository and uses them to decide who must review a pull request, who counts as an
approver, who can run commands, and which reviewers get auto-assigned.
What OWNERS controls
| Key | Effect |
|---|---|
approvers |
Members of this scope who can /approve. An approval from this list is required for the can-be-merged check only when the scope has at least one approver; a path with no approvers listed imposes no approval requirement. |
reviewers |
Members of this scope who are eligible for reviewer auto-assignment; /lgtm is not gated by membership. |
allowed-users |
Users (in addition to collaborators and contributors) who may run commands such as /retest, /cherry-pick, /rebase, /check-can-merge, /assign-reviewers. |
root-approvers |
Optional boolean. Set to false to opt out of requiring an approval from the root OWNERS approvers. |
File discovery rules
These are exact — the parser is strict.
-
The filename must be exactly
OWNERS(uppercase, no extension).OWNERS.yaml,owners,.github/CODEOWNERS, andOWNERS_ALIASESare not read. -
Files are found recursively in the cloned repository, which is checked out at the base branch of the PR. An
OWNERSfile added only in the PR branch is ignored until merged. -
Any path with a dot-prefixed directory component (
.git,.venv,.github, ...) is skipped. - At most 1000
OWNERSfiles are processed per PR. - Each file is keyed by its parent directory, not by file path.
webhook_server/OWNERSis stored underwebhook_server; the repo-rootOWNERSis stored under..
Supported syntax
Each OWNERS file is a YAML mapping. If it is not a mapping, or if approvers,
reviewers, or allowed-users is present but is not a list of strings, the file is rejected
(logged as Invalid OWNERS file <path>) and contributes nothing. Unknown keys are allowed
and ignored by the validator, with the exception of root-approvers, which is meaningful.
approvers:
- alice
- bob
reviewers:
- carol
- dave
A real example — this repository's own root OWNERS:
approvers:
- myakove
- rnetser
reviewers:
- myakove
- rnetser
A subdirectory file with the opt-out flag:
root-approvers: false
approvers:
- docs-team
reviewers:
- writer1
- writer2
allowed-users:
- "@contractor"
Notes on values:
-
Usernames are GitHub logins, matched case-sensitively against labels such as
approved-alice. Write them exactly as the login. -
allowed-usersaccepts a leading@(it is stripped), and is read only from the repo-rootOWNERS— anallowed-userslist in a subdirectory is ignored. -
root-approversonly affects a subdirectory file. Setting it in the rootOWNERShas no effect, because the root entry is always included anyway.
How owners are resolved for a PR
-
The webhook server clones the repo and runs
git diff --name-only <base_sha>...<head_sha>to get the changed files. (It falls back to two-dot..if there is no merge base.) -
It takes the parent directory of every changed file as the set of changed folders.
-
Every
OWNERSfile whose directory is equal to, or an ancestor of, a changed folder is matched. Sowebhook_server/OWNERSmatches a change towebhook_server/libs/config.py, and also matches a change towebhook_server/libs/OWNERS's subdirectories. -
The root
OWNERS(key.) is added unless a matched subdirectory file opts out withroot-approvers: false. When several files match, the first match processed decides the opt-out, so don't mix opting-out and non-opting-out files in one PR. -
all_pull_request_approvers/all_pull_request_reviewersare the de-duplicated unions of the approvers/reviewers from those matched files.
Separately, all_repository_approvers is the union of approvers from every OWNERS file in
the repository, regardless of what the PR touches. That repo-wide list is what makes a user
eligible to run commands; it is not what gates /approve.
Review commands
/approve
-
Only works if the commenter is in
all_pull_request_approvers(matched by the changed files) or in the rootOWNERSapprovers. Anyone else is silently ignored. -
Adds the label
approved-<login>and removeschanges-requested-<login>. /approve cancelremoves it.- A
/approveline anywhere in a submitted pull-request review body does the same thing. - Any
/approvetriggers the test oracle withtrigger="approved".
/lgtm
- Adds
lgtm-<login>and removeschanges-requested-<login>. -
Available to any commenter except the PR author — it is not restricted to OWNERS reviewers. Whether the LGTM counts toward
minimum-lgtmis a separate check. -
A GitHub review with state
approvedorcommentedalso produces thelgtm-<login>label. - A GitHub review with state
changes_requestedproduceschanges-requested-<login>, which blocks the merge check if that user is a matched approver.
Who may run other commands
/retest, /reprocess, /cherry-pick, /rebase, /check-can-merge, /assign-reviewer(s),
/add-allowed-user, /regenerate-welcome, /build-and-push-container, /security-override
require the commenter to be in the union of:
- repository collaborators,
- repository contributors,
- every approver in the repository (
all_repository_approvers), - the matched PR reviewers (
all_pull_request_reviewers), - root
OWNERSallowed-users.
Otherwise a maintainer or approver can grant access per-PR by commenting
/add-allowed-user @someone. A /hold label is managed with a narrower maintainers-only gate.
/assign-reviewers adds every matched reviewer as a review request (the PR author is skipped).
Configuration
These are repository-level settings under repositories.<key> in config.yaml.
minimum-lgtm
repositories:
my-repository:
name: my-org/my-repository
minimum-lgtm: 1
Default 0 (no LGTM requirement). Type: integer. When greater than zero, the welcome comment
adds a "LGTM Count" line to the merge requirements.
How the count works in check_if_can_be_merged → _check_if_pr_approved:
-
Eligible LGTM authors = matched PR reviewers + root approvers + root reviewers, minus the PR committer.
-
lgtm_countcountslgtm-<login>labels whose login is in that eligible set. Anlgtmfrom someone outside it is ignored. -
A PR passes if
lgtm_count >= minimum-lgtm, or iflgtm_countequals the total number of eligible reviewers (i.e. everyone who could have LGTM'd already has). So a repo with two eligible reviewers andminimum-lgtm: 2is satisfied by two LGTMs even if one is below the threshold in other configurations, andminimum-lgtmlarger than the reviewer count is never an impossible requirement. -
On failure the check-run reports:
Missing lgtm from reviewers. Minimum N required, (M given). Reviewers: a, b.
can-be-merged-required-labels
repositories:
my-repository:
name: my-org/my-repository
can-be-merged-required-labels:
- signed-off
- ci/green
Default []. Type: array of strings. Every listed label must be present on the PR, otherwise
the can-be-merged check run fails with Missing required labels: <label>. Unlike OWNERS
approvals, these labels can be added by anyone who can label the PR.
auto-verified-and-merged-users
# Global default, applies to all repositories
auto-verified-and-merged-users:
- release-bot
repositories:
my-repository:
name: my-org/my-repository
auto-verified-and-merged-users:
- alice
Array of strings; the repository value overrides the global one. The logins of every configured API token are appended automatically, so the bot accounts used by the webhook server are always auto-verified.
If the PR committer is in this list:
-
the
verifiedlabel and a passingverifiedcheck run are applied automatically (onopened/synchronize, and reset when the PR is re-processed); -
the welcome comment carries an auto-verified note;
- no tracking issue is created for the PR;
-
auto-merge is enabled for the PR regardless of the base branch — unless the PR touches
security-checks.suspicious-paths, in which case auto-merge is blocked and any already-enabled auto-merge is disabled; -
auto-verify-cherry-picked-prs: falsedisables auto-verification for cherry-picked PRs even for these users.
auto-verified-and-merged-users bypasses the verified step only. The can-be-merged check —
approvers, minimum-lgtm, required labels, status checks — still applies.
Merge decision summary
check_if_can_be_merged runs these and adds the can-be-merged label when all pass:
- PR is mergeable (no conflicts).
- No required status check or check run is in progress.
- No
wip/hold/has-conflictslabels (for enabled labels). - No failed or missing required status checks.
-
No
changes-requested-<login>label from a matched approver, and allcan-be-merged-required-labelspresent. -
No unresolved conversation threads when
required_conversation_resolutionis enabled. _check_if_pr_approved:- Approvers: for every matched
OWNERSfile, one of itsapproversmust be in theapproved-<login>labels — except that an approval from any root approver clears the requirement for all files at once. - LGTM: the
minimum-lgtmrule described above.
Failure output is written to the can-be-merged check run, e.g.
Missing approved from approvers: alice, bob.