Self-hosted service
siderolabs/conform avatar
siderolabs/conform

Conform checks commit messages and license headers before the code ever reaches review

Policy enforcement for your pipelines.

527 stars63 forksGoMPL-2.0

At a glance

What is it?
Conform is a Go tool for enforcing policies on build pipelines, covering commit message headers, imperative mood, spell check, DCO and GPG signatures, Conventional Commits, Jira references, and license headers on source files, with a YAML policy file and a commit-msg hook. It suits a team that wants its commit conventions enforced by the tool rather than by reviewers, and it is still an alpha release.
Who is it for?
Conform fits a team whose commit conventions are already written down and wants them checked mechanically, since it covers message shape, spelling, signatures, issue references and license headers in one pass with a readable report. It does not fit a team that wants the checks to run in CI on the whole history rather than at commit time, and it is still an alpha.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What it actually enforces

Conform is a tool for enforcing policies on your build pipelines, and the policy list is the specification.

The commit policies include commit message header length, Developer Certificate of Origin, GPG signature, GPG signature identity check, Conventional Commits, imperative mood, spell check, a maximum of one commit ahead of `master`, a requirement for a commit body, and a Jira issue check.

The license header policy enforces license headers on source code files.

Two of those are worth pausing on because they are unusual. The maximum of one commit ahead of master is a workflow constraint rather than a message constraint, which means Conform is opinionated about how you branch. And the spell check with a configurable locale is the kind of check that generates more argument than the others, which is presumably why the locale is configurable and why the upstream uses the golangci misspell library rather than a full dictionary.

The GPG identity check is also distinctive. Verifying that a signature exists is standard, but checking that the signature matches a specific GitHub organisation means the tool can enforce that only members of your organisation may land commits. That is a supply chain control rather than a style preference, and it is the kind of thing the tool was probably built for at Sidero Labs, who ship Kubernetes and Talos.

Installing it three ways

There are three routes, and they cover the usual split between a workstation tool and a CI tool.

Building it locally with Go installed.

bash
go install github.com/siderolabs/conform/cmd/conform@latest

Running it as a container.

bash
docker run --rm -it -v $PWD:/src:ro,Z -w /src ghcr.io/siderolabs/conform:v0.1.0-alpha.22 enforce

The `:ro,Z` on the volume is the detail to notice. The mount is read only so the container cannot write to your working tree, and the `Z` tells SELinux to relabel the mount for the container's access. That is a careful default for a tool that reads your repository.

And installing it with aqua.

bash
aqua g -i siderolabs/conform

The third route matters more than it looks. Aqua is a declarative CLI version manager, so adding conform to it means your whole team gets the same version without anyone chasing a download URL, which is the same argument for a tool that runs in CI and on laptops.

A third-party option is downloading a release, which the README lists first.

The container image version in the README example, v0.1.0-alpha.22, is older than the latest listed release, v0.1.0-alpha.31 from 2026-01-12, so the example has drifted from the current version.

The policy file, which is where the behaviour lives

Configuration is a YAML file named `.conform.yaml`, and the README's example is the best available documentation.

yaml
policies:
  - type: commit
    spec:
      header:
        length: 89
        imperative: true
        case: lower
        invalidLastCharacters: .
        jira:
          keys:
          - PROJ
          - JIRA
      body:
        required: true
      dco: true
      gpg:
        required: false
        identity:
          gitHubOrganization: some-organization
      spellcheck:
        locale: US
      maximumOfOneCommit: true
      conventional:
        types:
          - "type"
        scopes:
          - "scope"
        descriptionLength: 72
  - type: license
    spec:
      skipPaths:
        - .git/
        - .build*/
      includeSuffixes:
        - .ext
      excludeSuffixes:
        - .exclude-ext-prefix.ext
      allowPrecedingComments: false
      header: |
        This is the contents of a license header.

Every check from the earlier list appears here as a field, and the structure separates the header rules from the body rule, so a commit can have a constrained header and no body at all.

