scanner

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 6, 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 posted as a GitHub Issue.

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

No dashboard. No database. No setup beyond installing the GitHub App. Scan, report, done.


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.
  5. The report is posted as a GitHub Issue in a designated repository.

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 ScanConfig 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)
ReportRepo string Yes Repository name where the compliance issue is created (org is taken from Org)

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.


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

This section is empty.

Functions

func GenerateReport

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

GenerateReport produces a Markdown compliance report from scan results.

func Run

func Run(ctx context.Context, cfg Config) error

Run is the high-level entry point. It constructs a client, scans the org, generates a Markdown report, and posts it as a GitHub Issue.

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
	ReportRepo 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)
	CreateIssue(ctx context.Context, owner, repo, title, body string) 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 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 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
}

RepoResult holds all rule results for a single repository.

func Scan

func Scan(ctx context.Context, client GitHubClient, org string) ([]RepoResult, error)

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

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