Skip to content
Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Latest commit

 

History

157 Commits

Folders and files

Repository files navigation

CI codecov PyPI PyPI downloads Python versions License: MIT

CheckOwners

Keep CODEOWNERS aligned with reality.

$ checkowners --offline drift

severity: HIGH (Δmax=1.00)
                                CODEOWNERS Drift                                
┏━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Category ┃ Path       ┃    Δ ┃ Reason                                        ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ changed  │ /payments/ │ 1.00 │ owners diverge on 2 of 2 covered path(s)      │
│          │            │      │ (line 1)                                      │
└──────────┴────────────┴──────┴───────────────────────────────────────────────┘

CheckOwners analyzes git and review history to infer who actually knows each part of your repository, then compares that evidence with your CODEOWNERS policy. Use it to detect stale or incorrect rules, find code with dangerously concentrated knowledge, recommend knowledgeable reviewers, and discover ownership gaps before they become operational risk.

Local-first. Git-native. No source-code upload. No LLM required. The core install is pure git. With no token, CheckOwners sends nothing anywhere. checkowners --offline opens no network connection. PyPI releases use Trusted Publishing. Sigstore signs each distribution.

This is a knowledge-risk tool, not a performance-measurement tool. Using it for individual evaluation is unsupported and harmful.

uvx checkowners drift

Install

Requires Python 3.11 through 3.14 and Git 2.23 or newer.

pip install checkowners               # core CLI (pure git, zero API deps)
pip install "checkowners[graph]"      # + networkx-backed graph / topology / onboard
pip install "checkowners[github]"     # + GitHub API handle/team/review resolution
pip install "checkowners[all]"        # everything

Run

checkowners --offline drift

Exit status is the same for every command: 0 clean, 1 internal error, 2 configuration or usage, 3 findings, 4 git or GitHub failure. checkowners --exit-zero hides findings only. See Exit codes.

CI

Least privilege (job summary only; no pull-request comment):

name: checkowners
on: [pull_request]

jobs:
  drift:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: smusali/checkowners@v0
        with:
          config: .github/checkowners.yml
          comment_on_pr: false

Same-repo comments need pull-requests: write. The comment workflow and the pre-commit hooks are in GitHub Actions and Pre-commit.

CheckOwners treats code ownership as a confidence-scored spectrum rather than a static binary declaration.

No other open-source tool combines git-history inference, per-path ownership scores with evidence quality, pattern-aware drift with severity tiers, and knowledge-risk reporting behind a single CI-native JSON contract.

See it

checkowners --offline drift on a sanitized two-person tree. The committed rule is /payments/ @platform.

checkowners drift reporting high severity on /payments/

The composite Action posts that finding as one comment on same-repo pull requests:

CheckOwners pull-request comment for high-severity drift

generate --force on the same tree writes examples/sample-CODEOWNERS:

# Generated by checkOwners. Do not edit manually.

/payments/ @alice @bob

How it works

analyze reads git log and git blame and caches an ownership map per repo under ~/.checkowners/.

  • Noreply addresses become GitHub @handles locally. Other addresses use the GitHub API when a token is set.
  • One person with several emails counts once.
  • generate writes CODEOWNERS and collapses a directory of identical owners into one dir/ rule.
  • drift matches the committed file with GitHub's CODEOWNERS rules: directories, globs, last match wins.

Other reports use that same map. The table below lists them. In CI, the composite Action writes GITHUB_OUTPUT, a job summary, and one pull-request comment on same-repo pull requests.

Scoring commands accept --json, --as-of, and SOURCE_DATE_EPOCH. The default instant is the HEAD committer time. graph uses --export dot instead of --json.

The full pipeline is in docs/USAGE.md.

Command What it does
checkowners analyze Infer ownership scores, qualified owner count, and continuity-risk warnings
checkowners generate Write CODEOWNERS, ordered by ownership score; optional inline annotations
checkowners explain-path <path> Show which CODEOWNERS rule owns a path, and the full match chain
checkowners explain <path> Decompose inferred scores (signals, evidence, --why-not, --owner)
checkowners owners <path> Minimal ranked owner list (who is an alias)
checkowners print Print inferred ownership to stdout
checkowners validate Validate existing CODEOWNERS syntax
checkowners drift Compare inferred vs current; severity + max ownership-score delta
checkowners baseline create Write an accepted-findings file so later runs fail only on new findings
checkowners sync Open a pull request proposing CODEOWNERS changes (--commit commits locally)
checkowners expertise <path> Evidence ranking for one path from cached analysis
checkowners risk Rank paths by composite knowledge risk. bus-factor and decay are aliases
checkowners graph [--export dot] Render the ownership graph
checkowners qualified-owners [<path>] [--all] Per-path qualified owner count (capped by top_n_owners) with candidate backup reviewers
checkowners simulate --remove @alice What breaks if those people leave, from the cached map
checkowners topology Exploratory repository topology from commit co-occurrence
checkowners suggest Recommend a reviewer from expertise and current load. balance is an alias
checkowners onboard <path> Learning path from broadly shared paths to concentrated qualified ownership
checkowners trends [--periods N] [--period-days D] Historical activity and qualified owner count over time
checkowners github-action Run the full CI flow and write GITHUB_OUTPUT; used by the composite Action
Removing 2 of 34 contributors:

Files losing their ONLY owner ......... 412  (3.4% of repo)
Files dropping to bus factor 1 ........ 1,203
Directories fully orphaned ............ 7
   services/billing/          182 files   no remaining owner
   infra/terraform/vpc/        41 files   no remaining owner
Repo truck factor ..................... 4 -> 2

Suggested transfers (candidate backup reviewers, by residual confidence):
   services/billing/   -> @carol (0.61)  @dave (0.44)
   infra/terraform/vpc -> @erin  (0.38)  no strong second

Trimmed JSON from this repository is in examples/sample-output.md. Reference configs live under examples/.

Trust

Core inference is local git. checkowners --offline opens no network connection. With no token, CheckOwners sends nothing anywhere.

PyPI releases use Trusted Publishing. The publish workflow authenticates with a GitHub OIDC token and does not store a PyPI API token. Sigstore signs each distribution.

Each GitHub release also carries a CycloneDX SBOM and a signed build-provenance attestation.

This repository moved here from a previous GitHub organization; Sigstore attestations for 0.5.0 and earlier record that earlier publisher. 0.5.1 and later are published from smusali/checkowners.

Inference is deterministic git analysis; the scoring heuristics live in analyze.py and are auditable. The codebase has been built with agent assistance. Every AI-assisted change is human-reviewed, tested, and signed off.

What the tool reads, what leaves the machine, what the cache holds, how tokens are handled, and which permissions are required is in docs/PRIVACY.md.

Documentation

License

MIT

Releases

Packages

Used by

Contributors

Languages