Skip to main content

Validate, lint, and diff configuration files with schema enforcement and security checks

Project description

:gear: cfglint

Config file validator and linter for YAML, JSON, TOML, INI, and .env

GitHub Stars License Python Tests


Lint, validate, diff, and convert configuration files with 16 built-in rules and SARIF output

Quick Start | Rules | CLI | API | Architecture


Why This Exists

Configuration files are where secrets leak, debug flags get forgotten in production, and schema mismatches cause runtime crashes nobody can explain. Static analysis tools exist for code -- but config files are typically validated only at runtime, when it is already too late.

cfglint brings linting discipline to configuration files across every format your stack uses. Sixteen built-in rules catch hardcoded secrets, insecure protocols, duplicate keys, type mismatches, and deprecated fields before they reach production. SARIF output slots directly into GitHub Code Scanning, and the auto-fix engine corrects safe issues without manual edits.

  • Security-first rules -- detects hardcoded API keys, GitHub tokens, AWS credentials, JWT secrets, and weak passwords with regex patterns
  • Multi-format support -- YAML, JSON, TOML, INI, and .env files all go through the same rule engine
  • Auto-fix for safe issues -- debug flags, null values, and insecure protocols can be corrected automatically

Requirements

  • Python 3.10+
  • Dependencies: click, pyyaml, jsonschema, rich
  • Optional: tomli (for TOML on Python < 3.11)

Quick Start

pip install cfglint

Lint a Config File

# Basic lint
cfglint lint config.yaml

# Lint with JSON output
cfglint lint config.yaml --format json

# Lint with production preset
cfglint lint config.yaml --preset production

# Lint with schema validation
cfglint lint config.yaml --schema schema.json

Scan a Directory

# Auto-discover and lint all config files
cfglint scan .

# Scan with ignore patterns
cfglint scan . --ignore "node_modules/**" --ignore "dist/**"

Diff Two Configs

cfglint diff config.dev.yaml config.prod.yaml

Auto-Fix Issues

# Fix debug flags, null values, insecure protocols
cfglint fix config.yaml

# Preview fixes without writing
cfglint fix config.yaml --dry-run

Convert Formats

# YAML to JSON
cfglint convert config.yaml --to json

# JSON to TOML
cfglint convert config.json --to toml

Merge Configs

# Merge with override strategy
cfglint merge base.yaml override.yaml -o merged.yaml

# Merge with deep strategy
cfglint merge base.yaml override.yaml --strategy deep -o merged.yaml

Initialize Project

# Create .cfglintrc with CI preset
cfglint init --preset ci

How It Works

Discover        Parse           Lint            Report
──────────      ──────────      ──────────      ──────────
Glob/path   →   YAML/JSON/  →   16 rules    →   Rich/Text/
                 TOML/INI/       across 6        JSON/SARIF
                 .env            categories
  1. Discover -- find config files by glob pattern, extension, or explicit path
  2. Parse -- auto-detect format and parse into a normalized key-value tree
  3. Lint -- run 16 rules across security, structure, naming, type, environment, and deprecation categories
  4. Report -- output findings as colored terminal tables, plain text, JSON, or SARIF 2.1.0

Features

Multi-Format Parsing

  • YAML -- full YAML 1.2 support via pyyaml
  • JSON -- standard JSON with helpful parse error messages
  • TOML -- TOML v1.0 support via tomli (stdlib on 3.11+)
  • INI -- INI/cfg/conf files via configparser
  • .env -- dotenv files with comment and quote handling
  • Auto-detection -- format detected from file extension or name pattern

16 Built-in Rules

Security (4 rules)

  • SEC001 -- Detect hardcoded secrets and credentials (API keys, tokens, AWS keys, OpenAI keys, JWT secrets)
  • SEC002 -- Detect weak or default passwords
  • SEC003 -- Detect insecure protocol URLs (http://, ftp://)
  • SEC004 -- Detect debug/verbose mode left enabled

Structure (4 rules)

  • STR001 -- Detect empty or null values
  • STR002 -- Detect duplicate keys
  • STR003 -- Detect excessively deep nesting (configurable depth)
  • STR004 -- Detect overly large config files

Naming (2 rules)

  • NAM001 -- Detect inconsistent key naming conventions (snake_case vs camelCase)
  • NAM002 -- Detect reserved or dangerous key names

Schema (1 rule)

  • SCH001 -- Validate against JSON Schema

Environment (2 rules)

  • ENV001 -- Check production config for development values (localhost, debug ports)
  • ENV002 -- Detect values that should use environment variables instead of hardcoding

Type (2 rules)

  • TYP001 -- Detect likely type mismatches (strings that look like numbers/booleans)
  • TYP002 -- Validate port numbers (1-65535)

Deprecation (1 rule)

  • DEP001 -- Detect deprecated keys and non-inclusive naming (master, slave, whitelist, blacklist)

Auto-Fix Engine

  • Debug flag fix -- set debug: false and verbose: false automatically
  • Null value fix -- replace null/empty values with safe defaults
  • Protocol fix -- upgrade http:// to https:// where applicable
  • Dry-run mode -- preview fixes without writing changes
  • Selective fixing -- fix only specific rule categories

Config Diffing

  • Structural diff -- compare two config files by key structure, not text
  • Change classification -- added, removed, modified, type-changed
  • Cross-format diff -- diff YAML against JSON, TOML against INI
  • Key path reporting -- shows full dotted path to each changed key

Config Merging

  • Deep merge -- recursively merge nested structures
  • Override strategy -- second file wins on conflicts
  • Keep strategy -- first file wins on conflicts
  • Output to file -- write merged result in any supported format

Format Conversion

  • Any-to-any -- convert between YAML, JSON, TOML, INI, and ENV
  • Preserves structure -- maintains nested structure where format allows
  • CLI and API -- available from command line and programmatically

Schema Validation

  • JSON Schema -- validate any config format against a JSON Schema definition
  • Error reporting -- schema violations reported as lint findings with paths
  • CLI integration -- --schema flag on the lint command

File Discovery

  • Glob patterns -- find config files matching **/*.yaml, config.*, etc.
  • Ignore rules -- skip node_modules, dist, .git by default
  • Recursive scanning -- scan entire directory trees automatically

Plugin System

  • Custom rules -- write Python classes extending the Rule base class
  • Dynamic loading -- load plugins from Python files at runtime
  • Full API access -- plugins receive parsed data, file path, format, and raw content

Presets

  • strict -- all rules enabled, warnings treated as errors
  • production -- security + environment rules, strict severity
  • security -- security rules only
  • ci -- balanced set for CI pipelines
  • minimal -- errors only, no warnings

File Watcher

  • Continuous linting -- watch config files for changes and re-lint automatically
  • Directory watching -- monitor entire directories for config file modifications
  • Debounced -- avoids redundant runs on rapid file changes

CI/CD Integration

  • GitHub Actions generator -- generate a workflow YAML for config linting
  • SARIF output -- upload results to GitHub Code Scanning
  • Exit codes -- 0 for clean, 1 for errors (or warnings in strict mode)
  • Non-interactive -- all output formats work in headless CI environments

Statistics

  • Summary reporting -- total files, findings by severity, rules triggered
  • Per-file breakdown -- findings grouped by file path
  • Category analysis -- findings grouped by rule category

CLI Commands

# Core commands
cfglint lint <file>                    # Lint a config file
cfglint scan <dir>                     # Scan directory for config files
cfglint diff <file1> <file2>           # Diff two config files
cfglint fix <file>                     # Auto-fix safe issues
cfglint convert <file> --to <format>   # Convert between formats
cfglint merge <file1> <file2> -o <out> # Merge config files

# Utility commands
cfglint parse <file>                   # Parse and dump config structure
cfglint rules                          # List all available rules
cfglint presets                        # List available presets
cfglint init [--preset <name>]         # Initialize .cfglintrc

# Common flags
--format text|json|rich|sarif          # Output format (default: rich)
--severity error|warning|info          # Minimum severity filter
--preset strict|production|security|ci|minimal
--schema <schema.json>                 # JSON Schema to validate against
--disable SEC001,STR001                # Disable specific rules
--ignore "pattern/**"                  # Ignore file patterns
Command Description
cfglint lint <file> Lint a single config file
cfglint scan <dir> Auto-discover and lint all config files in directory
cfglint diff <a> <b> Structural diff between two config files
cfglint fix <file> Auto-fix safe issues (debug, null, protocol)
cfglint convert <file> Convert between YAML, JSON, TOML, INI, ENV
cfglint merge <a> <b> Merge two config files with strategy
cfglint parse <file> Parse and display config structure
cfglint rules List all 16 built-in rules
cfglint presets List available validation presets
cfglint init Generate .cfglintrc project config

Built-in Rules (16)

Rule ID Category Severity Description
SEC001 Security error Detect hardcoded secrets and credentials
SEC002 Security error Detect weak or default passwords
SEC003 Security warning Detect insecure protocol URLs
SEC004 Security warning Detect debug/verbose mode enabled
STR001 Structure warning Detect empty or null values
STR002 Structure error Detect duplicate keys
STR003 Structure warning Detect excessively deep nesting
STR004 Structure warning Detect overly large config files
NAM001 Naming info Detect inconsistent key naming conventions
NAM002 Naming warning Detect reserved or dangerous key names
SCH001 Schema error Validate against JSON Schema
ENV001 Environment warning Check production config for dev values
ENV002 Environment info Detect values that should use env vars
TYP001 Type info Detect likely type mismatches
TYP002 Type warning Validate port numbers (1-65535)
DEP001 Deprecation warning Detect deprecated keys and inclusive naming

Output Formats

Rich (default)

Colored terminal tables with severity highlighting, file paths, and suggestions.

Text

[ERROR] SEC001: Hardcoded API key detected at database.password (config.yaml)
[WARN]  SEC003: Insecure protocol URL at api.endpoint (config.yaml)
[INFO]  NAM001: Inconsistent naming convention at myKey (config.yaml)

JSON

{
  "file": "config.yaml",
  "format": "yaml",
  "findings": [
    {
      "rule_id": "SEC001",
      "severity": "error",
      "message": "Hardcoded API key detected",
      "key_path": "database.password",
      "auto_fixable": false
    }
  ]
}

SARIF 2.1.0

cfglint lint config.yaml --format sarif > results.sarif

Compatible with GitHub Code Scanning, VS Code SARIF Viewer, and other SARIF consumers.

Configuration

.cfglintrc (JSON)

{
  "severity": "warning",
  "disable": ["STR001"],
  "ignore": ["node_modules/**", "dist/**"],
  "enable": ["SEC001", "SEC002"],
  "preset": "production"
}

.cfglintrc.yaml

severity: warning
disable:
  - STR001
ignore:
  - "node_modules/**"
preset: ci

Configuration is loaded from the nearest .cfglintrc or .cfglintrc.yaml file, traversing parent directories up to the filesystem root.

Programmatic API

Linting

from cfglint.linter import Linter
from cfglint.models import Severity

linter = Linter(
    severity=Severity.WARNING,
    disable=["STR001"],
)
result = linter.lint_file("config.yaml")

for finding in result.findings:
    print(f"[{finding.severity.value}] {finding.rule_id}: {finding.message}")

Custom Rules (Plugin System)

from cfglint.rules.base import Rule
from cfglint.models import FileFormat, LintFinding, Severity

class MaxPortRule(Rule):
    @property
    def rule_id(self) -> str:
        return "CUSTOM001"

    @property
    def description(self) -> str:
        return "Ports must be below 10000"

    def check(self, data, file_path="", file_format=FileFormat.UNKNOWN, raw_content=""):
        findings = []
        # your validation logic here
        return findings

# Load plugin
from cfglint.plugins import load_plugin
rules = load_plugin("my_rules.py")

Config Diffing

from cfglint.differ import diff_configs

changes = diff_configs("config.dev.yaml", "config.prod.yaml")
for change in changes:
    print(f"[{change.change_type}] {change.key_path}: {change.description}")

Format Conversion

from cfglint.converter import convert_file

convert_file("config.yaml", "config.json")

Config Merging

from cfglint.merger import merge_configs

merged = merge_configs("base.yaml", "override.yaml", strategy="deep")

File Discovery

from cfglint.discovery import discover_config_files

files = discover_config_files(
    ".",
    patterns=["**/*.yaml", "**/*.json"],
    ignore=["node_modules/**"],
)

Schema Validation

from cfglint.linter import Linter

linter = Linter(schema_path="schema.json")
result = linter.lint_file("config.yaml")
# SCH001 findings included if schema violations found

CI/CD Integration

GitHub Actions

name: Config Lint
on: [push, pull_request]

jobs:
  cfglint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install cfglint
      - run: cfglint scan . --format sarif > results.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: results.sarif

Pre-commit Hook

#!/bin/sh
cfglint scan . --severity error || exit 1

Exit Codes

Code Meaning
0 No errors found
1 Errors found (or warnings in strict mode)

Architecture

src/cfglint/
  __init__.py          # Package version
  cli.py               # Click CLI (10 commands)
  linter.py            # Core linting engine
  config_loader.py     # .cfglintrc loader with directory traversal
  models.py            # Data models (Severity, FileFormat, LintFinding, LintResult)
  differ.py            # Structural config diffing
  fixer.py             # Auto-fix engine (debug, null, protocol)
  merger.py            # Config merge with deep/override/keep strategies
  converter.py         # Format conversion (any-to-any)
  discovery.py         # File discovery with glob and ignore
  watcher.py           # File watcher for continuous linting
  plugins.py           # Plugin loader for custom rules
  presets.py           # Validation presets (strict, production, security, ci, minimal)
  stats.py             # Statistics and summary reporting
  ci.py                # CI/CD integration helpers
  parsers/
    base.py            # Format detection and parser dispatch
    yaml_parser.py     # YAML parser
    json_parser.py     # JSON parser
    toml_parser.py     # TOML parser
    ini_parser.py      # INI/cfg/conf parser
    env_parser.py      # .env parser
  rules/
    base.py            # Rule abstract base class
    security.py        # SEC001-SEC004
    structure.py       # STR001-STR004
    naming.py          # NAM001-NAM002
    schema.py          # SCH001
    environment.py     # ENV001-ENV002
    types.py           # TYP001-TYP002
    deprecation.py     # DEP001
  formatters/
    text.py            # Plain text formatter
    json_fmt.py        # JSON formatter
    rich_fmt.py        # Rich terminal formatter
    sarif_fmt.py       # SARIF 2.1.0 formatter

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cfglint-1.0.0.tar.gz (41.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cfglint-1.0.0-py3-none-any.whl (47.2 kB view details)

Uploaded Python 3

File details

Details for the file cfglint-1.0.0.tar.gz.

File metadata

  • Download URL: cfglint-1.0.0.tar.gz
  • Upload date:
  • Size: 41.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cfglint-1.0.0.tar.gz
Algorithm Hash digest
SHA256 17a8d95e144521d718d5ed1bfd50b2427065e82c16a22f295d68b50e16d3642d
MD5 003ed7fb8a1d7753cb15aee27fcc7e3d
BLAKE2b-256 2b277e9aec4295f6d07ca52b9b8ffca3efcdcf7c2383c44e4adc1e64339fcc8f

See more details on using hashes here.

File details

Details for the file cfglint-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: cfglint-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 47.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cfglint-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a6d9ce9b30bf06aa2776b96fecfc22c5e2fe1b5d9ea45b95e2e4a2ba5d2fd527
MD5 3de527bbae6a5d0c0499730636f29a01
BLAKE2b-256 4ec6e248f35410789d03212d470fc1b94ebc9200da7845d1e4100146f43eff58

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page