Metadata-Version: 2.4
Name: cfglint
Version: 1.0.0
Summary: Validate, lint, and diff configuration files with schema enforcement and security checks
Author-email: JSLEEKR <93jslee@gmail.com>
License: MIT
Keywords: config,lint,validation,yaml,json,toml,security
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.1.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Requires-Dist: jsonschema>=4.17.0
Requires-Dist: rich>=13.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: pytest-mock>=3.11.0; extra == "dev"
Dynamic: license-file

# :gear: cfglint

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

[![GitHub Stars](https://img.shields.io/github/stars/JSLEEKR/cfglint?style=for-the-badge&logo=github&color=yellow)](https://github.com/JSLEEKR/cfglint/stargazers)
[![License](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)
[![Python](https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white)](https://python.org)
[![Tests](https://img.shields.io/badge/tests-411%20passing-brightgreen?style=for-the-badge)](#)

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

[Quick Start](#quick-start) | [Rules](#built-in-rules-16) | [CLI](#cli-commands) | [API](#programmatic-api) | [Architecture](#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

```bash
pip install cfglint
```

### Lint a Config File

```bash
# 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

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

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

### Diff Two Configs

```bash
cfglint diff config.dev.yaml config.prod.yaml
```

### Auto-Fix Issues

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

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

### Convert Formats

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

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

### Merge Configs

```bash
# 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

```bash
# 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

```bash
# 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

```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

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

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

## Configuration

### .cfglintrc (JSON)

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

### .cfglintrc.yaml

```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

```python
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)

```python
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

```python
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

```python
from cfglint.converter import convert_file

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

### Config Merging

```python
from cfglint.merger import merge_configs

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

### File Discovery

```python
from cfglint.discovery import discover_config_files

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

### Schema Validation

```python
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

```yaml
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

```bash
#!/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
