Skip to content

Writing a custom policy

baseliner ships a built-in default policy (10 checks). When your org's baseline differs, point baseliner at your own policy file.

Scope today: a custom policy composes the built-in checks — you choose which to run, at what severity, and whether each is enabled. Custom check types (arbitrary file/content/repo-settings checks) are planned for v0.3; see the roadmap.

Using a custom policy

Set policy.base in your baseliner.yaml to a path (anything other than default is treated as a file path):

yaml
scope:
  github:
    type: org
    name: acme
policy:
  base: ./policies/acme.yaml

Verify what will actually run:

bash
baseliner policy --config baseliner.yaml   # the effective policy
baseliner checks                           # the catalog of built-in checks

Policy schema

yaml
id: acme-v1            # required, non-empty — names the policy
checks:                # required, non-empty
  - id: readme_exists  # must be a built-in check id (see `baseliner checks`)
    severity: critical # critical | high | medium | low
    enabled: true      # optional, defaults to true when omitted
    policy_info: "Every repo must have a README."   # optional rationale
    policy_url: "https://wiki.acme.example/standards/readme"  # optional link
  • id — a name for the policy (appears in baseliner policy output).
  • checks[] — the checks to run. A check not listed simply doesn't run.
  • severity — drives scoring weight (below). An unknown value is treated as weight 1.
  • enabled — set false to keep a check in the policy but skip it. Omitting the key defaults to true.
  • policy_info (optional) — a short "why this matters", shown on findings in the console and the Markdown report, and carried in JSON.
  • policy_url (optional) — a link to your governing standard; the check id links to it in the Markdown report. The built-in policy points each check at the checks reference; set your own to point at your org's standards.

The built-in checks

Run baseliner checks for the live list. As of v0.1.1:

idlayerdefault severity
readme_existsfscritical
readme_nonemptyfshigh
readme_has_headingfsmedium
license_existsfshigh
gitignore_existsfsmedium
ci_presentfshigh
codeowners_existsfslow
dependency_update_configfsmedium
default_branch_is_maingitmedium
stale_repogitlow

A check's layer is the context it needs (fs / git / platform). If that context isn't available for a repo (e.g. a GitHub repo with no git metadata), the check is skipped, not failed — and skipped checks are excluded from scoring.

How scoring works

Each repo gets a severity-weighted pass ratio:

severityweight
critical4
high3
medium2
low1
score = round( sum(weight of passing checks) / sum(weight of non-skipped checks), 4 )

Skipped checks (layer unavailable, disabled, or ignored) are excluded from both sums. A repo where every check skips scores 1.0. Use --fail-under to gate CI on this score.

Ignoring checks per deployment

enabled: false lives in the policy. To suppress a check without editing the policy — e.g. for a specific infra repo — use the config instead:

yaml
policy:
  base: ./policies/acme.yaml
  ignore:                       # skip these checks on every repo
    - stale_repo
  repo_ignores:                 # skip per repo (slug -> check ids)
    "acme/.github":
      - ci_present
      - gitignore_exists

Ignored checks are skipped (excluded from scoring), exactly like enabled: false — but scoped to the deployment, so the policy stays reusable across orgs.

Worked examples

See examples/policies/:

  • essentials.yaml — a minimal bar (README + LICENSE + CI).
  • strict.yaml — all checks, severities raised so nothing is "low".
  • relaxed.yaml — the full set with stale_repo disabled via enabled: false.

Released under the MIT License.