Mainfast Owners
CODEOWNERS rots quietly: people leave, teams are renamed, paths move, and files end up with no reviewer. On a pull request Mainfast Owners lists the changed files no working code owner covers and lints the PR's own CODEOWNERS edit. Once a week it audits the whole file, dormant owners included.
What it catches
- unowned-files: changed files whose deciding line has no owner, or only owners who cannot review. The comment suggests lines to add.
- unknown-user, owner-left-org, owner-no-write: owners who do not exist, left the org, or lack write access.
- team-not-found, team-no-write, team-wrong-org: teams that do not exist, cannot write to the repo, or belong to another org.
- rule-without-valid-owner: a line whose owners are all invalid, so its paths are unowned.
- invalid-line, github-error, too-large: syntax GitHub skips (negation, [ ] ranges, GitLab sections), GitHub's own errors, files over 3 MB.
- pattern-matches-nothing and shadowed-rule: dead patterns, and lines that never decide a file because later lines win.
- dormant-owner and dormant-team (weekly audit only): no PR review in 180 days by default.
What you see
A real PR comment from a private test repository, where a PR adds a file no CODEOWNERS rule covers.
Install
name: Mainfast Owners
on:
pull_request:
schedule:
- cron: "23 6 * * 1" # weekly audit
workflow_dispatch:
permissions:
contents: read
pull-requests: write
jobs:
owners:
runs-on: ubuntu-latest
steps:
- uses: mainfast/owners@v0
with:
org-token: ${{ secrets.MAINFAST_OWNERS_ORG_TOKEN }} # optionalnpx mainfast-owners lint --repo . # offline, no token
GITHUB_TOKEN=... npx mainfast-owners audit --github-repo owner/name [--ref main]
GITHUB_TOKEN=... npx mainfast-owners pr --github-repo owner/name --pr 42 [--comment]Step by step, with what to check after each part: installation manual. Everything else: the README.
Permissions
- contents: read: CODEOWNERS and .mainfast.yml at the base/default branch and PR head, the git tree, and GitHub's CODEOWNERS errors. Without it the run stops.
- pull-requests: write: reads the PR's changed files and posts the one sticky comment. With read only there is no comment but the result stands.
- Optional org-token with Organization permission Members: Read-only (a fine-grained token or a GitHub App). Store it as the MAINFAST_OWNERS_ORG_TOKEN secret.
- Without the org-token, org membership, team existence and team access are skipped with one note; teams count as valid and users are still checked.
- GITHUB_TOKEN cannot have any organization permission, so it can never see private org membership or teams.
- Dormancy uses the search API (30 requests a minute), at most 100 requests per run by default.
Privacy
- Everything is read through the GitHub API at the base or default branch, never from a checkout. No PR code is fetched or run, so pull_request_target is safe too.
- For fork PRs and outside authors, owners are checked for public account existence only, and the org-token is never used.
- This stops a PR author using the comment to probe your org by putting any @user or @org/team into CODEOWNERS.
- Nothing is sent to a third party; only GitHub API calls with your tokens. With a licence key, only the key and the organisation id go to Polar to check it.
- File paths, patterns, owners, team slugs and GitHub error text are escaped: no HTML, no links, no @ mentions.
Limits
- A renamed file is judged by its new path only.
- Dormancy counts PRs the user reviewed in the window, per GitHub search; review comments without a review do not count. Never checked on PRs.
- The comment lists the first 50 unowned paths and 100 findings per table; the report output has all.
- A truncated tree listing (very large repositories) skips dead and shadowed patterns, with a note.
- Email owners cannot be verified through the API.
- A PR is judged against the base branch's CODEOWNERS, so a path it newly covers still shows as unowned until the line is merged.
More in Mainfast
Install Mainfast Owners
Catch CODEOWNERS drift: unowned files, departed owners, missing teams, dead patterns.
