dotguard-cli 0.2.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.
- dotguard_cli-0.2.0/LICENSE +21 -0
- dotguard_cli-0.2.0/PKG-INFO +361 -0
- dotguard_cli-0.2.0/README.md +331 -0
- dotguard_cli-0.2.0/pyproject.toml +52 -0
- dotguard_cli-0.2.0/setup.cfg +4 -0
- dotguard_cli-0.2.0/src/dotguard/__init__.py +22 -0
- dotguard_cli-0.2.0/src/dotguard/__main__.py +5 -0
- dotguard_cli-0.2.0/src/dotguard/checker.py +203 -0
- dotguard_cli-0.2.0/src/dotguard/cli.py +182 -0
- dotguard_cli-0.2.0/src/dotguard/differ.py +59 -0
- dotguard_cli-0.2.0/src/dotguard/models.py +63 -0
- dotguard_cli-0.2.0/src/dotguard/parser.py +216 -0
- dotguard_cli-0.2.0/src/dotguard/report.py +79 -0
- dotguard_cli-0.2.0/src/dotguard/secrets.py +90 -0
- dotguard_cli-0.2.0/src/dotguard/types.py +76 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/PKG-INFO +361 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/SOURCES.txt +24 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/dependency_links.txt +1 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/entry_points.txt +2 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/requires.txt +3 -0
- dotguard_cli-0.2.0/src/dotguard_cli.egg-info/top_level.txt +1 -0
- dotguard_cli-0.2.0/tests/test_checker.py +89 -0
- dotguard_cli-0.2.0/tests/test_cli.py +110 -0
- dotguard_cli-0.2.0/tests/test_differ.py +56 -0
- dotguard_cli-0.2.0/tests/test_parser.py +104 -0
- dotguard_cli-0.2.0/tests/test_secrets.py +46 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kanhaiya Kumar
|
|
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,361 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dotguard-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Validate .env files against a documented .env.example, and keep real secrets out of git.
|
|
5
|
+
Author: Kanhaiya Kumar
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/K70281095/dotguard
|
|
8
|
+
Project-URL: Issues, https://github.com/K70281095/dotguard/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/K70281095/dotguard/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: dotenv,env,environment-variables,config,validation,secrets,cli,ci
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# dotguard
|
|
32
|
+
|
|
33
|
+
**Validate `.env` files against a documented `.env.example`, and keep real secrets out of git.**
|
|
34
|
+
|
|
35
|
+
[](https://github.com/K70281095/dotguard/actions/workflows/ci.yml)
|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
[](LICENSE)
|
|
39
|
+
|
|
40
|
+
Almost every project has a `.env.example` that says which environment variables the app needs.
|
|
41
|
+
Almost every project also has that file drift out of date: a new variable gets added to the code
|
|
42
|
+
but not to the example, someone sets `PORT=80O0`, or a real API key slips into the example and
|
|
43
|
+
gets committed.
|
|
44
|
+
|
|
45
|
+
`dotguard` turns `.env.example` into a lightweight, human-readable **schema** and checks your
|
|
46
|
+
real `.env` against it, locally, in a pre-commit hook or in CI.
|
|
47
|
+
|
|
48
|
+
```console
|
|
49
|
+
$ dotguard check --env examples/.env --example examples/.env.example
|
|
50
|
+
examples/.env:3 error DG004 PORT=80O0: expected a port number between 1 and 65535
|
|
51
|
+
examples/.env:4 error DG007 APP_ENV=prod is not one of: development, staging, production
|
|
52
|
+
examples/.env:6 error DG006 WORKERS=64 is above the @max of 32
|
|
53
|
+
examples/.env:7 error DG004 BASE_URL=localhost:8080: expected a URL with a scheme and host, e.g. https://example.com
|
|
54
|
+
examples/.env error DG001 DATABASE_URL is missing (documented in examples/.env.example:32)
|
|
55
|
+
examples/.env:8 error DG003 PAYMENTS_API_TOKEN is required but empty
|
|
56
|
+
examples/.env:10 warning DG008 VERBOSE is deprecated: use LOG_LEVEL=debug instead
|
|
57
|
+
examples/.env:11 warning DG002 OLD_FEATURE_FLAG is not documented in examples/.env.example
|
|
58
|
+
|
|
59
|
+
6 error(s), 2 warning(s)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Table of contents
|
|
65
|
+
|
|
66
|
+
- [Why dotguard?](#why-dotguard)
|
|
67
|
+
- [Install](#install)
|
|
68
|
+
- [Quick start](#quick-start)
|
|
69
|
+
- [Annotating `.env.example`](#annotating-envexample)
|
|
70
|
+
- [Commands](#commands)
|
|
71
|
+
- [Output formats and exit codes](#output-formats-and-exit-codes)
|
|
72
|
+
- [Using dotguard in CI](#using-dotguard-in-ci)
|
|
73
|
+
- [Using it from Python](#using-it-from-python)
|
|
74
|
+
- [`.env` syntax supported](#env-syntax-supported)
|
|
75
|
+
- [Roadmap](#roadmap)
|
|
76
|
+
- [Contributing](#contributing)
|
|
77
|
+
- [License](#license)
|
|
78
|
+
|
|
79
|
+
## Why dotguard?
|
|
80
|
+
|
|
81
|
+
| | |
|
|
82
|
+
|---|---|
|
|
83
|
+
| **Zero dependencies** | Pure Python standard library. Nothing to audit, nothing to break. |
|
|
84
|
+
| **No new config file** | The schema lives as comments in the `.env.example` you already have. |
|
|
85
|
+
| **Catches real mistakes** | Missing keys, typos, wrong types, values outside an allowed list or range. |
|
|
86
|
+
| **Secret scanning** | Flags real-looking AWS, GitHub, Slack, Stripe, Google and OpenAI-style keys, private keys and JWTs in files you commit. |
|
|
87
|
+
| **Never leaks values** | Keys marked `@secret` are printed as `****` in every message and CI log. |
|
|
88
|
+
| **CI-friendly** | Stable rule codes, JSON output, GitHub Actions annotations, clear exit codes. |
|
|
89
|
+
|
|
90
|
+
## Install
|
|
91
|
+
|
|
92
|
+
From PyPI (the package is called `dotguard-cli`; the command is `dotguard`):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install dotguard-cli
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Or the latest code straight from GitHub:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install git+https://github.com/K70281095/dotguard.git
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or run it from a clone without installing:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
git clone https://github.com/K70281095/dotguard.git
|
|
108
|
+
cd dotguard
|
|
109
|
+
PYTHONPATH=src python3 -m dotguard --help
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Requires Python 3.9 or newer.
|
|
113
|
+
|
|
114
|
+
## Quick start
|
|
115
|
+
|
|
116
|
+
1. **Already have a `.env` but no example?** Generate one. Sensitive-looking keys get `@secret`
|
|
117
|
+
and every value is blanked, so the result is safe to commit:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
dotguard init # writes .env.example from .env
|
|
121
|
+
dotguard init --keep-values # keep non-secret values as defaults
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
2. **Document the rules** by adding annotation comments (see below).
|
|
125
|
+
|
|
126
|
+
3. **Check your environment**:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
dotguard check
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
4. **Make sure nobody commits a real secret** in the example:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
dotguard scan .env.example
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
A full, working example lives in [`examples/`](examples/).
|
|
139
|
+
|
|
140
|
+
## Annotating `.env.example`
|
|
141
|
+
|
|
142
|
+
Write annotations as comments directly above a key. Ordinary comments become the key's
|
|
143
|
+
documentation. A blank line ends the block.
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# Port the HTTP server listens on.
|
|
147
|
+
# @type port
|
|
148
|
+
# @required
|
|
149
|
+
PORT=8080
|
|
150
|
+
|
|
151
|
+
# Which deployment this is.
|
|
152
|
+
# @values development, staging, production
|
|
153
|
+
APP_ENV=development
|
|
154
|
+
|
|
155
|
+
# Number of background workers.
|
|
156
|
+
# @type int
|
|
157
|
+
# @min 1
|
|
158
|
+
# @max 32
|
|
159
|
+
WORKERS=4
|
|
160
|
+
|
|
161
|
+
# Postgres connection string.
|
|
162
|
+
# @type url
|
|
163
|
+
# @secret
|
|
164
|
+
DATABASE_URL=
|
|
165
|
+
|
|
166
|
+
# Sentry DSN. Leave empty to disable error reporting.
|
|
167
|
+
# @optional
|
|
168
|
+
SENTRY_DSN=
|
|
169
|
+
|
|
170
|
+
# @deprecated use LOG_LEVEL instead
|
|
171
|
+
# @optional
|
|
172
|
+
VERBOSE=
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Annotation | Meaning |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `@type T` | Value must be of type `T`: `string` (default), `int`, `float`, `bool`, `port`, `url`, `email`. |
|
|
178
|
+
| `@required` | Value must not be empty. |
|
|
179
|
+
| `@optional` | Key may be absent from `.env`. Without it, every documented key must be present. |
|
|
180
|
+
| `@pattern REGEX` | Value must fully match the Python regular expression. |
|
|
181
|
+
| `@values a, b, c` | Value must be one of the listed choices. |
|
|
182
|
+
| `@min N` / `@max N` | Inclusive bounds for numeric types. |
|
|
183
|
+
| `@secret` | Never print the value; also makes `scan` treat the key as sensitive. |
|
|
184
|
+
| `@deprecated [reason]` | Warn when the key is still set. |
|
|
185
|
+
|
|
186
|
+
Full reference: [docs/annotations.md](docs/annotations.md). Every rule code (`DG001`…) is
|
|
187
|
+
explained in [docs/rules.md](docs/rules.md).
|
|
188
|
+
|
|
189
|
+
## Commands
|
|
190
|
+
|
|
191
|
+
### `dotguard check`
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
dotguard check [--env .env] [--example .env.example] [--strict]
|
|
195
|
+
[--format text|json|github] [--fail-on-warning]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Checks every key documented in the example against the env file. With `--strict`, keys that
|
|
199
|
+
exist in `.env` but not in the example are errors instead of warnings, which helps keep the
|
|
200
|
+
example complete.
|
|
201
|
+
|
|
202
|
+
### `dotguard scan`
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
dotguard scan [FILES ...] [--format text|json|github] [--fail-on-warning]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Scans files you intend to commit (default: `.env.example`) for:
|
|
209
|
+
|
|
210
|
+
- **DS001 (error):** well-known credential formats (AWS, GitHub, Slack, Stripe live keys,
|
|
211
|
+
Google API keys, OpenAI-style keys, PEM private keys, JWTs).
|
|
212
|
+
- **DS002 (warning):** long, high-entropy values under sensitive-looking names
|
|
213
|
+
(`*_TOKEN`, `*_SECRET`, `*PASSWORD*`, `*API_KEY*`, …) or keys marked `@secret`.
|
|
214
|
+
|
|
215
|
+
Obvious placeholders such as `changeme`, `<your-token>`, `xxxx` and `${VAR}` are ignored.
|
|
216
|
+
|
|
217
|
+
### `dotguard diff`
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
dotguard diff LEFT RIGHT [--values] [--format text|json|github] [--fail-on-warning]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Compares two environment files, for example staging and production, and reports keys that
|
|
224
|
+
exist in only one of them (**DD001**, **DD002**). With `--values` it also lists keys whose values
|
|
225
|
+
differ (**DD003**, warning). Values themselves are never printed, so the output is safe to paste
|
|
226
|
+
into a ticket or a CI log.
|
|
227
|
+
|
|
228
|
+
```console
|
|
229
|
+
$ dotguard diff .env.staging .env.production --values
|
|
230
|
+
.env.staging:4 error DD001 FEATURE_X is set in .env.staging but missing from .env.production
|
|
231
|
+
.env.staging:2 warning DD003 DATABASE_URL has a different value in .env.production:2
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### `dotguard init`
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
dotguard init [--env .env] [--output .env.example] [--keep-values] [--force]
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Creates a starter `.env.example` from an existing `.env`, guessing `@type` for ports, numbers,
|
|
241
|
+
booleans, URLs and emails and marking sensitive keys `@secret`. Secret values are never copied,
|
|
242
|
+
even with `--keep-values`. It refuses to overwrite an existing file unless you pass `--force`.
|
|
243
|
+
|
|
244
|
+
## Output formats and exit codes
|
|
245
|
+
|
|
246
|
+
| `--format` | Use it for |
|
|
247
|
+
|---|---|
|
|
248
|
+
| `text` (default) | People. Colored when writing to a terminal; respects `NO_COLOR` and `FORCE_COLOR`. |
|
|
249
|
+
| `json` | Other tools. `{"issues": [...], "summary": {"errors": N, "warnings": N}}` |
|
|
250
|
+
| `github` | GitHub Actions. Issues appear as inline annotations on the pull request. |
|
|
251
|
+
|
|
252
|
+
| Exit code | Meaning |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `0` | No errors (warnings allowed unless `--fail-on-warning`). |
|
|
255
|
+
| `1` | Problems found. |
|
|
256
|
+
| `2` | Usage error: a file is missing or cannot be parsed. |
|
|
257
|
+
|
|
258
|
+
## Using dotguard in CI
|
|
259
|
+
|
|
260
|
+
### GitHub Actions
|
|
261
|
+
|
|
262
|
+
This repository is also a composite action:
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
- uses: actions/checkout@v5
|
|
266
|
+
- uses: K70281095/dotguard@v0.2.0
|
|
267
|
+
with:
|
|
268
|
+
command: scan
|
|
269
|
+
args: .env.example
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Or install and run it yourself:
|
|
273
|
+
|
|
274
|
+
```yaml
|
|
275
|
+
- uses: actions/setup-python@v6
|
|
276
|
+
with:
|
|
277
|
+
python-version: "3.12"
|
|
278
|
+
- run: pip install git+https://github.com/K70281095/dotguard.git
|
|
279
|
+
- run: dotguard scan .env.example --format github
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### pre-commit
|
|
283
|
+
|
|
284
|
+
```yaml
|
|
285
|
+
# .pre-commit-config.yaml
|
|
286
|
+
repos:
|
|
287
|
+
- repo: https://github.com/K70281095/dotguard
|
|
288
|
+
rev: v0.2.0
|
|
289
|
+
hooks:
|
|
290
|
+
- id: dotguard-scan
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
More recipes, including GitLab CI and a plain git hook: [docs/ci.md](docs/ci.md).
|
|
294
|
+
|
|
295
|
+
## Using it from Python
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
import dotguard
|
|
299
|
+
|
|
300
|
+
env = dotguard.parse_file(".env")
|
|
301
|
+
example = dotguard.parse_file(".env.example")
|
|
302
|
+
|
|
303
|
+
for issue in dotguard.check(env, example, strict=True):
|
|
304
|
+
print(issue.code, issue.severity.value, issue.message)
|
|
305
|
+
|
|
306
|
+
for issue in dotguard.scan(example):
|
|
307
|
+
print("possible secret:", issue.key)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## `.env` syntax supported
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
# comments on their own line
|
|
314
|
+
KEY=value
|
|
315
|
+
export KEY=value # "export" prefix is allowed
|
|
316
|
+
KEY=value # trailing comment # needs whitespace before "#"
|
|
317
|
+
URL=https://example.com/#anchor # "#" inside a value is kept
|
|
318
|
+
KEY="double \"quoted\"\nwith escapes" # \n \t \r \" \\ \$
|
|
319
|
+
KEY='single quoted, taken literally, even $HOME'
|
|
320
|
+
EMPTY=
|
|
321
|
+
|
|
322
|
+
# Quoted values can span several lines (handy for certificates):
|
|
323
|
+
CERT="-----BEGIN CERTIFICATE-----
|
|
324
|
+
MIIB...
|
|
325
|
+
-----END CERTIFICATE-----"
|
|
326
|
+
|
|
327
|
+
# References to keys defined earlier in the same file:
|
|
328
|
+
HOST=localhost
|
|
329
|
+
PORT=5432
|
|
330
|
+
DATABASE_URL=postgres://${HOST}:${PORT}/app # also $HOST
|
|
331
|
+
LOG_DIR=${LOG_ROOT:-/var/log}/app # default if unset or empty
|
|
332
|
+
LOG_FILE=${LOG_NAME-app.log} # default only if unset
|
|
333
|
+
PRICE="costs \$5" # \$ keeps a literal dollar sign
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
References work in unquoted and double-quoted values, never in single-quoted ones. A reference to
|
|
337
|
+
a key that is not defined above it expands to an empty string and `check` warns about it
|
|
338
|
+
(`DG011`). Values are never read from your shell's environment, so results are the same on every
|
|
339
|
+
machine.
|
|
340
|
+
|
|
341
|
+
Duplicate keys and malformed lines are reported with their file and line number.
|
|
342
|
+
|
|
343
|
+
## Roadmap
|
|
344
|
+
|
|
345
|
+
- [x] `${VAR}` interpolation when checking values
|
|
346
|
+
- [x] Multi-line quoted values
|
|
347
|
+
- [x] Publish to PyPI (as `dotguard-cli`)
|
|
348
|
+
- [x] `dotguard diff` to compare two environments (e.g. staging vs production keys)
|
|
349
|
+
- [ ] Optional JSON Schema export
|
|
350
|
+
|
|
351
|
+
Ideas and pull requests are welcome. See the [issues](https://github.com/K70281095/dotguard/issues).
|
|
352
|
+
|
|
353
|
+
## Contributing
|
|
354
|
+
|
|
355
|
+
Contributions of every size are welcome: bug reports, docs fixes, new secret patterns, new
|
|
356
|
+
`@type`s. Please read [CONTRIBUTING.md](CONTRIBUTING.md) and our
|
|
357
|
+
[Code of Conduct](CODE_OF_CONDUCT.md). To report a vulnerability, see [SECURITY.md](SECURITY.md).
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
[MIT](LICENSE) © 2026 Kanhaiya Kumar
|