The license policy is the more demanding half. It filters by path prefix with skipPaths and by suffix with includeSuffixes and excludeSuffixes, and excludeSuffixes supports a prefix match, which is why .exclude-ext-prefix.ext is in the example. allowPrecedingComments controls whether a comment block above the header is tolerated.

The Conventional Commits configuration lists the permitted types and scopes, so the check is a whitelist rather than a free-text pattern. That is stricter than most implementations and it is what makes the check worth running.

Running it, and the report format

The command is `conform enforce` run in the directory holding the policy file, and the output is a table.

bash
$ conform enforce
POLICY         CHECK                        STATUS        MESSAGE
commit         Header Length                PASS          Header is 43 characters
commit         Imperative Mood              PASS          Commit begins with imperative verb
commit         Header Case                  PASS          Header case is valid
commit         Header Last Character        PASS          Header last character is valid
commit         DCO                          PASS          Developer Certificate of Origin was found
commit         GPG                          PASS          GPG signature found
commit         GPG Identity                 PASS          Signed by "Someone <[email protected]>"
commit         Conventional Commit          PASS          Commit message is a valid conventional commit
commit         Spellcheck                   PASS          Commit contains 0 misspellings
commit         Number of Commits            PASS          HEAD is 0 commit(s) ahead of refs/heads/master
commit         Commit Body                  PASS          Commit body is valid
license        File Header                  PASS          All files have a valid license header

The format is the point. Every check appears as a row with a named check, a PASS or FAIL status and a message that says what was found rather than that something was wrong. When a check fails, the message tells you which specific rule was broken, so the developer does not have to guess which of a dozen rules their message violated.

The GPG Identity row is worth reading, because it shows the message includes the signing identity, so a failure would tell you who signed it, which is exactly what you need to decide whether it is a mismatch or a forgery.

The order of the rows is the order of the policy file, which means the report reads the way the policy is written.

The hooks, which is how it reaches a developer

The tool is useful in CI, but it is much more useful at commit time, and the README gives both a git hook and a pre-commit hook.

The git commit-msg hook is created by writing a small script into .git/hooks.

bash
cat <<EOF | tee .git/hooks/commit-msg
#!/bin/sh

conform enforce --commit-msg-file \$1
EOF
chmod +x .git/hooks/commit-msg

The `--commit-msg-file` flag is what makes this work: it points Conform at the file git has written with the proposed message, so the check runs against the message that is about to be committed rather than against the last commit.

The pre-commit hook is the alternative, and it is a YAML file.

yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/siderolabs/conform
    rev: main
    hooks:
      - id: conform
        stages:
          - commit-msg

The stages key is what limits the hook to the commit-msg stage, so the hook does not also run on every file change, which would be much slower given that the license policy has to walk the tree.

The pre-commit route has the advantage of being versioned with the repository, so every clone gets the hook configured, unlike the git hook above which each developer has to install by hand. The repository also ships a .pre-commit-hooks.yaml at the root, which is the file that makes the id: conform hook resolvable.

The build system behind it, and the release status

The repository is generated by kres, Sidero's build tool, and that is visible in the files.

The Makefile says it was automatically generated by kres and should not be edited, generated on 2026-06-26. The Dockerfile says the same about itself, generated on 2026-06-02, and the repository holds a .kres.yaml which is the kres configuration. There is also a lefthook.yml for git hooks on the maintainers' side and a .golangci.yml for linting.

The Dockerfile is a full CI-style multi-stage build that installs the toolchain, golangci-lint, gofumpt, goimports, gomock, deep-copy and the protobuf and gRPC generators at pinned versions. It also runs markdownlint in a Bun stage against the README and CHANGELOG with the sentences-per-line rule, which is a house style rule rather than a functional one.

The release status is the thing to weigh. The listed releases are v0.1.0-alpha.31 from 2026-01-12, v0.1.0-alpha.30 from 2024-11-28 and v0.1.0-alpha.29 from 2024-02-26. The project is still on a 0.1.0 alpha after several years, and the gap between the alpha.30 release in late 2024 and alpha.31 in early 2026 is long for an actively used tool.

