scanner

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2026 License: MIT Imports: 9 Imported by: 0

README

Codatus

Codatus scans every repository in a GitHub organization against a set of engineering standards and produces a Markdown compliance report.

It answers one question: does each repo in your org meet the baseline you care about?

This repository is a Go library and a CLI. Posting the report (e.g., as a GitHub Issue) is the caller's responsibility - the scanner returns structured results and Markdown, nothing more.


How it works

  1. Codatus receives a GitHub org to scan.
  2. It lists all non-archived repositories in the org.
  3. For each repo, it runs 11 rule checks (see below).
  4. It produces a single Markdown report summarizing pass/fail per repo per rule.

The CLI prints the Markdown to stdout. Callers using the library get both the structured []RepoResult and can generate the Markdown via GenerateReport.


Rules

Each rule produces a pass or fail result per repository. There are no scores, weights, or severity levels - just pass/fail.

Repo basics
1. Has repo description

Check: the GitHub repository description field is not blank.

Pass: description is set and non-empty. Fail: description is blank or not set.

2. Has .gitignore

Check: a .gitignore file exists in the repo root.

Pass: file found. Fail: file not found.

3. Has substantial README

Check: a README.md file exists in the repo root and is larger than 2048 bytes.

Pass: README.md exists and is >2048 bytes. Fail: README.md is missing, or exists but is ≤2048 bytes.

4. Has LICENSE

Check: a LICENSE or LICENSE.md file exists in the repo root.

Pass: file found. Fail: file not found.

5. Has SECURITY.md

Check: a SECURITY.md file exists in the repo root or .github/SECURITY.md.

Pass: file found in either location. Fail: file not found.

Code quality & process
6. Has CI workflow

Check: at least one file exists under .github/workflows/ with a .yml or .yaml extension.

Pass: one or more workflow files found. Fail: .github/workflows/ is missing or empty.

7. Has test directory

Check: a directory exists at the repo root level whose name indicates tests. Recognized names: test, tests, __tests__, spec, specs.

Pass: at least one matching directory found. Fail: none found.

8. Has CODEOWNERS

Check: a CODEOWNERS file exists in one of the three standard locations: root (/CODEOWNERS), docs/CODEOWNERS, or .github/CODEOWNERS.

Pass: file found in any of the three locations. Fail: file not found in any location.

Branch protection
9. Has branch protection

Check: the default branch has branch protection rules enabled (via the GitHub API's branch protection endpoint).

Pass: branch protection is enabled on the default branch. Fail: branch protection is not enabled, or the API returns 404 (no protection configured).

10. Has required reviewers

Check: the default branch's branch protection rules require at least one approving review before merging (via the GitHub API - required_pull_request_reviews.required_approving_review_count >= 1).

Pass: required reviewers is set to 1 or more. Fail: required reviewers is not configured, or set to 0, or branch protection is not enabled.

11. Requires status checks before merging

Check: the default branch's branch protection rules require at least one status check to pass before merging (via the GitHub API - required_status_checks is configured with one or more contexts).

Pass: at least one required status check is configured. Fail: required status checks are not configured, or the list of required contexts is empty, or branch protection is not enabled.


Report format

The report is a single Markdown document posted as a GitHub Issue. Structure:

# Codatus - Org Compliance Report

**Org:** {org_name}
**Scanned:** {timestamp}
**Repos scanned:** {count}

## Summary

| Rule | Passing | Failing | Pass rate |
|------|---------|---------|-----------|
| Has CI workflow | 42 | 8 | 84% |
| Has CODEOWNERS | 30 | 20 | 60% |
| ... | ... | ... | ... |

## Results by repository

### repo-name-1

| Rule | Result |
|------|--------|
| Has repo description | ✅ |
| Has .gitignore | ✅ |
| Has substantial README | ❌ |
| ... | ... |

### repo-name-2

...

Repositories are sorted alphabetically. The summary table is sorted by pass rate ascending (worst compliance first).


Scanner configuration

The scanner module accepts a Config struct with the following fields:

Field Type Required Description
Org string Yes GitHub organization name to scan
Token string Yes GitHub token (PAT or GitHub App installation token)

Scan also accepts functional options:

Option Description
WithBaseURL(url string) Override the GitHub API base URL. Defaults to the public GitHub API. Useful for testing against a mock server or targeting GitHub Enterprise.

The token must have the following permissions across the org:

  • repo (read access to repo contents and branch protection)
  • admin:org (read access to list org repos)

How these values are sourced (env vars, CLI flags, config file) is the responsibility of the caller, not the scanner module.

CLI

The codatus binary reads CODATUS_ORG and CODATUS_TOKEN from the environment, runs a scan, and prints the Markdown report to stdout. Log output (scan summary, errors) goes to stderr so stdout stays clean for piping.

CODATUS_ORG=myorg CODATUS_TOKEN=ghp_... codatus > report.md

What Codatus is not

  • Not a velocity/DORA metrics tool. It does not measure cycle time, deployment frequency, or review speed. That's a different product category.
  • Not a security scanner. It checks whether SECURITY.md exists and whether branch protection is on, but it does not scan code for vulnerabilities.
  • Not a developer portal. There is no service catalog, no scaffolding, no self-service actions. Just standards compliance.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrEmptyRepo     = errors.New("repository is empty")
	ErrTruncatedTree = errors.New("tree truncated by GitHub API")
)

