cfglint 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cfglint-1.0.0/LICENSE +21 -0
- cfglint-1.0.0/PKG-INFO +561 -0
- cfglint-1.0.0/README.md +531 -0
- cfglint-1.0.0/pyproject.toml +59 -0
- cfglint-1.0.0/setup.cfg +4 -0
- cfglint-1.0.0/src/cfglint/__init__.py +3 -0
- cfglint-1.0.0/src/cfglint/ci.py +106 -0
- cfglint-1.0.0/src/cfglint/cli.py +363 -0
- cfglint-1.0.0/src/cfglint/config_loader.py +75 -0
- cfglint-1.0.0/src/cfglint/converter.py +68 -0
- cfglint-1.0.0/src/cfglint/differ.py +81 -0
- cfglint-1.0.0/src/cfglint/discovery.py +86 -0
- cfglint-1.0.0/src/cfglint/fixer.py +128 -0
- cfglint-1.0.0/src/cfglint/formatters/__init__.py +7 -0
- cfglint-1.0.0/src/cfglint/formatters/json_fmt.py +29 -0
- cfglint-1.0.0/src/cfglint/formatters/rich_fmt.py +121 -0
- cfglint-1.0.0/src/cfglint/formatters/sarif_fmt.py +105 -0
- cfglint-1.0.0/src/cfglint/formatters/text.py +81 -0
- cfglint-1.0.0/src/cfglint/linter.py +125 -0
- cfglint-1.0.0/src/cfglint/merger.py +61 -0
- cfglint-1.0.0/src/cfglint/models.py +161 -0
- cfglint-1.0.0/src/cfglint/parsers/__init__.py +19 -0
- cfglint-1.0.0/src/cfglint/parsers/base.py +83 -0
- cfglint-1.0.0/src/cfglint/parsers/env_parser.py +58 -0
- cfglint-1.0.0/src/cfglint/parsers/ini_parser.py +49 -0
- cfglint-1.0.0/src/cfglint/parsers/json_parser.py +21 -0
- cfglint-1.0.0/src/cfglint/parsers/toml_parser.py +46 -0
- cfglint-1.0.0/src/cfglint/parsers/yaml_parser.py +24 -0
- cfglint-1.0.0/src/cfglint/plugins.py +99 -0
- cfglint-1.0.0/src/cfglint/presets.py +77 -0
- cfglint-1.0.0/src/cfglint/rules/__init__.py +36 -0
- cfglint-1.0.0/src/cfglint/rules/base.py +111 -0
- cfglint-1.0.0/src/cfglint/rules/deprecation.py +85 -0
- cfglint-1.0.0/src/cfglint/rules/environment.py +141 -0
- cfglint-1.0.0/src/cfglint/rules/naming.py +146 -0
- cfglint-1.0.0/src/cfglint/rules/schema.py +69 -0
- cfglint-1.0.0/src/cfglint/rules/security.py +259 -0
- cfglint-1.0.0/src/cfglint/rules/structure.py +254 -0
- cfglint-1.0.0/src/cfglint/rules/types.py +132 -0
- cfglint-1.0.0/src/cfglint/stats.py +122 -0
- cfglint-1.0.0/src/cfglint/watcher.py +73 -0
- cfglint-1.0.0/src/cfglint.egg-info/PKG-INFO +561 -0
- cfglint-1.0.0/src/cfglint.egg-info/SOURCES.txt +45 -0
- cfglint-1.0.0/src/cfglint.egg-info/dependency_links.txt +1 -0
- cfglint-1.0.0/src/cfglint.egg-info/entry_points.txt +2 -0
- cfglint-1.0.0/src/cfglint.egg-info/requires.txt +12 -0
- cfglint-1.0.0/src/cfglint.egg-info/top_level.txt +1 -0
cfglint-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JSLEEKR
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cfglint-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cfglint
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Validate, lint, and diff configuration files with schema enforcement and security checks
|
|
5
|
+
Author-email: JSLEEKR <93jslee@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: config,lint,validation,yaml,json,toml,security
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: click>=8.1.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0
|
|
22
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
23
|
+
Requires-Dist: jsonschema>=4.17.0
|
|
24
|
+
Requires-Dist: rich>=13.0.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-mock>=3.11.0; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
|
|
33
|
+
# :gear: cfglint
|
|
34
|
+
|
|
35
|
+
### Config file validator and linter for YAML, JSON, TOML, INI, and .env
|
|
36
|
+
|
|
37
|
+
[](https://github.com/JSLEEKR/cfglint/stargazers)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
[](https://python.org)
|
|
40
|
+
[](#)
|
|
41
|
+
|
|
42
|
+
<br/>
|
|
43
|
+
|
|
44
|
+
**Lint, validate, diff, and convert configuration files with 16 built-in rules and SARIF output**
|
|
45
|
+
|
|
46
|
+
[Quick Start](#quick-start) | [Rules](#built-in-rules-16) | [CLI](#cli-commands) | [API](#programmatic-api) | [Architecture](#architecture)
|
|
47
|
+
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Why This Exists
|
|
53
|
+
|
|
54
|
+
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.
|
|
55
|
+
|
|
56
|
+
`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.
|
|
57
|
+
|
|
58
|
+
- **Security-first rules** -- detects hardcoded API keys, GitHub tokens, AWS credentials, JWT secrets, and weak passwords with regex patterns
|
|
59
|
+
- **Multi-format support** -- YAML, JSON, TOML, INI, and .env files all go through the same rule engine
|
|
60
|
+
- **Auto-fix for safe issues** -- debug flags, null values, and insecure protocols can be corrected automatically
|
|
61
|
+
|
|
62
|
+
## Requirements
|
|
63
|
+
|
|
64
|
+
- Python 3.10+
|
|
65
|
+
- Dependencies: `click`, `pyyaml`, `jsonschema`, `rich`
|
|
66
|
+
- Optional: `tomli` (for TOML on Python < 3.11)
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install cfglint
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Lint a Config File
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Basic lint
|
|
78
|
+
cfglint lint config.yaml
|
|
79
|
+
|
|
80
|
+
# Lint with JSON output
|
|
81
|
+
cfglint lint config.yaml --format json
|
|
82
|
+
|
|
83
|
+
# Lint with production preset
|
|
84
|
+
cfglint lint config.yaml --preset production
|
|
85
|
+
|
|
86
|
+
# Lint with schema validation
|
|
87
|
+
cfglint lint config.yaml --schema schema.json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Scan a Directory
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Auto-discover and lint all config files
|
|
94
|
+
cfglint scan .
|
|
95
|
+
|
|
96
|
+
# Scan with ignore patterns
|
|
97
|
+
cfglint scan . --ignore "node_modules/**" --ignore "dist/**"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Diff Two Configs
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cfglint diff config.dev.yaml config.prod.yaml
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Auto-Fix Issues
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Fix debug flags, null values, insecure protocols
|
|
110
|
+
cfglint fix config.yaml
|
|
111
|
+
|
|
112
|
+
# Preview fixes without writing
|
|
113
|
+
cfglint fix config.yaml --dry-run
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Convert Formats
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# YAML to JSON
|
|
120
|
+
cfglint convert config.yaml --to json
|
|
121
|
+
|
|
122
|
+
# JSON to TOML
|
|
123
|
+
cfglint convert config.json --to toml
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Merge Configs
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Merge with override strategy
|
|
130
|
+
cfglint merge base.yaml override.yaml -o merged.yaml
|
|
131
|
+
|
|
132
|
+
# Merge with deep strategy
|
|
133
|
+
cfglint merge base.yaml override.yaml --strategy deep -o merged.yaml
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Initialize Project
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Create .cfglintrc with CI preset
|
|
140
|
+
cfglint init --preset ci
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## How It Works
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Discover Parse Lint Report
|
|
147
|
+
────────── ────────── ────────── ──────────
|
|
148
|
+
Glob/path → YAML/JSON/ → 16 rules → Rich/Text/
|
|
149
|
+
TOML/INI/ across 6 JSON/SARIF
|
|
150
|
+
.env categories
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
1. **Discover** -- find config files by glob pattern, extension, or explicit path
|
|
154
|
+
2. **Parse** -- auto-detect format and parse into a normalized key-value tree
|
|
155
|
+
3. **Lint** -- run 16 rules across security, structure, naming, type, environment, and deprecation categories
|
|
156
|
+
4. **Report** -- output findings as colored terminal tables, plain text, JSON, or SARIF 2.1.0
|
|
157
|
+
|
|
158
|
+
## Features
|
|
159
|
+
|
|
160
|
+
### Multi-Format Parsing
|
|
161
|
+
- **YAML** -- full YAML 1.2 support via `pyyaml`
|
|
162
|
+
- **JSON** -- standard JSON with helpful parse error messages
|
|
163
|
+
- **TOML** -- TOML v1.0 support via `tomli` (stdlib on 3.11+)
|
|
164
|
+
- **INI** -- INI/cfg/conf files via `configparser`
|
|
165
|
+
- **.env** -- dotenv files with comment and quote handling
|
|
166
|
+
- **Auto-detection** -- format detected from file extension or name pattern
|
|
167
|
+
|
|
168
|
+
### 16 Built-in Rules
|
|
169
|
+
|
|
170
|
+
#### Security (4 rules)
|
|
171
|
+
- **SEC001** -- Detect hardcoded secrets and credentials (API keys, tokens, AWS keys, OpenAI keys, JWT secrets)
|
|
172
|
+
- **SEC002** -- Detect weak or default passwords
|
|
173
|
+
- **SEC003** -- Detect insecure protocol URLs (http://, ftp://)
|
|
174
|
+
- **SEC004** -- Detect debug/verbose mode left enabled
|
|
175
|
+
|
|
176
|
+
#### Structure (4 rules)
|
|
177
|
+
- **STR001** -- Detect empty or null values
|
|
178
|
+
- **STR002** -- Detect duplicate keys
|
|
179
|
+
- **STR003** -- Detect excessively deep nesting (configurable depth)
|
|
180
|
+
- **STR004** -- Detect overly large config files
|
|
181
|
+
|
|
182
|
+
#### Naming (2 rules)
|
|
183
|
+
- **NAM001** -- Detect inconsistent key naming conventions (snake_case vs camelCase)
|
|
184
|
+
- **NAM002** -- Detect reserved or dangerous key names
|
|
185
|
+
|
|
186
|
+
#### Schema (1 rule)
|
|
187
|
+
- **SCH001** -- Validate against JSON Schema
|
|
188
|
+
|
|
189
|
+
#### Environment (2 rules)
|
|
190
|
+
- **ENV001** -- Check production config for development values (localhost, debug ports)
|
|
191
|
+
- **ENV002** -- Detect values that should use environment variables instead of hardcoding
|
|
192
|
+
|
|
193
|
+
#### Type (2 rules)
|
|
194
|
+
- **TYP001** -- Detect likely type mismatches (strings that look like numbers/booleans)
|
|
195
|
+
- **TYP002** -- Validate port numbers (1-65535)
|
|
196
|
+
|
|
197
|
+
#### Deprecation (1 rule)
|
|
198
|
+
- **DEP001** -- Detect deprecated keys and non-inclusive naming (master, slave, whitelist, blacklist)
|
|
199
|
+
|
|
200
|
+
### Auto-Fix Engine
|
|
201
|
+
- **Debug flag fix** -- set `debug: false` and `verbose: false` automatically
|
|
202
|
+
- **Null value fix** -- replace null/empty values with safe defaults
|
|
203
|
+
- **Protocol fix** -- upgrade `http://` to `https://` where applicable
|
|
204
|
+
- **Dry-run mode** -- preview fixes without writing changes
|
|
205
|
+
- **Selective fixing** -- fix only specific rule categories
|
|
206
|
+
|
|
207
|
+
### Config Diffing
|
|
208
|
+
- **Structural diff** -- compare two config files by key structure, not text
|
|
209
|
+
- **Change classification** -- added, removed, modified, type-changed
|
|
210
|
+
- **Cross-format diff** -- diff YAML against JSON, TOML against INI
|
|
211
|
+
- **Key path reporting** -- shows full dotted path to each changed key
|
|
212
|
+
|
|
213
|
+
### Config Merging
|
|
214
|
+
- **Deep merge** -- recursively merge nested structures
|
|
215
|
+
- **Override strategy** -- second file wins on conflicts
|
|
216
|
+
- **Keep strategy** -- first file wins on conflicts
|
|
217
|
+
- **Output to file** -- write merged result in any supported format
|
|
218
|
+
|
|
219
|
+
### Format Conversion
|
|
220
|
+
- **Any-to-any** -- convert between YAML, JSON, TOML, INI, and ENV
|
|
221
|
+
- **Preserves structure** -- maintains nested structure where format allows
|
|
222
|
+
- **CLI and API** -- available from command line and programmatically
|
|
223
|
+
|
|
224
|
+
### Schema Validation
|
|
225
|
+
- **JSON Schema** -- validate any config format against a JSON Schema definition
|
|
226
|
+
- **Error reporting** -- schema violations reported as lint findings with paths
|
|
227
|
+
- **CLI integration** -- `--schema` flag on the `lint` command
|
|
228
|
+
|
|
229
|
+
### File Discovery
|
|
230
|
+
- **Glob patterns** -- find config files matching `**/*.yaml`, `config.*`, etc.
|
|
231
|
+
- **Ignore rules** -- skip `node_modules`, `dist`, `.git` by default
|
|
232
|
+
- **Recursive scanning** -- scan entire directory trees automatically
|
|
233
|
+
|
|
234
|
+
### Plugin System
|
|
235
|
+
- **Custom rules** -- write Python classes extending the `Rule` base class
|
|
236
|
+
- **Dynamic loading** -- load plugins from Python files at runtime
|
|
237
|
+
- **Full API access** -- plugins receive parsed data, file path, format, and raw content
|
|
238
|
+
|
|
239
|
+
### Presets
|
|
240
|
+
- **strict** -- all rules enabled, warnings treated as errors
|
|
241
|
+
- **production** -- security + environment rules, strict severity
|
|
242
|
+
- **security** -- security rules only
|
|
243
|
+
- **ci** -- balanced set for CI pipelines
|
|
244
|
+
- **minimal** -- errors only, no warnings
|
|
245
|
+
|
|
246
|
+
### File Watcher
|
|
247
|
+
- **Continuous linting** -- watch config files for changes and re-lint automatically
|
|
248
|
+
- **Directory watching** -- monitor entire directories for config file modifications
|
|
249
|
+
- **Debounced** -- avoids redundant runs on rapid file changes
|
|
250
|
+
|
|
251
|
+
### CI/CD Integration
|
|
252
|
+
- **GitHub Actions generator** -- generate a workflow YAML for config linting
|
|
253
|
+
- **SARIF output** -- upload results to GitHub Code Scanning
|
|
254
|
+
- **Exit codes** -- 0 for clean, 1 for errors (or warnings in strict mode)
|
|
255
|
+
- **Non-interactive** -- all output formats work in headless CI environments
|
|
256
|
+
|
|
257
|
+
### Statistics
|
|
258
|
+
- **Summary reporting** -- total files, findings by severity, rules triggered
|
|
259
|
+
- **Per-file breakdown** -- findings grouped by file path
|
|
260
|
+
- **Category analysis** -- findings grouped by rule category
|
|
261
|
+
|
|
262
|
+
## CLI Commands
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# Core commands
|
|
266
|
+
cfglint lint <file> # Lint a config file
|
|
267
|
+
cfglint scan <dir> # Scan directory for config files
|
|
268
|
+
cfglint diff <file1> <file2> # Diff two config files
|
|
269
|
+
cfglint fix <file> # Auto-fix safe issues
|
|
270
|
+
cfglint convert <file> --to <format> # Convert between formats
|
|
271
|
+
cfglint merge <file1> <file2> -o <out> # Merge config files
|
|
272
|
+
|
|
273
|
+
# Utility commands
|
|
274
|
+
cfglint parse <file> # Parse and dump config structure
|
|
275
|
+
cfglint rules # List all available rules
|
|
276
|
+
cfglint presets # List available presets
|
|
277
|
+
cfglint init [--preset <name>] # Initialize .cfglintrc
|
|
278
|
+
|
|
279
|
+
# Common flags
|
|
280
|
+
--format text|json|rich|sarif # Output format (default: rich)
|
|
281
|
+
--severity error|warning|info # Minimum severity filter
|
|
282
|
+
--preset strict|production|security|ci|minimal
|
|
283
|
+
--schema <schema.json> # JSON Schema to validate against
|
|
284
|
+
--disable SEC001,STR001 # Disable specific rules
|
|
285
|
+
--ignore "pattern/**" # Ignore file patterns
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
| Command | Description |
|
|
289
|
+
|---------|-------------|
|
|
290
|
+
| `cfglint lint <file>` | Lint a single config file |
|
|
291
|
+
| `cfglint scan <dir>` | Auto-discover and lint all config files in directory |
|
|
292
|
+
| `cfglint diff <a> <b>` | Structural diff between two config files |
|
|
293
|
+
| `cfglint fix <file>` | Auto-fix safe issues (debug, null, protocol) |
|
|
294
|
+
| `cfglint convert <file>` | Convert between YAML, JSON, TOML, INI, ENV |
|
|
295
|
+
| `cfglint merge <a> <b>` | Merge two config files with strategy |
|
|
296
|
+
| `cfglint parse <file>` | Parse and display config structure |
|
|
297
|
+
| `cfglint rules` | List all 16 built-in rules |
|
|
298
|
+
| `cfglint presets` | List available validation presets |
|
|
299
|
+
| `cfglint init` | Generate `.cfglintrc` project config |
|
|
300
|
+
|
|
301
|
+
## Built-in Rules (16)
|
|
302
|
+
|
|
303
|
+
| Rule ID | Category | Severity | Description |
|
|
304
|
+
|---------|----------|----------|-------------|
|
|
305
|
+
| SEC001 | Security | error | Detect hardcoded secrets and credentials |
|
|
306
|
+
| SEC002 | Security | error | Detect weak or default passwords |
|
|
307
|
+
| SEC003 | Security | warning | Detect insecure protocol URLs |
|
|
308
|
+
| SEC004 | Security | warning | Detect debug/verbose mode enabled |
|
|
309
|
+
| STR001 | Structure | warning | Detect empty or null values |
|
|
310
|
+
| STR002 | Structure | error | Detect duplicate keys |
|
|
311
|
+
| STR003 | Structure | warning | Detect excessively deep nesting |
|
|
312
|
+
| STR004 | Structure | warning | Detect overly large config files |
|
|
313
|
+
| NAM001 | Naming | info | Detect inconsistent key naming conventions |
|
|
314
|
+
| NAM002 | Naming | warning | Detect reserved or dangerous key names |
|
|
315
|
+
| SCH001 | Schema | error | Validate against JSON Schema |
|
|
316
|
+
| ENV001 | Environment | warning | Check production config for dev values |
|
|
317
|
+
| ENV002 | Environment | info | Detect values that should use env vars |
|
|
318
|
+
| TYP001 | Type | info | Detect likely type mismatches |
|
|
319
|
+
| TYP002 | Type | warning | Validate port numbers (1-65535) |
|
|
320
|
+
| DEP001 | Deprecation | warning | Detect deprecated keys and inclusive naming |
|
|
321
|
+
|
|
322
|
+
## Output Formats
|
|
323
|
+
|
|
324
|
+
### Rich (default)
|
|
325
|
+
|
|
326
|
+
Colored terminal tables with severity highlighting, file paths, and suggestions.
|
|
327
|
+
|
|
328
|
+
### Text
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
[ERROR] SEC001: Hardcoded API key detected at database.password (config.yaml)
|
|
332
|
+
[WARN] SEC003: Insecure protocol URL at api.endpoint (config.yaml)
|
|
333
|
+
[INFO] NAM001: Inconsistent naming convention at myKey (config.yaml)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### JSON
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"file": "config.yaml",
|
|
341
|
+
"format": "yaml",
|
|
342
|
+
"findings": [
|
|
343
|
+
{
|
|
344
|
+
"rule_id": "SEC001",
|
|
345
|
+
"severity": "error",
|
|
346
|
+
"message": "Hardcoded API key detected",
|
|
347
|
+
"key_path": "database.password",
|
|
348
|
+
"auto_fixable": false
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### SARIF 2.1.0
|
|
355
|
+
|
|
356
|
+
```bash
|
|
357
|
+
cfglint lint config.yaml --format sarif > results.sarif
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Compatible with GitHub Code Scanning, VS Code SARIF Viewer, and other SARIF consumers.
|
|
361
|
+
|
|
362
|
+
## Configuration
|
|
363
|
+
|
|
364
|
+
### .cfglintrc (JSON)
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"severity": "warning",
|
|
369
|
+
"disable": ["STR001"],
|
|
370
|
+
"ignore": ["node_modules/**", "dist/**"],
|
|
371
|
+
"enable": ["SEC001", "SEC002"],
|
|
372
|
+
"preset": "production"
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### .cfglintrc.yaml
|
|
377
|
+
|
|
378
|
+
```yaml
|
|
379
|
+
severity: warning
|
|
380
|
+
disable:
|
|
381
|
+
- STR001
|
|
382
|
+
ignore:
|
|
383
|
+
- "node_modules/**"
|
|
384
|
+
preset: ci
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Configuration is loaded from the nearest `.cfglintrc` or `.cfglintrc.yaml` file, traversing parent directories up to the filesystem root.
|
|
388
|
+
|
|
389
|
+
## Programmatic API
|
|
390
|
+
|
|
391
|
+
### Linting
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
from cfglint.linter import Linter
|
|
395
|
+
from cfglint.models import Severity
|
|
396
|
+
|
|
397
|
+
linter = Linter(
|
|
398
|
+
severity=Severity.WARNING,
|
|
399
|
+
disable=["STR001"],
|
|
400
|
+
)
|
|
401
|
+
result = linter.lint_file("config.yaml")
|
|
402
|
+
|
|
403
|
+
for finding in result.findings:
|
|
404
|
+
print(f"[{finding.severity.value}] {finding.rule_id}: {finding.message}")
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Custom Rules (Plugin System)
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
from cfglint.rules.base import Rule
|
|
411
|
+
from cfglint.models import FileFormat, LintFinding, Severity
|
|
412
|
+
|
|
413
|
+
class MaxPortRule(Rule):
|
|
414
|
+
@property
|
|
415
|
+
def rule_id(self) -> str:
|
|
416
|
+
return "CUSTOM001"
|
|
417
|
+
|
|
418
|
+
@property
|
|
419
|
+
def description(self) -> str:
|
|
420
|
+
return "Ports must be below 10000"
|
|
421
|
+
|
|
422
|
+
def check(self, data, file_path="", file_format=FileFormat.UNKNOWN, raw_content=""):
|
|
423
|
+
findings = []
|
|
424
|
+
# your validation logic here
|
|
425
|
+
return findings
|
|
426
|
+
|
|
427
|
+
# Load plugin
|
|
428
|
+
from cfglint.plugins import load_plugin
|
|
429
|
+
rules = load_plugin("my_rules.py")
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Config Diffing
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
from cfglint.differ import diff_configs
|
|
436
|
+
|
|
437
|
+
changes = diff_configs("config.dev.yaml", "config.prod.yaml")
|
|
438
|
+
for change in changes:
|
|
439
|
+
print(f"[{change.change_type}] {change.key_path}: {change.description}")
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Format Conversion
|
|
443
|
+
|
|
444
|
+
```python
|
|
445
|
+
from cfglint.converter import convert_file
|
|
446
|
+
|
|
447
|
+
convert_file("config.yaml", "config.json")
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Config Merging
|
|
451
|
+
|
|
452
|
+
```python
|
|
453
|
+
from cfglint.merger import merge_configs
|
|
454
|
+
|
|
455
|
+
merged = merge_configs("base.yaml", "override.yaml", strategy="deep")
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### File Discovery
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
from cfglint.discovery import discover_config_files
|
|
462
|
+
|
|
463
|
+
files = discover_config_files(
|
|
464
|
+
".",
|
|
465
|
+
patterns=["**/*.yaml", "**/*.json"],
|
|
466
|
+
ignore=["node_modules/**"],
|
|
467
|
+
)
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Schema Validation
|
|
471
|
+
|
|
472
|
+
```python
|
|
473
|
+
from cfglint.linter import Linter
|
|
474
|
+
|
|
475
|
+
linter = Linter(schema_path="schema.json")
|
|
476
|
+
result = linter.lint_file("config.yaml")
|
|
477
|
+
# SCH001 findings included if schema violations found
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
## CI/CD Integration
|
|
481
|
+
|
|
482
|
+
### GitHub Actions
|
|
483
|
+
|
|
484
|
+
```yaml
|
|
485
|
+
name: Config Lint
|
|
486
|
+
on: [push, pull_request]
|
|
487
|
+
|
|
488
|
+
jobs:
|
|
489
|
+
cfglint:
|
|
490
|
+
runs-on: ubuntu-latest
|
|
491
|
+
steps:
|
|
492
|
+
- uses: actions/checkout@v4
|
|
493
|
+
- uses: actions/setup-python@v5
|
|
494
|
+
with:
|
|
495
|
+
python-version: "3.12"
|
|
496
|
+
- run: pip install cfglint
|
|
497
|
+
- run: cfglint scan . --format sarif > results.sarif
|
|
498
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
499
|
+
with:
|
|
500
|
+
sarif_file: results.sarif
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Pre-commit Hook
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
#!/bin/sh
|
|
507
|
+
cfglint scan . --severity error || exit 1
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Exit Codes
|
|
511
|
+
|
|
512
|
+
| Code | Meaning |
|
|
513
|
+
|------|---------|
|
|
514
|
+
| 0 | No errors found |
|
|
515
|
+
| 1 | Errors found (or warnings in strict mode) |
|
|
516
|
+
|
|
517
|
+
## Architecture
|
|
518
|
+
|
|
519
|
+
```
|
|
520
|
+
src/cfglint/
|
|
521
|
+
__init__.py # Package version
|
|
522
|
+
cli.py # Click CLI (10 commands)
|
|
523
|
+
linter.py # Core linting engine
|
|
524
|
+
config_loader.py # .cfglintrc loader with directory traversal
|
|
525
|
+
models.py # Data models (Severity, FileFormat, LintFinding, LintResult)
|
|
526
|
+
differ.py # Structural config diffing
|
|
527
|
+
fixer.py # Auto-fix engine (debug, null, protocol)
|
|
528
|
+
merger.py # Config merge with deep/override/keep strategies
|
|
529
|
+
converter.py # Format conversion (any-to-any)
|
|
530
|
+
discovery.py # File discovery with glob and ignore
|
|
531
|
+
watcher.py # File watcher for continuous linting
|
|
532
|
+
plugins.py # Plugin loader for custom rules
|
|
533
|
+
presets.py # Validation presets (strict, production, security, ci, minimal)
|
|
534
|
+
stats.py # Statistics and summary reporting
|
|
535
|
+
ci.py # CI/CD integration helpers
|
|
536
|
+
parsers/
|
|
537
|
+
base.py # Format detection and parser dispatch
|
|
538
|
+
yaml_parser.py # YAML parser
|
|
539
|
+
json_parser.py # JSON parser
|
|
540
|
+
toml_parser.py # TOML parser
|
|
541
|
+
ini_parser.py # INI/cfg/conf parser
|
|
542
|
+
env_parser.py # .env parser
|
|
543
|
+
rules/
|
|
544
|
+
base.py # Rule abstract base class
|
|
545
|
+
security.py # SEC001-SEC004
|
|
546
|
+
structure.py # STR001-STR004
|
|
547
|
+
naming.py # NAM001-NAM002
|
|
548
|
+
schema.py # SCH001
|
|
549
|
+
environment.py # ENV001-ENV002
|
|
550
|
+
types.py # TYP001-TYP002
|
|
551
|
+
deprecation.py # DEP001
|
|
552
|
+
formatters/
|
|
553
|
+
text.py # Plain text formatter
|
|
554
|
+
json_fmt.py # JSON formatter
|
|
555
|
+
rich_fmt.py # Rich terminal formatter
|
|
556
|
+
sarif_fmt.py # SARIF 2.1.0 formatter
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## License
|
|
560
|
+
|
|
561
|
+
MIT
|