The last push to the repository was on 2026-10-17, so it is still being worked on. The go.mod requires Go 1.25.0 and pins the interesting dependencies: go-git for reading the repository, keybase/go-crypto for GPG verification, google/go-github for the GitHub organisation check, jdkato/prose for the imperative mood analysis, golangci/misspell for the spell check, cobra for the command line, and yaml.v3 for the policy file.

The licence is MPL-2.0, and the repository carries a .license-header.go.txt file which is the header that the license policy expects to find in Go source files.

Where Conform is the wrong choice

Four cases argue against it.

The first is a team that wants the checks to run in CI over the history rather than at commit time. Conform is built around a single commit and a working tree, so enforcing it retroactively across a repository means scripting the commit-message checks yourself over the log, which the tool does not do for you.

The second is a repository whose commit messages are already clean but whose real problem is elsewhere. Conform checks messages and license headers. It does not check that tests pass, it does not scan for secrets, it does not verify dependencies, and it does not enforce anything about the contents of a commit beyond the message and the license header in the files it touches.

The third is the spell check and imperative mood pair, which is where teams disagree. A spell checker over commit messages catches typos, and an imperative mood check enforces a convention that many teams do not share. The README's example enables both. If your team writes commit subjects in a different style, the tool becomes something you configure around rather than something you enable.

The alternative in the same direction is a set of focused tools. A commitlint configuration handles Conventional Commits and message shape, a separate hook handles the GPG and DCO checks, a license header tool such as addlicense or a git hook handles the headers, and a spell checker such as codespell handles typos. The difference in approach is that Conform gives you one policy file and one report for all of it, which is easier to reason about and to explain to a team, while the separate tools are individually more flexible and individually better documented, and each one is a smaller dependency than a Go binary pulling in go-git, go-github and a GPG library.

Editorial conclusion

Conform fits a team whose commit conventions are already written down and wants them checked mechanically, since it covers message shape, spelling, signatures, issue references and license headers in one pass with a readable report. It does not fit a team that wants the checks to run in CI on the whole history rather than at commit time, and it is still an alpha. Install it with `go install github.com/siderolabs/conform/cmd/conform@latest`, put your rules in `.conform.yaml`, wire the `commit-msg` hook, and run `conform enforce` once locally to see the check list before you make the hook mandatory.

Frequently asked questions

What does Conform do?

It is a tool for enforcing policies on your build pipelines. The commit policies cover header length, Developer Certificate of Origin, GPG signature and identity, Conventional Commits, imperative mood, spell check, a maximum of one commit ahead of master, a required commit body and a Jira issue check, and there is a license header policy for source files.

How do I install Conform?

With `go install github.com/siderolabs/conform/cmd/conform@latest` if you have Go installed, as a container with `docker run --rm -it -v $PWD:/src:ro,Z -w /src ghcr.io/siderolabs/conform:v0.1.0-alpha.22 enforce`, or with aqua using `aqua g -i siderolabs/conform`. You can also download a release.

How is Conform configured?

With a `.conform.yaml` file in the repository root, holding a list of policies each with a type and a spec. The commit policy configures header rules such as length, imperative mood, case and Jira keys, the body requirement, dco, gpg identity, spellcheck locale, maximumOfOneCommit and the permitted conventional types and scopes, and the license policy configures skipPaths, includeSuffixes, excludeSuffixes and the expected header text.

How do I run Conform as a git hook?

Write a commit-msg hook that calls `conform enforce --commit-msg-file $1`, which checks the message git is about to commit rather than the previous commit. The README also provides a pre-commit hook configuration using the id: conform hook with stages set to commit-msg.

Is Conform ready for production use?

It is still an alpha. The listed releases are v0.1.0-alpha.31 from 2026-01-12, v0.1.0-alpha.30 from 2024-11-28 and v0.1.0-alpha.29 from 2024-02-26, although the repository was pushed to on 2026-10-17.

Official sources

  1. Issues
  2. License: MPL-2.0
  3. README
  4. Releases
  5. siderolabs/conform on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/siderolabs-conform.svg)](https://hysenlabs.com/projects/siderolabs-conform)

Was this useful?