Sentinel errors for per-repo scan failures.

Functions

func GenerateReport

func GenerateReport(org string, results []RepoResult) string

GenerateReport produces a Markdown compliance report from scan results.

Types

type BranchProtection

type BranchProtection struct {
	RequiredReviewers    int
	RequiredStatusChecks []string
}

BranchProtection holds the branch protection settings the scanner needs.

type Config

type Config struct {
	Org   string
	Token string
}

Config holds the configuration needed to run a scan.

type FileEntry

type FileEntry struct {
	Path string // full path relative to repo root (e.g., ".github/workflows/ci.yml")
	Size int
	Type string // "blob" (file) or "tree" (directory)
}

FileEntry represents a file or directory in a repo.

type GitHubClient

type GitHubClient interface {
	ListRepos(ctx context.Context, org string) ([]Repo, error)
	GetTree(ctx context.Context, owner, repo, branch string) ([]FileEntry, error)
	GetBranchProtection(ctx context.Context, owner, repo, branch string) (*BranchProtection, error)
	GetRulesets(ctx context.Context, owner, repo, branch string) (*BranchProtection, error)
}

GitHubClient is the interface for all GitHub API interactions. The scanner depends only on this interface, making it testable via mocks.

func NewGitHubClient

func NewGitHubClient(token string) GitHubClient

NewGitHubClient creates a GitHubClient that calls the public GitHub REST API.

type HasBranchProtection

type HasBranchProtection struct{}

HasBranchProtection checks that the default branch has protection rules enabled.

func (HasBranchProtection) Check

func (r HasBranchProtection) Check(repo Repo) bool

func (HasBranchProtection) Name

func (r HasBranchProtection) Name() string

type HasCIWorkflow

type HasCIWorkflow struct{}

HasCIWorkflow checks that at least one .yml or .yaml file exists under .github/workflows/.

func (HasCIWorkflow) Check

func (r HasCIWorkflow) Check(repo Repo) bool

func (HasCIWorkflow) Name

func (r HasCIWorkflow) Name() string

type HasCodeowners

type HasCodeowners struct{}

HasCodeowners checks that a CODEOWNERS file exists in root, docs/, or .github/.

func (HasCodeowners) Check

func (r HasCodeowners) Check(repo Repo) bool

func (HasCodeowners) Name

func (r HasCodeowners) Name() string

type HasGitignore

type HasGitignore struct{}

HasGitignore checks that a .gitignore file exists in the repo root.

