conflint 0.1.1__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.
- conflint-0.1.1/.gitignore +55 -0
- conflint-0.1.1/CHANGELOG.md +24 -0
- conflint-0.1.1/LICENSE +21 -0
- conflint-0.1.1/PKG-INFO +255 -0
- conflint-0.1.1/README.md +188 -0
- conflint-0.1.1/docs/configuration.md +64 -0
- conflint-0.1.1/docs/index.md +89 -0
- conflint-0.1.1/docs/plugins.md +104 -0
- conflint-0.1.1/docs/reference.md +22 -0
- conflint-0.1.1/docs/reporters.md +58 -0
- conflint-0.1.1/docs/rules.md +67 -0
- conflint-0.1.1/docs/usage.md +76 -0
- conflint-0.1.1/pyproject.toml +143 -0
- conflint-0.1.1/src/conflint/__about__.py +7 -0
- conflint-0.1.1/src/conflint/__init__.py +32 -0
- conflint-0.1.1/src/conflint/__main__.py +8 -0
- conflint-0.1.1/src/conflint/_version.py +24 -0
- conflint-0.1.1/src/conflint/cli.py +374 -0
- conflint-0.1.1/src/conflint/config.py +268 -0
- conflint-0.1.1/src/conflint/discovery.py +167 -0
- conflint-0.1.1/src/conflint/engine.py +182 -0
- conflint-0.1.1/src/conflint/exceptions.py +60 -0
- conflint-0.1.1/src/conflint/models.py +302 -0
- conflint-0.1.1/src/conflint/registry.py +163 -0
- conflint-0.1.1/src/conflint/reporters/__init__.py +50 -0
- conflint-0.1.1/src/conflint/reporters/base.py +31 -0
- conflint-0.1.1/src/conflint/reporters/github.py +45 -0
- conflint-0.1.1/src/conflint/reporters/json.py +37 -0
- conflint-0.1.1/src/conflint/reporters/junit.py +70 -0
- conflint-0.1.1/src/conflint/reporters/sarif.py +103 -0
- conflint-0.1.1/src/conflint/reporters/text.py +102 -0
- conflint-0.1.1/src/conflint/rules/__init__.py +44 -0
- conflint-0.1.1/src/conflint/rules/base.py +61 -0
- conflint-0.1.1/src/conflint/rules/drift.py +38 -0
- conflint-0.1.1/src/conflint/rules/duplicate.py +70 -0
- conflint-0.1.1/src/conflint/rules/empty.py +38 -0
- conflint-0.1.1/src/conflint/rules/missing.py +38 -0
- conflint-0.1.1/src/conflint/rules/secrets.py +39 -0
- conflint-0.1.1/src/conflint/rules/typo.py +39 -0
- conflint-0.1.1/src/conflint/rules/undocumented.py +48 -0
- conflint-0.1.1/src/conflint/rules/unused.py +40 -0
- conflint-0.1.1/src/conflint/rules/weak.py +75 -0
- conflint-0.1.1/src/conflint/scanners/__init__.py +21 -0
- conflint-0.1.1/src/conflint/scanners/base.py +49 -0
- conflint-0.1.1/src/conflint/scanners/go.py +53 -0
- conflint-0.1.1/src/conflint/scanners/javascript.py +115 -0
- conflint-0.1.1/src/conflint/scanners/python.py +196 -0
- conflint-0.1.1/src/conflint/scanners/ruby.py +80 -0
- conflint-0.1.1/src/conflint/sources/__init__.py +19 -0
- conflint-0.1.1/src/conflint/sources/_yaml.py +25 -0
- conflint-0.1.1/src/conflint/sources/base.py +66 -0
- conflint-0.1.1/src/conflint/sources/docker_compose.py +88 -0
- conflint-0.1.1/src/conflint/sources/dotenv.py +83 -0
- conflint-0.1.1/src/conflint/sources/github_actions.py +77 -0
- conflint-0.1.1/src/conflint/sources/kubernetes.py +146 -0
- conflint-0.1.1/src/conflint/sources/terraform.py +168 -0
- conflint-0.1.1/src/conflint/sync.py +123 -0
- conflint-0.1.1/src/conflint/utils.py +263 -0
- conflint-0.1.1/src/conflint/version.py +30 -0
- conflint-0.1.1/tests/conftest.py +42 -0
- conflint-0.1.1/tests/test_cli.py +130 -0
- conflint-0.1.1/tests/test_config.py +86 -0
- conflint-0.1.1/tests/test_discovery.py +63 -0
- conflint-0.1.1/tests/test_engine.py +117 -0
- conflint-0.1.1/tests/test_reporters.py +94 -0
- conflint-0.1.1/tests/test_rules.py +238 -0
- conflint-0.1.1/tests/test_scanners_javascript.py +72 -0
- conflint-0.1.1/tests/test_scanners_other.py +63 -0
- conflint-0.1.1/tests/test_scanners_python.py +90 -0
- conflint-0.1.1/tests/test_sources.py +221 -0
- conflint-0.1.1/tests/test_sync.py +49 -0
- conflint-0.1.1/tests/test_utils.py +63 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
.Python
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
*.egg
|
|
14
|
+
wheels/
|
|
15
|
+
.installed.cfg
|
|
16
|
+
|
|
17
|
+
# Test / coverage
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
.coverage.*
|
|
21
|
+
htmlcov/
|
|
22
|
+
.tox/
|
|
23
|
+
.nox/
|
|
24
|
+
.coverage.xml
|
|
25
|
+
junit.xml
|
|
26
|
+
report.xml
|
|
27
|
+
|
|
28
|
+
# Type checkers / linters / formatters
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.dmypy.json
|
|
31
|
+
.ruff_cache/
|
|
32
|
+
.pytype/
|
|
33
|
+
|
|
34
|
+
# Virtual environments
|
|
35
|
+
.venv/
|
|
36
|
+
venv/
|
|
37
|
+
env/
|
|
38
|
+
ENV/
|
|
39
|
+
|
|
40
|
+
# Editors / OS
|
|
41
|
+
.idea/
|
|
42
|
+
.vscode/
|
|
43
|
+
*.swp
|
|
44
|
+
.DS_Store
|
|
45
|
+
Thumbs.db
|
|
46
|
+
*.sublime-workspace
|
|
47
|
+
|
|
48
|
+
# mkdocs
|
|
49
|
+
site/
|
|
50
|
+
|
|
51
|
+
# generated by hatch-vcs at build/install time
|
|
52
|
+
src/conflint/_version.py
|
|
53
|
+
|
|
54
|
+
# conflint self-output
|
|
55
|
+
.conflint-cache/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## Unreleased
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Code-aware configuration linter with scanners for Python, JavaScript, Go and
|
|
13
|
+
Ruby.
|
|
14
|
+
- Configuration sources: dotenv, docker-compose, GitHub Actions, Kubernetes and
|
|
15
|
+
Terraform.
|
|
16
|
+
- Nine rules (CL001–CL009) covering missing, unused, misspelled, secret,
|
|
17
|
+
drift, empty, duplicate, weak and undocumented values.
|
|
18
|
+
- Reporters: text, JSON, SARIF, GitHub annotations and JUnit.
|
|
19
|
+
- `confl` CLI with `check`, `sync` (example-file generator), `explain`, `init`
|
|
20
|
+
and `rules` commands.
|
|
21
|
+
- `conflint.toml` / `[tool.conflint]` configuration with CLI overrides.
|
|
22
|
+
- Plugin entry points for third-party scanners, sources and rules.
|
|
23
|
+
- Test suite (135 tests), strict mypy typing, ruff linting/formatting, CI
|
|
24
|
+
(GitHub Actions) and pre-commit hooks.
|
conflint-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 conflint contributors
|
|
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.
|
conflint-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: conflint
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Code-aware config linter. Find every env var, config key and secret your app needs - and the drift across .env, CI, Docker, Kubernetes and Terraform before it breaks prod.
|
|
5
|
+
Project-URL: Homepage, https://github.com/conflint/conflint
|
|
6
|
+
Project-URL: Documentation, https://conflint.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/conflint/conflint
|
|
8
|
+
Project-URL: Issues, https://github.com/conflint/conflint/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/conflint/conflint/blob/main/CHANGELOG.md
|
|
10
|
+
Author: conflint contributors
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 conflint contributors
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: ci,config,dotenv,drift,env,kubernetes,linter,secrets
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Environment :: Console
|
|
36
|
+
Classifier: Intended Audience :: Developers
|
|
37
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
38
|
+
Classifier: Operating System :: OS Independent
|
|
39
|
+
Classifier: Programming Language :: Python :: 3
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
45
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
46
|
+
Classifier: Topic :: System :: Systems Administration
|
|
47
|
+
Classifier: Typing :: Typed
|
|
48
|
+
Requires-Python: >=3.9
|
|
49
|
+
Requires-Dist: click>=8.1
|
|
50
|
+
Requires-Dist: pathspec>=0.11
|
|
51
|
+
Requires-Dist: pyyaml>=6.0
|
|
52
|
+
Requires-Dist: rich>=12.0
|
|
53
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
54
|
+
Provides-Extra: dev
|
|
55
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
56
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
57
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
58
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
59
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
60
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
61
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
62
|
+
Provides-Extra: docs
|
|
63
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
64
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
65
|
+
Requires-Dist: mkdocstrings[python]>=0.24; extra == 'docs'
|
|
66
|
+
Description-Content-Type: text/markdown
|
|
67
|
+
|
|
68
|
+
<div align="center">
|
|
69
|
+
|
|
70
|
+
# conflint
|
|
71
|
+
|
|
72
|
+
**Code-aware configuration linting.**
|
|
73
|
+
Find every env var, config key and secret your app *actually* reads, then reconcile
|
|
74
|
+
it against `.env`, CI, Docker, Kubernetes and Terraform — **before it breaks prod**.
|
|
75
|
+
|
|
76
|
+
`pip install conflint` · `confl check` · [`conflint` on PyPI](https://pypi.org/project/conflint)
|
|
77
|
+
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Why conflint?
|
|
83
|
+
|
|
84
|
+
Most "works on my machine" disasters are configuration disasters:
|
|
85
|
+
|
|
86
|
+
- A teammate deleted a key from `.env` that your code still **requires**.
|
|
87
|
+
- The CI workflow never defines `DATABASE_URL`, so the app crashes at **deploy**, not at commit.
|
|
88
|
+
- `DB_HOST` vs `DBHOST` — the typo that no linter catches because your linter doesn't read your code.
|
|
89
|
+
- A real API key sitting in a committed `.env`.
|
|
90
|
+
|
|
91
|
+
`.env` linters validate a file against a **schema you write by hand**. conflint reads
|
|
92
|
+
the **actual source code** to learn the truth about what your app needs, then
|
|
93
|
+
reconciles it against **every** place that value should exist.
|
|
94
|
+
|
|
95
|
+
## Quick start
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install conflint
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# From your project root:
|
|
103
|
+
confl check # lint the whole project
|
|
104
|
+
confl sync # regenerate an accurate .env.example
|
|
105
|
+
confl explain DB_HOST # who reads DB_HOST? where is it defined?
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Example output:
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
conflint checked 42 files (173 config reads, 58 definitions) in 1.24s
|
|
112
|
+
|
|
113
|
+
app/main.py
|
|
114
|
+
CL001 error: 'DATABASE_URL' is read in code but not defined in any configuration source:12
|
|
115
|
+
hint: Add it to your .env (then run `confl sync` to refresh .env.example)
|
|
116
|
+
CL003 warning: 'DBHOST' is undefined but resembles 'DB_HOST' (distance 1):45
|
|
117
|
+
hint: Did you mean 'DB_HOST'?
|
|
118
|
+
docker-compose.yml
|
|
119
|
+
CL004 error: 'POSTGRES_PASSWORD' looks like a committed secret
|
|
120
|
+
|
|
121
|
+
42 files checked - 2 errors, 1 warning, 0 infos
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Commands
|
|
125
|
+
|
|
126
|
+
| Command | Purpose |
|
|
127
|
+
| --------------------- | ------------------------------------------------------------------ |
|
|
128
|
+
| `confl check` | Run all rules and exit `1` if anything reaches your fail level. |
|
|
129
|
+
| `confl check --fix` | Auto-remediate fixable findings (currently: syncs `.env.example`). |
|
|
130
|
+
| `confl sync` | Regenerate `.env.example` from code + sources (lossless rewrite). |
|
|
131
|
+
| `confl explain KEY` | Trace one key: every read site and every definition site. |
|
|
132
|
+
| `confl rules` | List all rules with their default severity. |
|
|
133
|
+
| `confl init` | Write a template `conflint.toml`. |
|
|
134
|
+
| `confl version` | Print the installed version. |
|
|
135
|
+
|
|
136
|
+
## Rules
|
|
137
|
+
|
|
138
|
+
| Rule | Name | Default | Meaning |
|
|
139
|
+
| ----- | ------------- | --------- | ------------------------------------------------------------------ |
|
|
140
|
+
| CL001 | missing | error | read in code, defined nowhere |
|
|
141
|
+
| CL002 | unused | warning | defined for real, never read by code |
|
|
142
|
+
| CL003 | typo | warning | undefined name is one edit away from a known one |
|
|
143
|
+
| CL004 | secret-leak | error | high-entropy secret committed in a config source |
|
|
144
|
+
| CL005 | drift | error | documented in `.env.example`, provided by no real source |
|
|
145
|
+
| CL006 | empty-value | warning | required value defined but empty |
|
|
146
|
+
| CL007 | duplicate | warning | defined twice in one file / conflicting values across sources |
|
|
147
|
+
| CL008 | weak-secret | warning | secret value equals a weak/default placeholder |
|
|
148
|
+
| CL009 | undocumented | info | used or provided, but missing from the example template |
|
|
149
|
+
|
|
150
|
+
### What gets scanned
|
|
151
|
+
|
|
152
|
+
| Language | Files | Recognised reads |
|
|
153
|
+
| -------- | ------------------------ | ----------------------------------------------------------- |
|
|
154
|
+
| Python | `.py`, `.pyi` (AST) | `os.environ[...]`, `os.environ.get`, `os.getenv` (+ aliases) |
|
|
155
|
+
| JS/TS | `.js`, `.ts`, `.jsx`... | `process.env`, `import.meta.env`, `Bun.env`, `Deno.env.get`, destructuring |
|
|
156
|
+
| Go | `.go` | `os.Getenv`, `os.LookupEnv`, `os.Setenv` |
|
|
157
|
+
| Ruby | `.rb` | `ENV[...]`, `ENV.fetch` |
|
|
158
|
+
|
|
159
|
+
### Configuration sources (all gitignore-aware in reverse)
|
|
160
|
+
|
|
161
|
+
| Source | Finds |
|
|
162
|
+
| --------------- | ------------------------------------------------------- |
|
|
163
|
+
| dotenv | `.env`, `.env.local`, `.env.example`, ... |
|
|
164
|
+
| docker-compose | `services.*.environment` (list & map styles) |
|
|
165
|
+
| github-actions | `env:` maps in `.github/workflows/*` |
|
|
166
|
+
| kubernetes | container `env`, `ConfigMap.data`, `Secret.data` |
|
|
167
|
+
| terraform | `variable ""`, `.tfvars`, `environment = {}` blocks |
|
|
168
|
+
|
|
169
|
+
## Configuration
|
|
170
|
+
|
|
171
|
+
Config is optional. When you need it, use `conflint.toml` (or `pyproject.toml`
|
|
172
|
+
under `[tool.conflint]`):
|
|
173
|
+
|
|
174
|
+
```toml
|
|
175
|
+
[tool.conflint]
|
|
176
|
+
fail-level = "error" # error | warning | info
|
|
177
|
+
require-example = true # enforce a populated .env.example
|
|
178
|
+
|
|
179
|
+
enable = { CL003 = "error" } # raise a rule's severity
|
|
180
|
+
disable = ["CL002"] # turn rules off
|
|
181
|
+
|
|
182
|
+
ignore-names = ["CI=true", "NODE_ENV=*"]
|
|
183
|
+
ignore-paths = ["scripts/**", "vendor/**"]
|
|
184
|
+
|
|
185
|
+
sources = ["dotenv", "docker-compose", "github-actions", "kubernetes", "terraform"]
|
|
186
|
+
scanners = ["python", "javascript"]
|
|
187
|
+
reporters = ["text"]
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Run `confl init` to write a commented template.
|
|
191
|
+
|
|
192
|
+
## CI integration
|
|
193
|
+
|
|
194
|
+
### GitHub Actions
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
- name: Lint configuration
|
|
198
|
+
uses: conflint/conflint@v1
|
|
199
|
+
with:
|
|
200
|
+
reporter: github # inline PR annotations
|
|
201
|
+
fail-level: error
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
or with pip directly:
|
|
205
|
+
|
|
206
|
+
```yaml
|
|
207
|
+
- uses: actions/setup-python@v5
|
|
208
|
+
with: { python-version: "3.12" }
|
|
209
|
+
- run: pip install conflint
|
|
210
|
+
- run: confl check --github
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### pre-commit
|
|
214
|
+
|
|
215
|
+
```yaml
|
|
216
|
+
- repo: https://github.com/conflint/conflint
|
|
217
|
+
rev: v0.1.0
|
|
218
|
+
hooks:
|
|
219
|
+
- id: conflint
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Output formats
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
confl check # rich terminal output
|
|
226
|
+
confl check --json # stable JSON schema (v1.0)
|
|
227
|
+
confl check --sarif # SARIF 2.1.0 (CodeQL, Azure Pipelines, GitLab)
|
|
228
|
+
confl check --github # GitHub Actions workflow commands
|
|
229
|
+
confl check --report junit # JUnit XML for Jenkins dashboards
|
|
230
|
+
confl check --json --output report.json # write to a file
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
git clone https://github.com/conflint/conflint
|
|
237
|
+
cd conflint
|
|
238
|
+
pip install -e ".[dev]"
|
|
239
|
+
pytest
|
|
240
|
+
ruff check .
|
|
241
|
+
mypy src
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT. See [LICENSE](LICENSE).
|
|
247
|
+
|
|
248
|
+
## Similar tools & why conflint is different
|
|
249
|
+
|
|
250
|
+
| Tool | What it does | What conflint adds |
|
|
251
|
+
| ------------ | ------------------------------- | -------------------------------------- |
|
|
252
|
+
| `dotenv-linter` | validates `.env` against rules | reads your **code**, not a hand-made schema |
|
|
253
|
+
| `trufflehog`/`gitleaks` | scans git history for secrets | live per-key **value** + **drift** reconciliation in CI |
|
|
254
|
+
| envcheck-style CLIs | compare `.env.example` to `.env` | cross-source graph: code · .env · CI · k8s · terraform |
|
|
255
|
+
| `mypy`/`ruff` | static types/lint | the **configuration layer** they ignore |
|
conflint-0.1.1/README.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# conflint
|
|
4
|
+
|
|
5
|
+
**Code-aware configuration linting.**
|
|
6
|
+
Find every env var, config key and secret your app *actually* reads, then reconcile
|
|
7
|
+
it against `.env`, CI, Docker, Kubernetes and Terraform — **before it breaks prod**.
|
|
8
|
+
|
|
9
|
+
`pip install conflint` · `confl check` · [`conflint` on PyPI](https://pypi.org/project/conflint)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Why conflint?
|
|
16
|
+
|
|
17
|
+
Most "works on my machine" disasters are configuration disasters:
|
|
18
|
+
|
|
19
|
+
- A teammate deleted a key from `.env` that your code still **requires**.
|
|
20
|
+
- The CI workflow never defines `DATABASE_URL`, so the app crashes at **deploy**, not at commit.
|
|
21
|
+
- `DB_HOST` vs `DBHOST` — the typo that no linter catches because your linter doesn't read your code.
|
|
22
|
+
- A real API key sitting in a committed `.env`.
|
|
23
|
+
|
|
24
|
+
`.env` linters validate a file against a **schema you write by hand**. conflint reads
|
|
25
|
+
the **actual source code** to learn the truth about what your app needs, then
|
|
26
|
+
reconciles it against **every** place that value should exist.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install conflint
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# From your project root:
|
|
36
|
+
confl check # lint the whole project
|
|
37
|
+
confl sync # regenerate an accurate .env.example
|
|
38
|
+
confl explain DB_HOST # who reads DB_HOST? where is it defined?
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Example output:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
conflint checked 42 files (173 config reads, 58 definitions) in 1.24s
|
|
45
|
+
|
|
46
|
+
app/main.py
|
|
47
|
+
CL001 error: 'DATABASE_URL' is read in code but not defined in any configuration source:12
|
|
48
|
+
hint: Add it to your .env (then run `confl sync` to refresh .env.example)
|
|
49
|
+
CL003 warning: 'DBHOST' is undefined but resembles 'DB_HOST' (distance 1):45
|
|
50
|
+
hint: Did you mean 'DB_HOST'?
|
|
51
|
+
docker-compose.yml
|
|
52
|
+
CL004 error: 'POSTGRES_PASSWORD' looks like a committed secret
|
|
53
|
+
|
|
54
|
+
42 files checked - 2 errors, 1 warning, 0 infos
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Commands
|
|
58
|
+
|
|
59
|
+
| Command | Purpose |
|
|
60
|
+
| --------------------- | ------------------------------------------------------------------ |
|
|
61
|
+
| `confl check` | Run all rules and exit `1` if anything reaches your fail level. |
|
|
62
|
+
| `confl check --fix` | Auto-remediate fixable findings (currently: syncs `.env.example`). |
|
|
63
|
+
| `confl sync` | Regenerate `.env.example` from code + sources (lossless rewrite). |
|
|
64
|
+
| `confl explain KEY` | Trace one key: every read site and every definition site. |
|
|
65
|
+
| `confl rules` | List all rules with their default severity. |
|
|
66
|
+
| `confl init` | Write a template `conflint.toml`. |
|
|
67
|
+
| `confl version` | Print the installed version. |
|
|
68
|
+
|
|
69
|
+
## Rules
|
|
70
|
+
|
|
71
|
+
| Rule | Name | Default | Meaning |
|
|
72
|
+
| ----- | ------------- | --------- | ------------------------------------------------------------------ |
|
|
73
|
+
| CL001 | missing | error | read in code, defined nowhere |
|
|
74
|
+
| CL002 | unused | warning | defined for real, never read by code |
|
|
75
|
+
| CL003 | typo | warning | undefined name is one edit away from a known one |
|
|
76
|
+
| CL004 | secret-leak | error | high-entropy secret committed in a config source |
|
|
77
|
+
| CL005 | drift | error | documented in `.env.example`, provided by no real source |
|
|
78
|
+
| CL006 | empty-value | warning | required value defined but empty |
|
|
79
|
+
| CL007 | duplicate | warning | defined twice in one file / conflicting values across sources |
|
|
80
|
+
| CL008 | weak-secret | warning | secret value equals a weak/default placeholder |
|
|
81
|
+
| CL009 | undocumented | info | used or provided, but missing from the example template |
|
|
82
|
+
|
|
83
|
+
### What gets scanned
|
|
84
|
+
|
|
85
|
+
| Language | Files | Recognised reads |
|
|
86
|
+
| -------- | ------------------------ | ----------------------------------------------------------- |
|
|
87
|
+
| Python | `.py`, `.pyi` (AST) | `os.environ[...]`, `os.environ.get`, `os.getenv` (+ aliases) |
|
|
88
|
+
| JS/TS | `.js`, `.ts`, `.jsx`... | `process.env`, `import.meta.env`, `Bun.env`, `Deno.env.get`, destructuring |
|
|
89
|
+
| Go | `.go` | `os.Getenv`, `os.LookupEnv`, `os.Setenv` |
|
|
90
|
+
| Ruby | `.rb` | `ENV[...]`, `ENV.fetch` |
|
|
91
|
+
|
|
92
|
+
### Configuration sources (all gitignore-aware in reverse)
|
|
93
|
+
|
|
94
|
+
| Source | Finds |
|
|
95
|
+
| --------------- | ------------------------------------------------------- |
|
|
96
|
+
| dotenv | `.env`, `.env.local`, `.env.example`, ... |
|
|
97
|
+
| docker-compose | `services.*.environment` (list & map styles) |
|
|
98
|
+
| github-actions | `env:` maps in `.github/workflows/*` |
|
|
99
|
+
| kubernetes | container `env`, `ConfigMap.data`, `Secret.data` |
|
|
100
|
+
| terraform | `variable ""`, `.tfvars`, `environment = {}` blocks |
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
Config is optional. When you need it, use `conflint.toml` (or `pyproject.toml`
|
|
105
|
+
under `[tool.conflint]`):
|
|
106
|
+
|
|
107
|
+
```toml
|
|
108
|
+
[tool.conflint]
|
|
109
|
+
fail-level = "error" # error | warning | info
|
|
110
|
+
require-example = true # enforce a populated .env.example
|
|
111
|
+
|
|
112
|
+
enable = { CL003 = "error" } # raise a rule's severity
|
|
113
|
+
disable = ["CL002"] # turn rules off
|
|
114
|
+
|
|
115
|
+
ignore-names = ["CI=true", "NODE_ENV=*"]
|
|
116
|
+
ignore-paths = ["scripts/**", "vendor/**"]
|
|
117
|
+
|
|
118
|
+
sources = ["dotenv", "docker-compose", "github-actions", "kubernetes", "terraform"]
|
|
119
|
+
scanners = ["python", "javascript"]
|
|
120
|
+
reporters = ["text"]
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run `confl init` to write a commented template.
|
|
124
|
+
|
|
125
|
+
## CI integration
|
|
126
|
+
|
|
127
|
+
### GitHub Actions
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
- name: Lint configuration
|
|
131
|
+
uses: conflint/conflint@v1
|
|
132
|
+
with:
|
|
133
|
+
reporter: github # inline PR annotations
|
|
134
|
+
fail-level: error
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
or with pip directly:
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
- uses: actions/setup-python@v5
|
|
141
|
+
with: { python-version: "3.12" }
|
|
142
|
+
- run: pip install conflint
|
|
143
|
+
- run: confl check --github
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### pre-commit
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
- repo: https://github.com/conflint/conflint
|
|
150
|
+
rev: v0.1.0
|
|
151
|
+
hooks:
|
|
152
|
+
- id: conflint
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Output formats
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
confl check # rich terminal output
|
|
159
|
+
confl check --json # stable JSON schema (v1.0)
|
|
160
|
+
confl check --sarif # SARIF 2.1.0 (CodeQL, Azure Pipelines, GitLab)
|
|
161
|
+
confl check --github # GitHub Actions workflow commands
|
|
162
|
+
confl check --report junit # JUnit XML for Jenkins dashboards
|
|
163
|
+
confl check --json --output report.json # write to a file
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
git clone https://github.com/conflint/conflint
|
|
170
|
+
cd conflint
|
|
171
|
+
pip install -e ".[dev]"
|
|
172
|
+
pytest
|
|
173
|
+
ruff check .
|
|
174
|
+
mypy src
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT. See [LICENSE](LICENSE).
|
|
180
|
+
|
|
181
|
+
## Similar tools & why conflint is different
|
|
182
|
+
|
|
183
|
+
| Tool | What it does | What conflint adds |
|
|
184
|
+
| ------------ | ------------------------------- | -------------------------------------- |
|
|
185
|
+
| `dotenv-linter` | validates `.env` against rules | reads your **code**, not a hand-made schema |
|
|
186
|
+
| `trufflehog`/`gitleaks` | scans git history for secrets | live per-key **value** + **drift** reconciliation in CI |
|
|
187
|
+
| envcheck-style CLIs | compare `.env.example` to `.env` | cross-source graph: code · .env · CI · k8s · terraform |
|
|
188
|
+
| `mypy`/`ruff` | static types/lint | the **configuration layer** they ignore |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Configuration is optional. When you need it, put a **flat** `conflint.toml` in
|
|
4
|
+
the project root (or a `.conflint.toml`), or nest the same keys under
|
|
5
|
+
`[tool.conflint]` in `pyproject.toml`.
|
|
6
|
+
|
|
7
|
+
Run `confl init` to write a commented template.
|
|
8
|
+
|
|
9
|
+
```toml
|
|
10
|
+
# conflint.toml — keys are top-level here.
|
|
11
|
+
# In pyproject.toml they are nested under [tool.conflint].
|
|
12
|
+
|
|
13
|
+
fail-level = "error" # error | warning | info
|
|
14
|
+
require-example = true # enforce a populated .env.example
|
|
15
|
+
|
|
16
|
+
enable = { CL003 = "error" } # raise a rule's severity
|
|
17
|
+
disable = ["CL002", "CL009"] # turn rules off
|
|
18
|
+
|
|
19
|
+
ignore-names = ["CI=true", "NODE_ENV=*"]
|
|
20
|
+
ignore-paths = ["scripts/**", "vendor/**"]
|
|
21
|
+
|
|
22
|
+
include = ["**/*"] # code globs (relative to the project root)
|
|
23
|
+
exclude = [".git/**", "**/node_modules/**", ...]
|
|
24
|
+
|
|
25
|
+
sources = ["dotenv", "docker-compose", "github-actions", "kubernetes", "terraform"]
|
|
26
|
+
scanners = ["python", "javascript"]
|
|
27
|
+
reporters = ["text"] # default reporter(s) for `confl check`
|
|
28
|
+
|
|
29
|
+
color = true # ANSI in text output
|
|
30
|
+
entropy-threshold = 3.5 # CL004 secret sensitivity
|
|
31
|
+
|
|
32
|
+
example-files = [".env.example", ".env.sample", ...]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Config file resolution order (later wins):
|
|
36
|
+
|
|
37
|
+
1. `pyproject.toml` → `[tool.conflint]`
|
|
38
|
+
2. `conflint.toml`, then `.conflint.toml`
|
|
39
|
+
3. `--config FILE` on the command line
|
|
40
|
+
4. CLI flags (`--fail-level`, `--no-color`, positional paths)
|
|
41
|
+
|
|
42
|
+
Unknown keys raise a configuration error so typos surface immediately.
|
|
43
|
+
|
|
44
|
+
## Reference
|
|
45
|
+
|
|
46
|
+
| Key | Type | Default | Meaning |
|
|
47
|
+
| --- | --- | --- | --- |
|
|
48
|
+
| `include` | list of globs | `["**/*"]` | code files to scan |
|
|
49
|
+
| `exclude` | list of globs | system defaults | paths to skip |
|
|
50
|
+
| `scanners` | list of names | all | enabled language scanners |
|
|
51
|
+
| `sources` | list of names | all | enabled config sources |
|
|
52
|
+
| `enable` | table rule→severity | — | override a rule's severity |
|
|
53
|
+
| `disable` | list of rule ids | — | turn rules off |
|
|
54
|
+
| `ignore-names` | list of globs | — | exempt names from all rules |
|
|
55
|
+
| `ignore-paths` | list of globs | — | exempt paths from scanning |
|
|
56
|
+
| `fail-level` | `error`/`warning`/`info` | `error` | exit threshold for `check` |
|
|
57
|
+
| `example-files` | list of names | system defaults | example/template files |
|
|
58
|
+
| `color` | bool | auto | ANSI in text output |
|
|
59
|
+
| `entropy-threshold` | float | `3.5` | CL004 sensitivity |
|
|
60
|
+
| `require-example` | bool | `true` | require a populated example file |
|
|
61
|
+
| `reporters` | list of names | `["text"]` | default output for `check` |
|
|
62
|
+
|
|
63
|
+
`CLI overrides` for paths and `--fail-level`/`--no-color` always win because
|
|
64
|
+
they come last.
|