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.
Files changed (72) hide show
  1. conflint-0.1.1/.gitignore +55 -0
  2. conflint-0.1.1/CHANGELOG.md +24 -0
  3. conflint-0.1.1/LICENSE +21 -0
  4. conflint-0.1.1/PKG-INFO +255 -0
  5. conflint-0.1.1/README.md +188 -0
  6. conflint-0.1.1/docs/configuration.md +64 -0
  7. conflint-0.1.1/docs/index.md +89 -0
  8. conflint-0.1.1/docs/plugins.md +104 -0
  9. conflint-0.1.1/docs/reference.md +22 -0
  10. conflint-0.1.1/docs/reporters.md +58 -0
  11. conflint-0.1.1/docs/rules.md +67 -0
  12. conflint-0.1.1/docs/usage.md +76 -0
  13. conflint-0.1.1/pyproject.toml +143 -0
  14. conflint-0.1.1/src/conflint/__about__.py +7 -0
  15. conflint-0.1.1/src/conflint/__init__.py +32 -0
  16. conflint-0.1.1/src/conflint/__main__.py +8 -0
  17. conflint-0.1.1/src/conflint/_version.py +24 -0
  18. conflint-0.1.1/src/conflint/cli.py +374 -0
  19. conflint-0.1.1/src/conflint/config.py +268 -0
  20. conflint-0.1.1/src/conflint/discovery.py +167 -0
  21. conflint-0.1.1/src/conflint/engine.py +182 -0
  22. conflint-0.1.1/src/conflint/exceptions.py +60 -0
  23. conflint-0.1.1/src/conflint/models.py +302 -0
  24. conflint-0.1.1/src/conflint/registry.py +163 -0
  25. conflint-0.1.1/src/conflint/reporters/__init__.py +50 -0
  26. conflint-0.1.1/src/conflint/reporters/base.py +31 -0
  27. conflint-0.1.1/src/conflint/reporters/github.py +45 -0
  28. conflint-0.1.1/src/conflint/reporters/json.py +37 -0
  29. conflint-0.1.1/src/conflint/reporters/junit.py +70 -0
  30. conflint-0.1.1/src/conflint/reporters/sarif.py +103 -0
  31. conflint-0.1.1/src/conflint/reporters/text.py +102 -0
  32. conflint-0.1.1/src/conflint/rules/__init__.py +44 -0
  33. conflint-0.1.1/src/conflint/rules/base.py +61 -0
  34. conflint-0.1.1/src/conflint/rules/drift.py +38 -0
  35. conflint-0.1.1/src/conflint/rules/duplicate.py +70 -0
  36. conflint-0.1.1/src/conflint/rules/empty.py +38 -0
  37. conflint-0.1.1/src/conflint/rules/missing.py +38 -0
  38. conflint-0.1.1/src/conflint/rules/secrets.py +39 -0
  39. conflint-0.1.1/src/conflint/rules/typo.py +39 -0
  40. conflint-0.1.1/src/conflint/rules/undocumented.py +48 -0
  41. conflint-0.1.1/src/conflint/rules/unused.py +40 -0
  42. conflint-0.1.1/src/conflint/rules/weak.py +75 -0
  43. conflint-0.1.1/src/conflint/scanners/__init__.py +21 -0
  44. conflint-0.1.1/src/conflint/scanners/base.py +49 -0
  45. conflint-0.1.1/src/conflint/scanners/go.py +53 -0
  46. conflint-0.1.1/src/conflint/scanners/javascript.py +115 -0
  47. conflint-0.1.1/src/conflint/scanners/python.py +196 -0
  48. conflint-0.1.1/src/conflint/scanners/ruby.py +80 -0
  49. conflint-0.1.1/src/conflint/sources/__init__.py +19 -0
  50. conflint-0.1.1/src/conflint/sources/_yaml.py +25 -0
  51. conflint-0.1.1/src/conflint/sources/base.py +66 -0
  52. conflint-0.1.1/src/conflint/sources/docker_compose.py +88 -0
  53. conflint-0.1.1/src/conflint/sources/dotenv.py +83 -0
  54. conflint-0.1.1/src/conflint/sources/github_actions.py +77 -0
  55. conflint-0.1.1/src/conflint/sources/kubernetes.py +146 -0
  56. conflint-0.1.1/src/conflint/sources/terraform.py +168 -0
  57. conflint-0.1.1/src/conflint/sync.py +123 -0
  58. conflint-0.1.1/src/conflint/utils.py +263 -0
  59. conflint-0.1.1/src/conflint/version.py +30 -0
  60. conflint-0.1.1/tests/conftest.py +42 -0
  61. conflint-0.1.1/tests/test_cli.py +130 -0
  62. conflint-0.1.1/tests/test_config.py +86 -0
  63. conflint-0.1.1/tests/test_discovery.py +63 -0
  64. conflint-0.1.1/tests/test_engine.py +117 -0
  65. conflint-0.1.1/tests/test_reporters.py +94 -0
  66. conflint-0.1.1/tests/test_rules.py +238 -0
  67. conflint-0.1.1/tests/test_scanners_javascript.py +72 -0
  68. conflint-0.1.1/tests/test_scanners_other.py +63 -0
  69. conflint-0.1.1/tests/test_scanners_python.py +90 -0
  70. conflint-0.1.1/tests/test_sources.py +221 -0
  71. conflint-0.1.1/tests/test_sync.py +49 -0
  72. 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.
@@ -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 |
@@ -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.