Getting Started Β Β β’Β Β Getting Involved Β Β β’Β Β Getting In Touch
Rules Β Β β’Β Β Usage Β Β β’Β Β Custom Policies Β Β β’Β Β Library Β Β β’Β Β Package
A fast, opinionated linter for OpenTelemetry Collector configurations. Catches misconfigurations, security issues, and performance pitfalls before they hit production.
Built with OPA/Rego β every rule is a plain .rego file you can read, override, or extend.
The OpenTelemetry Collector is flexible, but that flexibility makes it easy to ship configs that silently drop data, leak secrets, or OOM under load. augur encodes hard-won operational knowledge into automated checks:
- No memory limiter? You'll OOM in production.
- Hardcoded API key? It'll end up in version control.
- Batch processor in the wrong position? You're leaving performance on the table.
brew install --cask starkross/tap/augurgo install github.com/starkross/augur/cmd/augur@latestdocker run --rm -v "$(pwd):/work" ghcr.io/starkross/augur:latest config.yamlDownload from GitHub Releases β available for Linux, macOS, and Windows (amd64/arm64).
augur otel-collector-config.yamlotel-collector-config.yaml
FAIL OTEL-001: memory_limiter processor is not configured. Required to prevent OOM in production.
FAIL OTEL-003: batch processor is not configured. Required for efficient data export.
WARN OTEL-011: health_check extension is not configured. Recommended for k8s liveness/readiness probes.
β 2 failure(s), 1 warning(s)
Exit code 1 on any failure. Warnings are informational by default.
See docs/RULES.md for the full list of built-in rules.
augur [flags] <config.yaml | -> [config.yaml | -]...
| Flag | Description | Default |
|---|---|---|
-o, --output |
Output format: text, json, github |
text |
-s, --strict |
Treat warnings as errors | false |
-q, --quiet |
Suppress warnings, show only failures | false |
-k, --skip |
Comma-separated rule IDs to skip | |
--no-color |
Disable colored output | false |
-p, --policy |
Additional policy directory (merged with built-in rules) |
When you pass more than one file, augur deep-merges them into a single effective config before linting β the same way the OpenTelemetry Collector combines multiple --config flags. Use - in place of a filename to read from stdin (may only appear once):
augur common.yaml client.yamlMerge rules (matching the collector's confmap):
| Value type | Behavior |
|---|---|
| Map | Deep-merged recursively. Later files add keys and override scalar leaves. |
| Scalar | Later file wins. |
| Slice | Replaced wholesale by the later file. |
To lint several standalone configs independently, invoke augur once per file.
# Merge two files
augur gateway.yaml overrides.yaml
# Strict mode β warnings become errors
augur --strict config.yaml
# JSON output for programmatic consumption
augur -o json config.yaml
# Skip specific rules
augur --skip OTEL-015,OTEL-016 config.yaml
# Use custom policies
augur --policy ./my-policies config.yaml
# Read from stdin
cat config.yaml | augur -
# Mix stdin with file arguments
augur base.yaml - overrides.yaml < patch.yamlAll built-in rules live in rules/policy/ as standard Rego files. To add your own:
- Create a directory with your custom rules:
# my-policies/main/custom.rego
package main
import future.keywords.contains
import future.keywords.if
deny contains msg if {
not input.processors.filter
msg := "CUSTOM-001: filter processor is required by our platform team."
}- Run with
--policy:
augur --policy ./my-policies config.yamlCustom policies are merged with the built-in rules β your rules run alongside all default checks.
augur can also be embedded directly in a Go program. Import the top-level package and construct a Linter:
go get github.com/starkross/augurpackage main
import (
"context"
"fmt"
"log"
"github.com/starkross/augur"
)
func main() {
linter, err := augur.New()
if err != nil {
log.Fatal(err)
}
result, err := linter.LintFile(context.Background(), "otel-collector.yaml")
if err != nil {
log.Fatal(err)
}
for _, f := range result.Findings {
fmt.Printf("%s [%s] %s\n", f.RuleID, f.Severity, f.Message)
}
}Available entry points:
| Method | Input |
|---|---|
Lint(ctx, label, map[string]any) |
Pre-parsed config map |
LintYAML(ctx, label, []byte) |
Raw YAML bytes |
LintFile(ctx, path) |
Single YAML file |
LintFiles(ctx, paths) |
Multiple files (deep-merged, same semantics as the CLI) |
Options passed to augur.New:
| Option | Purpose |
|---|---|
WithPolicyDir(path) |
Add a filesystem directory of extra .rego policies |
WithPolicyFS(fsys, root) |
Add a custom io/fs.FS policy source (works with //go:embed) |
WithoutBuiltinRules() |
Exclude the bundled OTEL-* rule set |
WithSkipRules(ids...) |
Drop findings for the given rule IDs |
WithSeverities(sev...) |
Filter findings by severity (e.g., pass SeverityDeny for fail-only) |
A Linter compiles its policies once and is safe for concurrent use β construct a single instance and share it across goroutines.
See examples/library for a runnable example.
Every release is reproducibly built and signed:
- CycloneDX SBOMs for every archive and every container image
- Cosign keyless signatures (sigstore OIDC) on
checksums.txtand on the published OCI image - SLSA Level 3 build provenance for binary artifacts
Quick verification of a release:
cosign verify ghcr.io/starkross/augur:vX.Y.Z \
--certificate-identity-regexp 'https://github.com/starkross/augur/\.github/workflows/release\.yml@refs/tags/v.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'See SECURITY.md for the full verification recipe (binaries, images, SLSA provenance, SBOMs) and the vulnerability disclosure process.

