envshield 4.7.4__tar.gz → 4.8.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.
Files changed (58) hide show
  1. {envshield-4.7.4 → envshield-4.8.0}/PKG-INFO +9 -5
  2. {envshield-4.7.4 → envshield-4.8.0}/README.md +8 -4
  3. envshield-4.8.0/envshield/__init__.py +1 -0
  4. {envshield-4.7.4 → envshield-4.8.0}/envshield/cli.py +274 -113
  5. {envshield-4.7.4 → envshield-4.8.0}/envshield/config/manager.py +452 -65
  6. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/contract_diff.py +133 -51
  7. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/dependency_diff.py +24 -3
  8. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/dependency_snapshot.py +26 -6
  9. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/discovery.py +312 -21
  10. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/doctor.py +66 -48
  11. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/enforcement.py +6 -0
  12. envshield-4.8.0/envshield/core/evaluator.py +598 -0
  13. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/exceptions.py +116 -0
  14. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/explain.py +62 -92
  15. envshield-4.8.0/envshield/core/file_updater.py +296 -0
  16. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/generator.py +31 -15
  17. envshield-4.8.0/envshield/core/hooks_manager.py +669 -0
  18. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/importer.py +15 -2
  19. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/scanner.py +187 -503
  20. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/schema_manager.py +255 -108
  21. envshield-4.8.0/envshield/core/schema_scope.py +296 -0
  22. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/schema_snapshot.py +66 -6
  23. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/schema_types.py +139 -24
  24. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/service_discovery.py +20 -7
  25. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/setup_manager.py +54 -24
  26. envshield-4.8.0/envshield/core/source_files.py +124 -0
  27. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_base.py +6 -0
  28. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_docker_compose.py +32 -13
  29. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/PKG-INFO +9 -5
  30. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/SOURCES.txt +3 -0
  31. {envshield-4.7.4 → envshield-4.8.0}/pyproject.toml +1 -1
  32. envshield-4.7.4/envshield/__init__.py +0 -1
  33. envshield-4.7.4/envshield/core/file_updater.py +0 -135
  34. envshield-4.7.4/envshield/core/hooks_manager.py +0 -216
  35. {envshield-4.7.4 → envshield-4.8.0}/LICENSE.md +0 -0
  36. {envshield-4.7.4 → envshield-4.8.0}/envshield/__main__.py +0 -0
  37. {envshield-4.7.4 → envshield-4.8.0}/envshield/classifier/__init__.py +0 -0
  38. {envshield-4.7.4 → envshield-4.8.0}/envshield/classifier/context_classifier.py +0 -0
  39. {envshield-4.7.4 → envshield-4.8.0}/envshield/classifier/tokenizer.py +0 -0
  40. {envshield-4.7.4 → envshield-4.8.0}/envshield/config/__init__.py +0 -0
  41. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/__init__.py +0 -0
  42. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/inspector.py +0 -0
  43. {envshield-4.7.4 → envshield-4.8.0}/envshield/core/service_manager.py +0 -0
  44. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/__init__.py +0 -0
  45. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_deployment.py +0 -0
  46. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_dotenv.py +0 -0
  47. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_kubernetes.py +0 -0
  48. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/_python.py +0 -0
  49. {envshield-4.7.4 → envshield-4.8.0}/envshield/parsers/factory.py +0 -0
  50. {envshield-4.7.4 → envshield-4.8.0}/envshield/state.py +0 -0
  51. {envshield-4.7.4 → envshield-4.8.0}/envshield/utils/__init__.py +0 -0
  52. {envshield-4.7.4 → envshield-4.8.0}/envshield/utils/git_utils.py +0 -0
  53. {envshield-4.7.4 → envshield-4.8.0}/envshield/utils/paths.py +0 -0
  54. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/dependency_links.txt +0 -0
  55. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/entry_points.txt +0 -0
  56. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/requires.txt +0 -0
  57. {envshield-4.7.4 → envshield-4.8.0}/envshield.egg-info/top_level.txt +0 -0
  58. {envshield-4.7.4 → envshield-4.8.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: envshield
3
- Version: 4.7.4
3
+ Version: 4.8.0
4
4
  Summary: EnvShield: environment variables as a version-controlled configuration contract.
5
5
  Author-email: Rabbil Yasar Sajal <rabbilyasar@gmail.com>
6
6
  License: MIT License
@@ -165,10 +165,11 @@ What each field actually means:
165
165
  | `enum` | Value must be one of this list. Implies an enum type regardless of `type`. |
166
166
  | `pattern` | A regex the value must also match, e.g. `pattern = "^v\\d+\\.\\d+\\.\\d+$"`. |
167
167
  | `secret` | Marks the variable sensitive — masked input in `setup`, masked in generated code. `import` auto-suggests it from the variable's name/value; it never overwrites a `secret` value you've already committed. |
168
- | `defaultValue` | What `setup` writes automatically. A variable still has to be explicitly present in your local file even with a default — `check`/`doctor` name the default inline so a missing one is obvious. |
168
+ | `defaultValue` | What `setup` writes automatically (and `.env.example` and generated code show). A default never makes a variable optional: it still has to be explicitly present in your local file — `check`/`doctor` name the default inline so a missing one is obvious. |
169
+ | `required` | Optional. `required = false` makes a variable optional: it may be absent or blank, but a value that is set must still be valid. `required = true` is the default. Can't be combined with `requiredIf`. |
169
170
  | `description` | Shown in `setup`, copied into generated code. |
170
171
 
171
- **There is no separate `required = true/false` field.** Requiredness is derived: unconditional by default, waived by a `defaultValue`, or made conditional by `requiredIf` — see below.
172
+ Requiredness: every variable is required unless `required = false`, or `requiredIf` makes it conditional (see below). Any other key, or an unknown `type`, is an error — a typo like `default = "8000"` is reported (`did you mean 'defaultValue'?`) instead of silently ignored.
172
173
 
173
174
  ### Conditional requirements (`requiredIf`)
174
175
 
@@ -210,7 +211,7 @@ Four stages, in order: define the contract, validate against it, discover what c
210
211
 
211
212
  ### Validate
212
213
 
213
- **`envshield check`** — validate local configuration, and commonly-used Docker Compose and Kubernetes deployment-manifest patterns, against the same schema (see [Known limitations](#known-limitations)).
214
+ **`envshield check`** — validate local configuration, and commonly-used Docker Compose and Kubernetes deployment-manifest patterns, against the same schema (see [Known limitations](#known-limitations)). It also scans the service's own source code and fails on a variable the code reads but the schema doesn't declare (the same files the pre-commit `scan` checks). `--process-env` also counts variables set in your shell (for a name the schema declares, the shell's value wins over the file's). `--json` adds a versioned, value-free report per service.
214
215
 
215
216
  ```bash
216
217
  $ envshield check
@@ -569,12 +570,15 @@ envshield uninstall --yes # skip the confirmation prompt
569
570
 
570
571
  ## Known limitations
571
572
 
572
- EnvShield is built around the patterns real projects actually use. A few narrower cases aren't handled yet — none of them let a secret leak or let a genuinely missing required variable pass as clean:
573
+ EnvShield is built around the patterns real projects actually use. A few narrower cases aren't handled yet. None of them let a secret leak; the first one can let a value EnvShield couldn't see pass `check`:
573
574
 
575
+ - **Unverified manifest values pass the v4 gate.** When a deployment manifest only *points* at a value — a Kubernetes `secretKeyRef`/`configMapKeyRef` to an object outside the file, a Secret key in the same file, a Compose `${VAR}` or bare `KEY`, or a `${VAR-x}`/`${VAR:-x}` fallback — EnvShield can't see the deployed value. `check` reports these variables as unverified (`valid: null`, status `not_visible`, listed in `summary.unverified`, and named in the human output), but they still pass: exit code and `success` are unchanged. A fallback that itself violates the contract still fails. Making the gate act on unverified values is planned for v5.
574
576
  - **Docker Compose:** `${VAR}`, `${VAR:-default}`, and the no-colon `${VAR-default}` form are all supported. The `${VAR:?}`/`${VAR:+}` forms and embedded/multiple interpolation references in one value aren't evaluated yet.
575
577
  - **Kubernetes:** `env[].valueFrom.secretKeyRef`/`configMapKeyRef` are matched by the container's environment-variable name (`env[].name`) — name your schema variable after the env var, not the key — and, when the referenced Secret/ConfigMap is defined in the same manifest, the referenced key is validated to actually exist there. `envFrom.prefix` is applied. `initContainers` are selectable via `--container` but never auto-selected by default.
576
578
  - **Source discovery:** Python is AST-based; JavaScript/TypeScript is pattern-based. No other language is discovered yet.
577
579
  - **.env:** multiline quoted values aren't supported.
580
+ - **Windows:** the write-safety fix for a failed permission change (BL-162) hasn't been run on Windows; where `os.fchmod` is missing (Windows before Python 3.13) it's skipped, which is tested on Linux by simulation only.
581
+ - **CI:** runs on Ubuntu only (Python 3.10–3.12).
578
582
 
579
583
  These are bounded, tracked engineering work — see the [roadmap](ROADMAP.md) for what's next and what EnvShield deliberately isn't building.
580
584
 
@@ -106,10 +106,11 @@ What each field actually means:
106
106
  | `enum` | Value must be one of this list. Implies an enum type regardless of `type`. |
107
107
  | `pattern` | A regex the value must also match, e.g. `pattern = "^v\\d+\\.\\d+\\.\\d+$"`. |
108
108
  | `secret` | Marks the variable sensitive — masked input in `setup`, masked in generated code. `import` auto-suggests it from the variable's name/value; it never overwrites a `secret` value you've already committed. |
109
- | `defaultValue` | What `setup` writes automatically. A variable still has to be explicitly present in your local file even with a default — `check`/`doctor` name the default inline so a missing one is obvious. |
109
+ | `defaultValue` | What `setup` writes automatically (and `.env.example` and generated code show). A default never makes a variable optional: it still has to be explicitly present in your local file — `check`/`doctor` name the default inline so a missing one is obvious. |
110
+ | `required` | Optional. `required = false` makes a variable optional: it may be absent or blank, but a value that is set must still be valid. `required = true` is the default. Can't be combined with `requiredIf`. |
110
111
  | `description` | Shown in `setup`, copied into generated code. |
111
112
 
112
- **There is no separate `required = true/false` field.** Requiredness is derived: unconditional by default, waived by a `defaultValue`, or made conditional by `requiredIf` — see below.
113
+ Requiredness: every variable is required unless `required = false`, or `requiredIf` makes it conditional (see below). Any other key, or an unknown `type`, is an error — a typo like `default = "8000"` is reported (`did you mean 'defaultValue'?`) instead of silently ignored.
113
114
 
114
115
  ### Conditional requirements (`requiredIf`)
115
116
 
@@ -151,7 +152,7 @@ Four stages, in order: define the contract, validate against it, discover what c
151
152
 
152
153
  ### Validate
153
154
 
154
- **`envshield check`** — validate local configuration, and commonly-used Docker Compose and Kubernetes deployment-manifest patterns, against the same schema (see [Known limitations](#known-limitations)).
155
+ **`envshield check`** — validate local configuration, and commonly-used Docker Compose and Kubernetes deployment-manifest patterns, against the same schema (see [Known limitations](#known-limitations)). It also scans the service's own source code and fails on a variable the code reads but the schema doesn't declare (the same files the pre-commit `scan` checks). `--process-env` also counts variables set in your shell (for a name the schema declares, the shell's value wins over the file's). `--json` adds a versioned, value-free report per service.
155
156
 
156
157
  ```bash
157
158
  $ envshield check
@@ -510,12 +511,15 @@ envshield uninstall --yes # skip the confirmation prompt
510
511
 
511
512
  ## Known limitations
512
513
 
513
- EnvShield is built around the patterns real projects actually use. A few narrower cases aren't handled yet — none of them let a secret leak or let a genuinely missing required variable pass as clean:
514
+ EnvShield is built around the patterns real projects actually use. A few narrower cases aren't handled yet. None of them let a secret leak; the first one can let a value EnvShield couldn't see pass `check`:
514
515
 
516
+ - **Unverified manifest values pass the v4 gate.** When a deployment manifest only *points* at a value — a Kubernetes `secretKeyRef`/`configMapKeyRef` to an object outside the file, a Secret key in the same file, a Compose `${VAR}` or bare `KEY`, or a `${VAR-x}`/`${VAR:-x}` fallback — EnvShield can't see the deployed value. `check` reports these variables as unverified (`valid: null`, status `not_visible`, listed in `summary.unverified`, and named in the human output), but they still pass: exit code and `success` are unchanged. A fallback that itself violates the contract still fails. Making the gate act on unverified values is planned for v5.
515
517
  - **Docker Compose:** `${VAR}`, `${VAR:-default}`, and the no-colon `${VAR-default}` form are all supported. The `${VAR:?}`/`${VAR:+}` forms and embedded/multiple interpolation references in one value aren't evaluated yet.
516
518
  - **Kubernetes:** `env[].valueFrom.secretKeyRef`/`configMapKeyRef` are matched by the container's environment-variable name (`env[].name`) — name your schema variable after the env var, not the key — and, when the referenced Secret/ConfigMap is defined in the same manifest, the referenced key is validated to actually exist there. `envFrom.prefix` is applied. `initContainers` are selectable via `--container` but never auto-selected by default.
517
519
  - **Source discovery:** Python is AST-based; JavaScript/TypeScript is pattern-based. No other language is discovered yet.
518
520
  - **.env:** multiline quoted values aren't supported.
521
+ - **Windows:** the write-safety fix for a failed permission change (BL-162) hasn't been run on Windows; where `os.fchmod` is missing (Windows before Python 3.13) it's skipped, which is tested on Linux by simulation only.
522
+ - **CI:** runs on Ubuntu only (Python 3.10–3.12).
519
523
 
520
524
  These are bounded, tracked engineering work — see the [roadmap](ROADMAP.md) for what's next and what EnvShield deliberately isn't building.
521
525
 
@@ -0,0 +1 @@
1
+ __version__ = "4.8.0"