func (HasGitignore) Check

func (r HasGitignore) Check(repo Repo) bool

func (HasGitignore) Name

func (r HasGitignore) Name() string

type HasLicense

type HasLicense struct{}

HasLicense checks that a LICENSE or LICENSE.md file exists in the repo root.

func (HasLicense) Check

func (r HasLicense) Check(repo Repo) bool

func (HasLicense) Name

func (r HasLicense) Name() string

type HasRepoDescription

type HasRepoDescription struct{}

HasRepoDescription checks that the repo description field is not blank.

func (HasRepoDescription) Check

func (r HasRepoDescription) Check(repo Repo) bool

func (HasRepoDescription) Name

func (r HasRepoDescription) Name() string

type HasRequiredReviewers

type HasRequiredReviewers struct{}

HasRequiredReviewers checks that at least one approving review is required.

func (HasRequiredReviewers) Check

func (r HasRequiredReviewers) Check(repo Repo) bool

func (HasRequiredReviewers) Name

func (r HasRequiredReviewers) Name() string

type HasRequiredStatusChecks

type HasRequiredStatusChecks struct{}

HasRequiredStatusChecks checks that at least one status check is required before merging.

func (HasRequiredStatusChecks) Check

func (r HasRequiredStatusChecks) Check(repo Repo) bool

func (HasRequiredStatusChecks) Name

type HasSecurityMd

type HasSecurityMd struct{}

HasSecurityMd checks that SECURITY.md exists in the repo root or .github/.

func (HasSecurityMd) Check

func (r HasSecurityMd) Check(repo Repo) bool

func (HasSecurityMd) Name

func (r HasSecurityMd) Name() string

type HasSubstantialReadme

type HasSubstantialReadme struct{}

HasSubstantialReadme checks that README.md exists and is larger than 2048 bytes.

func (HasSubstantialReadme) Check

func (r HasSubstantialReadme) Check(repo Repo) bool

func (HasSubstantialReadme) Name

func (r HasSubstantialReadme) Name() string

type HasTestDirectory

type HasTestDirectory struct{}

HasTestDirectory checks that a recognized test directory exists at the repo root.

func (HasTestDirectory) Check

func (r HasTestDirectory) Check(repo Repo) bool

func (HasTestDirectory) Name

func (r HasTestDirectory) Name() string

type Option added in v0.2.0

type Option func(*scanOptions)

Option configures optional scan behavior.

func WithBaseURL added in v0.2.0

func WithBaseURL(url string) Option

WithBaseURL sets a custom GitHub API base URL. Defaults to the public GitHub API when unset. Useful for testing against a mock server or pointing at a GitHub Enterprise instance.

type Repo

type Repo struct {
	Name             string
	Description      string
	DefaultBranch    string
	Archived         bool
	Files            []FileEntry       // all files and directories in the repo
	BranchProtection *BranchProtection // nil if no protection configured
}

Repo represents a GitHub repository with the fields the scanner needs.

type RepoResult

type RepoResult struct {
	RepoName         string
	Results          []RuleResult
	KnownSkipReason  string
	UnknownSkipError string
}

RepoResult holds all rule results for a single repository. KnownSkipReason and UnknownSkipError are mutually exclusive.

func Scan

func Scan(ctx context.Context, cfg Config, opts ...Option) ([]RepoResult, error)

Scan lists all non-archived repos in the org and evaluates every rule against each.

func (RepoResult) Skipped added in v0.2.0

func (rr RepoResult) Skipped() bool

type Rule

type Rule interface {
	Name() string
	Check(repo Repo) bool
}

Rule defines a named check that produces a pass/fail result for a repo.

func AllRules

func AllRules() []Rule

AllRules returns the ordered list of rules the scanner evaluates.

type RuleResult

type RuleResult struct {
	RuleName string
	Passed   bool
}

RuleResult holds the outcome of a single rule check for a single repo.

Directories

Path Synopsis
cmd
scanner command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL