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
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
- Discover -- find config files by glob pattern, extension, or explicit path
- Parse -- auto-detect format and parse into a normalized key-value tree
- Lint -- run 16 rules across security, structure, naming, type, environment, and deprecation categories
- 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: falseandverbose: falseautomatically - Null value fix -- replace null/empty values with safe defaults
- Protocol fix -- upgrade
http://tohttps://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 --
--schemaflag on thelintcommand
File Discovery
- Glob patterns -- find config files matching
**/*.yaml,config.*, etc. - Ignore rules -- skip
node_modules,dist,.gitby default - Recursive scanning -- scan entire directory trees automatically
Plugin System
- Custom rules -- write Python classes extending the
Rulebase 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17a8d95e144521d718d5ed1bfd50b2427065e82c16a22f295d68b50e16d3642d
|
|
| MD5 |
003ed7fb8a1d7753cb15aee27fcc7e3d
|
|
| BLAKE2b-256 |
2b277e9aec4295f6d07ca52b9b8ffca3efcdcf7c2383c44e4adc1e64339fcc8f
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6d9ce9b30bf06aa2776b96fecfc22c5e2fe1b5d9ea45b95e2e4a2ba5d2fd527
|
|
| MD5 |
3de527bbae6a5d0c0499730636f29a01
|
|
| BLAKE2b-256 |
4ec6e248f35410789d03212d470fc1b94ebc9200da7845d1e4100146f43eff58
|