@romaintaillandier1978/dotenv-never-lies 0.4.0 → 1.1.1
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.
- package/README.md +257 -239
- package/dist/cli/commands/export.d.ts +4 -3
- package/dist/cli/commands/export.d.ts.map +1 -1
- package/dist/cli/commands/export.js +105 -100
- package/dist/cli/commands/generate.d.ts +4 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/reverseEnv.d.ts.map +1 -1
- package/dist/cli/commands/reverseEnv.js +8 -2
- package/dist/cli/index.js +146 -109
- package/dist/cli/utils/infer-schema.d.ts.map +1 -1
- package/dist/cli/utils/infer-schema.js +4 -3
- package/dist/cli/utils/load-schema.d.ts.map +1 -1
- package/dist/cli/utils/load-schema.js +5 -4
- package/dist/cli/utils/printer.d.ts.map +1 -1
- package/dist/cli/utils/printer.js +5 -4
- package/dist/core.d.ts +33 -33
- package/dist/core.js +8 -8
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
# dotenv-never-lies
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Because environment variables lie all the time.
|
|
4
4
|
|
|
5
|
-
**dotenv-never-lies**
|
|
6
|
-
|
|
5
|
+
**dotenv-never-lies** validates, types, and documents your environment variables from a TypeScript / Zod schema.
|
|
6
|
+
It fails fast, loud, and before production.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Why?
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Because all of this happens all the time:
|
|
11
11
|
|
|
12
|
-
- ❌
|
|
13
|
-
- ❌
|
|
14
|
-
- ❌
|
|
15
|
-
- ❌
|
|
12
|
+
- ❌ a missing env variable → runtime crash
|
|
13
|
+
- ❌ a malformed URL → subtle production bug
|
|
14
|
+
- ❌ CI was not updated after a new variable → confusing red deployment
|
|
15
|
+
- ❌ an optimistic `process.env.FOO!` → lying to yourself
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
And because `.env` files are:
|
|
18
18
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
19
|
+
- untyped
|
|
20
|
+
- undocumented
|
|
21
|
+
- shared manually
|
|
22
|
+
- rarely up to date
|
|
23
23
|
|
|
24
|
-
👉 **dotenv-never-lies**
|
|
24
|
+
👉 **dotenv-never-lies** turns this fragile configuration into an explicit contract.
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## What the library does
|
|
29
29
|
|
|
30
|
-
- ✅
|
|
31
|
-
- ✅
|
|
32
|
-
- ✅
|
|
33
|
-
- ✅
|
|
34
|
-
- ✅
|
|
30
|
+
- ✅ validates environment variables at startup
|
|
31
|
+
- ✅ provides reliable TypeScript typings
|
|
32
|
+
- ✅ documents each variable
|
|
33
|
+
- ✅ exposes a CLI for CI and humans
|
|
34
|
+
- ✅ enables complex transformations (arrays, parsing, coercion…)
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## What dotenv-never-lies is not
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
This package has a deliberately limited scope.
|
|
41
41
|
|
|
42
|
-
- ❌ **
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
- ❌ **It is not a frontend tool**
|
|
43
|
+
It is not meant to be used in a browser.
|
|
44
|
+
No bundler, no `import.meta.env`, no variables exposed to the client.
|
|
45
45
|
|
|
46
|
-
- ❌ **
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
- ❌ **It is not a secrets manager**
|
|
47
|
+
It does not encrypt anything, does not store anything, and does not replace Vault, AWS Secrets Manager,
|
|
48
|
+
nor your CI/CD provider’s secure variables.
|
|
49
49
|
|
|
50
|
-
- ❌ **
|
|
51
|
-
|
|
52
|
-
Deno, Bun, Cloudflare Workers, edge runtimes
|
|
50
|
+
- ❌ **It is not a cross-runtime solution**
|
|
51
|
+
Targeted support: **Node.js**.
|
|
52
|
+
Deno, Bun, Cloudflare Workers, edge runtimes: out of scope (for now).
|
|
53
53
|
|
|
54
|
-
- ❌ **
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
- ❌ **It is not a global configuration framework**
|
|
55
|
+
It does not manage YAML/JSON files, dynamic profiles,
|
|
56
|
+
nor magical per-environment overrides.
|
|
57
57
|
|
|
58
|
-
- ❌ **
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
- ❌ **It is not permissive**
|
|
59
|
+
If a variable is missing or a value is invalid, it crashes.
|
|
60
|
+
That’s the point.
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
**dotenv-never-lies**
|
|
64
|
-
|
|
62
|
+
In short:
|
|
63
|
+
**dotenv-never-lies** is for **Node.js APIs** and **backend services**
|
|
64
|
+
that prefer to **fail cleanly at startup** rather than **silently break in production**.
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
@@ -69,22 +69,22 @@ qui préfèrent **échouer proprement au démarrage** plutôt que **bugger silen
|
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
npm install @romaintaillandier1978/dotenv-never-lies
|
|
72
|
-
#
|
|
72
|
+
# or
|
|
73
73
|
yarn add @romaintaillandier1978/dotenv-never-lies
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## Dependencies and compatibility
|
|
77
77
|
|
|
78
|
-
**[`zod`](https://www.npmjs.com/package/zod)
|
|
78
|
+
**[`zod`](https://www.npmjs.com/package/zod)** — dotenv-never-lies exposes Zod schemas in its public API.
|
|
79
79
|
|
|
80
|
-
⚠️
|
|
81
|
-
|
|
80
|
+
⚠️ Important: Zod **v4.2.1** minimum is required.
|
|
81
|
+
Using Zod v3 will cause typing or inference errors.
|
|
82
82
|
|
|
83
|
-
**[`dotenv`](https://www.npmjs.com/package/dotenv)**
|
|
83
|
+
**[`dotenv`](https://www.npmjs.com/package/dotenv)** allows dotenv-never-lies to automatically handle parsing of env files.
|
|
84
84
|
|
|
85
|
-
**[`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand)**
|
|
85
|
+
**[`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand)** allows dotenv-never-lies to automatically handle environment variable expansion. This lets you define variables composed from other variables without duplication or fragile copy-paste.
|
|
86
86
|
|
|
87
|
-
**
|
|
87
|
+
**Example**
|
|
88
88
|
|
|
89
89
|
```env
|
|
90
90
|
FRONT_A=https://a.site.com
|
|
@@ -94,20 +94,20 @@ FRONT_C=https://c.site.com
|
|
|
94
94
|
NODE_CORS_ORIGIN="${FRONT_A};${FRONT_B};${FRONT_C}"
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
##
|
|
97
|
+
## DNL schema
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
The DNL schema is your new source of truth.
|
|
100
100
|
|
|
101
|
-
(`dnl reverse-env`
|
|
101
|
+
(`dnl reverse-env` will help you scaffold the first skeleton)
|
|
102
102
|
|
|
103
|
-
###
|
|
103
|
+
### schema location
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
Recommended: `env.dnl.ts`
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
Supported in this order for all CLI commands:
|
|
108
108
|
|
|
109
|
-
1.
|
|
110
|
-
2.
|
|
109
|
+
1. `--schema path/to/my-dnl.ts`
|
|
110
|
+
2. declared in `package.json`:
|
|
111
111
|
|
|
112
112
|
```json
|
|
113
113
|
{
|
|
@@ -119,9 +119,9 @@ Supporté dans cet ordre pour toutes les commandes CLI :
|
|
|
119
119
|
}
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
3.
|
|
122
|
+
3. one of `env.dnl.ts`, `env.dnl.js`, `dnl.config.ts`, `dnl.config.js`
|
|
123
123
|
|
|
124
|
-
###
|
|
124
|
+
### define a schema
|
|
125
125
|
|
|
126
126
|
```typescript
|
|
127
127
|
import { z } from "zod";
|
|
@@ -129,17 +129,17 @@ import { define } from "@romaintaillandier1978/dotenv-never-lies";
|
|
|
129
129
|
|
|
130
130
|
export default define({
|
|
131
131
|
NODE_ENV: {
|
|
132
|
-
description: "
|
|
132
|
+
description: "Runtime environment",
|
|
133
133
|
schema: z.enum(["test", "development", "staging", "production"]),
|
|
134
134
|
},
|
|
135
135
|
|
|
136
136
|
NODE_PORT: {
|
|
137
|
-
description: "
|
|
137
|
+
description: "API port",
|
|
138
138
|
schema: z.coerce.number().default(3000),
|
|
139
139
|
},
|
|
140
140
|
|
|
141
141
|
FRONT_URL: {
|
|
142
|
-
description: "
|
|
142
|
+
description: "My website",
|
|
143
143
|
schema: z.url(),
|
|
144
144
|
},
|
|
145
145
|
|
|
@@ -151,51 +151,71 @@ export default define({
|
|
|
151
151
|
});
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
##
|
|
154
|
+
## Secrets handling
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
Reminder: dotenv-never-lies is not a secrets manager.
|
|
157
157
|
|
|
158
|
-
###
|
|
158
|
+
### declaration in the DNL schema
|
|
159
159
|
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
A variable is considered secret if and only if it is explicitly marked in the schema with `secret: true`.
|
|
161
|
+
(`secret: undefined` is equivalent to `secret: false`)
|
|
162
|
+
This rule is intentionally strict.
|
|
162
163
|
|
|
163
164
|
```ts
|
|
164
165
|
JWT_SECRET: {
|
|
165
|
-
description: "
|
|
166
|
+
description: "JWT signing key",
|
|
166
167
|
schema: z.string(),
|
|
167
168
|
secret: true,
|
|
168
169
|
}
|
|
169
170
|
```
|
|
170
171
|
|
|
171
|
-
### Secrets
|
|
172
|
+
### Secrets and CLI commands
|
|
172
173
|
|
|
173
|
-
assert
|
|
174
|
+
assert: validates secrets like any other variable
|
|
174
175
|
|
|
175
|
-
reverse-env
|
|
176
|
-
**
|
|
176
|
+
reverse-env: when generating the schema, with `--guess-secret` option, the command tries to automatically identify sensitive variables (e.g. SECRET, KEY, TOKEN, PASSWORD).
|
|
177
|
+
**This detection is heuristic and must always be reviewed and corrected manually.**
|
|
177
178
|
|
|
178
|
-
export
|
|
179
|
+
export: adapts behavior depending on the target format (env, docker, CI, Kubernetes…). See the table below for details by format.
|
|
179
180
|
|
|
180
|
-
###
|
|
181
|
+
### During export
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
Variables marked `secret: true` in the schema are treated differently depending on the export format.
|
|
183
184
|
|
|
184
|
-
| Format | Secrets
|
|
185
|
-
| ------------- |
|
|
186
|
-
| env |
|
|
187
|
-
| docker-env |
|
|
188
|
-
| docker-args |
|
|
189
|
-
| json |
|
|
190
|
-
| ts |
|
|
191
|
-
| js |
|
|
192
|
-
| github-env |
|
|
193
|
-
| github-secret | secrets
|
|
194
|
-
| gitlab-env |
|
|
195
|
-
| k8s-configmap |
|
|
196
|
-
| k8s-secret | secrets
|
|
185
|
+
| Format | Secrets included by default | Maskable (`--hide-secret`) | Excludable (`--exclude-secret`) | Notes |
|
|
186
|
+
| ------------- | --------------------------- | -------------------------- | ------------------------------- | -------------------------- |
|
|
187
|
+
| env | yes | yes | yes | classic .env |
|
|
188
|
+
| docker-env | yes | yes | yes | For --env-file |
|
|
189
|
+
| docker-args | yes | yes | yes | For docker run -e |
|
|
190
|
+
| json | yes | yes | yes | Debug / tooling |
|
|
191
|
+
| ts | yes | yes | yes | Typed export |
|
|
192
|
+
| js | yes | yes | yes | Runtime export |
|
|
193
|
+
| github-env | yes | yes | yes | visible in logs |
|
|
194
|
+
| github-secret | secrets only | no | yes | Via gh secret set |
|
|
195
|
+
| gitlab-env | yes | yes | yes | GitLab CI variables |
|
|
196
|
+
| k8s-configmap | yes | yes | yes | warning if secret unmasked |
|
|
197
|
+
| k8s-secret | secrets only | yes | yes | Kubernetes Secret |
|
|
197
198
|
|
|
198
|
-
##
|
|
199
|
+
## Variable lifecycle
|
|
200
|
+
|
|
201
|
+
dotenv-never-lies works with three distinct representations of environment variables:
|
|
202
|
+
|
|
203
|
+
1. **Raw value**
|
|
204
|
+
The original value coming from the source (`.env` file or `process.env`).
|
|
205
|
+
Always a string (or undefined).
|
|
206
|
+
|
|
207
|
+
2. **Runtime value (validated)**
|
|
208
|
+
The value after validation — and possible transformation — by the Zod schema.
|
|
209
|
+
This value may be strongly typed (number, boolean, array, object, etc.).
|
|
210
|
+
|
|
211
|
+
3. **Exported value**
|
|
212
|
+
The value written by `dnl export`.
|
|
213
|
+
- For env-like formats (`env`, `docker-*`, `github-*`, `k8s-*`), this is the **raw value**, after validation.
|
|
214
|
+
- For `js`, `ts` and `json`, the runtime value can be exported using `--serialize-typed`.
|
|
215
|
+
|
|
216
|
+
This separation ensures that validation, runtime usage and configuration export remain explicit and predictable.
|
|
217
|
+
|
|
218
|
+
## Runtime usage
|
|
199
219
|
|
|
200
220
|
```typescript
|
|
201
221
|
import envDef from "./env.dnl";
|
|
@@ -214,204 +234,202 @@ server.listen(ENV.NODE_PORT, () => {
|
|
|
214
234
|
});
|
|
215
235
|
```
|
|
216
236
|
|
|
217
|
-
|
|
237
|
+
Result:
|
|
218
238
|
|
|
219
|
-
- ENV.NODE_ENV
|
|
220
|
-
- ENV.NODE_PORT
|
|
221
|
-
- FRONT_URL
|
|
222
|
-
- ENV.JWT_SECRET
|
|
239
|
+
- `ENV.NODE_ENV` is an enum
|
|
240
|
+
- `ENV.NODE_PORT` is a number
|
|
241
|
+
- `FRONT_URL` is a valid URL
|
|
242
|
+
- `ENV.JWT_SECRET` is a string
|
|
223
243
|
|
|
224
|
-
|
|
225
|
-
|
|
244
|
+
If a variable is missing or invalid → the process exits immediately.
|
|
245
|
+
This is intentional.
|
|
226
246
|
|
|
227
|
-
##
|
|
247
|
+
## Avoid `process.env` in application code
|
|
228
248
|
|
|
229
|
-
|
|
230
|
-
|
|
249
|
+
Once the schema is loaded, environment variables
|
|
250
|
+
must be accessed exclusively via the `ENV` object.
|
|
231
251
|
|
|
232
|
-
|
|
252
|
+
This guarantees:
|
|
233
253
|
|
|
234
|
-
-
|
|
235
|
-
-
|
|
236
|
-
-
|
|
254
|
+
- strict typing
|
|
255
|
+
- validated values
|
|
256
|
+
- a single entry point for configuration
|
|
237
257
|
|
|
238
|
-
|
|
258
|
+
To identify residual `process.env` usages in your codebase, a simple search tool is enough:
|
|
239
259
|
|
|
240
260
|
```bash
|
|
241
261
|
grep -R "process\.env" src
|
|
242
262
|
```
|
|
243
263
|
|
|
244
|
-
|
|
264
|
+
Choosing to refactor (or not) those usages depends on context and is intentionally left to the developer.
|
|
245
265
|
|
|
246
266
|
## CLI
|
|
247
267
|
|
|
248
|
-
|
|
268
|
+
The CLI lets you validate, load, generate, export, and document environment variables from a `dotenv-never-lies` schema.
|
|
249
269
|
|
|
250
|
-
|
|
270
|
+
It is designed to be used:
|
|
251
271
|
|
|
252
|
-
-
|
|
253
|
-
-
|
|
254
|
-
-
|
|
272
|
+
- locally (by humans)
|
|
273
|
+
- in CI (without surprises)
|
|
274
|
+
- before the application starts (not after)
|
|
255
275
|
|
|
256
276
|
### Exit codes
|
|
257
277
|
|
|
258
|
-
`dotenv-never-lies`
|
|
278
|
+
`dotenv-never-lies` uses explicit exit codes, designed for CI:
|
|
259
279
|
|
|
260
|
-
| Code |
|
|
261
|
-
| ---: |
|
|
262
|
-
| 0 |
|
|
263
|
-
| 1 |
|
|
264
|
-
| 2 |
|
|
265
|
-
| 3 |
|
|
266
|
-
| 4 |
|
|
280
|
+
| Code | Meaning |
|
|
281
|
+
| ---: | ----------------------------- |
|
|
282
|
+
| 0 | Success |
|
|
283
|
+
| 1 | Usage error or internal error |
|
|
284
|
+
| 2 | DNL schema not found |
|
|
285
|
+
| 3 | Environment validation failed |
|
|
286
|
+
| 4 | Error during export |
|
|
267
287
|
|
|
268
|
-
### assert
|
|
288
|
+
### assert: Validate a `.env` file (CI-friendly)
|
|
269
289
|
|
|
270
|
-
|
|
290
|
+
Validates variables without injecting them into `process.env`.
|
|
271
291
|
|
|
272
292
|
```bash
|
|
273
293
|
dnl assert --source .env --schema env.dnl.ts
|
|
274
294
|
```
|
|
275
295
|
|
|
276
|
-
|
|
277
|
-
|
|
296
|
+
Without `--source`, `dnl assert` validates `process.env`.
|
|
297
|
+
This is the recommended mode when variables are injected by the runtime or CI.
|
|
278
298
|
|
|
279
|
-
→
|
|
299
|
+
→ fails if:
|
|
280
300
|
|
|
281
|
-
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
301
|
+
- a variable is missing
|
|
302
|
+
- a value is invalid
|
|
303
|
+
- the schema is not respected
|
|
284
304
|
|
|
285
|
-
### generate
|
|
305
|
+
### generate: Generate a .env file from the schema
|
|
286
306
|
|
|
287
|
-
|
|
307
|
+
Generates a documented `.env` from the schema.
|
|
288
308
|
|
|
289
309
|
```bash
|
|
290
310
|
dnl generate --schema env.dnl.ts --out .env
|
|
291
311
|
```
|
|
292
312
|
|
|
293
|
-
|
|
313
|
+
Useful for:
|
|
294
314
|
|
|
295
|
-
-
|
|
296
|
-
-
|
|
297
|
-
-
|
|
315
|
+
- bootstrapping a project
|
|
316
|
+
- sharing a template
|
|
317
|
+
- avoiding obsolete `.env.example` files
|
|
298
318
|
|
|
299
|
-
### reverse-env
|
|
319
|
+
### reverse-env: Generate a schema from an existing .env
|
|
300
320
|
|
|
301
|
-
|
|
321
|
+
Creates an `env.dnl.ts` file from a `.env`.
|
|
302
322
|
|
|
303
323
|
```bash
|
|
304
324
|
dnl reverse-env --source .env
|
|
305
325
|
```
|
|
306
326
|
|
|
307
|
-
|
|
327
|
+
Useful for:
|
|
308
328
|
|
|
309
|
-
-
|
|
310
|
-
-
|
|
329
|
+
- migrating an existing project
|
|
330
|
+
- documenting a legacy configuration afterwards
|
|
311
331
|
|
|
312
|
-
### explain
|
|
332
|
+
### explain: Display variables documentation
|
|
313
333
|
|
|
314
|
-
|
|
334
|
+
Displays the list of known variables and their description.
|
|
315
335
|
|
|
316
336
|
```bash
|
|
317
337
|
dnl explain
|
|
318
338
|
```
|
|
319
339
|
|
|
320
|
-
|
|
340
|
+
Sample output:
|
|
321
341
|
|
|
322
342
|
```bash
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
NODE_CORS_ORIGIN: URLs frontend autorisées à appeler cette API
|
|
343
|
+
NODE_ENV: Runtime environment
|
|
344
|
+
NODE_PORT: API port
|
|
345
|
+
FRONT_URL: My website
|
|
327
346
|
JWT_SECRET: JWT Secret
|
|
328
|
-
|
|
329
347
|
```
|
|
330
348
|
|
|
331
|
-
### export
|
|
349
|
+
### export: Export variables to other formats
|
|
332
350
|
|
|
333
|
-
|
|
334
|
-
|
|
351
|
+
The `export` command transforms variables validated by the schema
|
|
352
|
+
into formats directly consumable by other tools (Docker, CI, Kubernetes, scripts…).
|
|
335
353
|
|
|
336
|
-
|
|
337
|
-
|
|
354
|
+
The schema remains the source of truth.
|
|
355
|
+
Values are validated before export.
|
|
338
356
|
|
|
339
357
|
```bash
|
|
340
358
|
dnl export <format>
|
|
341
359
|
```
|
|
342
360
|
|
|
343
|
-
|
|
344
|
-
|
|
361
|
+
By default, values are read from `process.env`.
|
|
362
|
+
A `.env` file can be provided via `--source`.
|
|
345
363
|
|
|
346
|
-
|
|
347
|
-
|
|
364
|
+
Examples:
|
|
365
|
+
Export environment variables as JSON from a `.env` file
|
|
348
366
|
|
|
349
367
|
```bash
|
|
350
368
|
dnl export json --source .env
|
|
351
369
|
```
|
|
352
370
|
|
|
353
|
-
|
|
371
|
+
Clean a `.env` file (remove comments and extraneous lines)
|
|
354
372
|
|
|
355
373
|
```bash
|
|
356
374
|
dnl export env --source .env --out .env.clean
|
|
357
375
|
dnl export env --source .env --out .env --force
|
|
358
376
|
```
|
|
359
377
|
|
|
360
|
-
|
|
378
|
+
Export variables as `docker-args`
|
|
361
379
|
|
|
362
380
|
```bash
|
|
363
381
|
dnl export docker-args --source .env
|
|
364
382
|
```
|
|
365
383
|
|
|
366
|
-
|
|
384
|
+
Result:
|
|
367
385
|
|
|
368
386
|
```bash
|
|
369
387
|
-e "NODE_ENV=production" -e "NODE_PORT=3000"
|
|
370
388
|
```
|
|
371
389
|
|
|
372
|
-
|
|
390
|
+
Export for GitHub Actions (variables)
|
|
373
391
|
|
|
374
392
|
```bash
|
|
375
393
|
dnl export github-env
|
|
376
394
|
```
|
|
377
395
|
|
|
378
|
-
|
|
396
|
+
Result:
|
|
379
397
|
|
|
380
398
|
```bash
|
|
381
|
-
|
|
382
|
-
|
|
399
|
+
printf '%s\n' "NODE_ENV=production" >> $GITHUB_ENV
|
|
400
|
+
printf '%s\n' "NODE_PORT=3000" >> $GITHUB_ENV
|
|
383
401
|
```
|
|
384
402
|
|
|
385
|
-
|
|
403
|
+
There are a few more formats and options (see CLI docs `dnl export --help`).
|
|
386
404
|
|
|
387
|
-
##
|
|
405
|
+
## Real-life usage
|
|
388
406
|
|
|
389
407
|
### GitIgnore
|
|
390
408
|
|
|
391
|
-
dotenv-never-lies
|
|
392
|
-
|
|
409
|
+
dotenv-never-lies creates temporary files in your project directory.
|
|
410
|
+
Add `.dnl/` to your `.gitignore`.
|
|
393
411
|
|
|
394
412
|
### Git
|
|
395
413
|
|
|
396
|
-
#### Git hooks
|
|
414
|
+
#### Recommended Git hooks
|
|
397
415
|
|
|
398
|
-
|
|
416
|
+
Using **dotenv-never-lies** via Git hooks is strongly recommended:
|
|
399
417
|
|
|
400
|
-
- **pre-commit
|
|
401
|
-
- **post-merge
|
|
418
|
+
- **pre-commit**: prevents committing if the local configuration is not compliant with the schema
|
|
419
|
+
- **post-merge**: immediately detects schema changes impacting the local environment
|
|
402
420
|
|
|
403
|
-
|
|
404
|
-
**
|
|
421
|
+
The goal is simple:
|
|
422
|
+
**if the local configuration is not compliant with the schema, code must not be committed.**
|
|
405
423
|
|
|
406
|
-
|
|
424
|
+
The schema is the source of truth, not `.env` files.
|
|
407
425
|
|
|
408
|
-
|
|
426
|
+
These hooks help avoid classic mistakes:
|
|
409
427
|
|
|
410
|
-
- variable
|
|
411
|
-
- format
|
|
412
|
-
-
|
|
428
|
+
- missing variable after a pull
|
|
429
|
+
- invalid format detected too late
|
|
430
|
+
- “works on my machine” due to an outdated `.env`
|
|
413
431
|
|
|
414
|
-
####
|
|
432
|
+
#### Hooks installation
|
|
415
433
|
|
|
416
434
|
```bash
|
|
417
435
|
git config core.hooksPath .githooks
|
|
@@ -430,9 +448,9 @@ EOF
|
|
|
430
448
|
chmod +x .githooks/pre-commit .githooks/post-merge
|
|
431
449
|
```
|
|
432
450
|
|
|
433
|
-
###
|
|
451
|
+
### GitLab CI
|
|
434
452
|
|
|
435
|
-
|
|
453
|
+
Environment variables validation step.
|
|
436
454
|
|
|
437
455
|
```yaml
|
|
438
456
|
# .gitlab-ci.yml
|
|
@@ -466,11 +484,11 @@ jobs:
|
|
|
466
484
|
- run: corepack enable
|
|
467
485
|
- run: yarn install --frozen-lockfile
|
|
468
486
|
|
|
469
|
-
#
|
|
487
|
+
# Example with a .env file provided by a secret
|
|
470
488
|
- run: yarn dnl assert --source .env
|
|
471
489
|
```
|
|
472
490
|
|
|
473
|
-
|
|
491
|
+
The `.env` file can be generated from a GitHub secret or mounted dynamically.
|
|
474
492
|
|
|
475
493
|
```yaml
|
|
476
494
|
- run: echo "$ENV_FILE_CONTENT" > .env
|
|
@@ -478,101 +496,101 @@ Le fichier .env peut être généré à partir d’un secret GitHub ou monté dy
|
|
|
478
496
|
ENV_FILE_CONTENT: ${{ secrets.ENV_FILE }}
|
|
479
497
|
```
|
|
480
498
|
|
|
481
|
-
###
|
|
499
|
+
### Which commands should I use?
|
|
482
500
|
|
|
483
|
-
|
|
|
484
|
-
|
|
|
485
|
-
|
|
|
486
|
-
|
|
|
487
|
-
|
|
|
488
|
-
|
|
|
489
|
-
|
|
|
490
|
-
|
|
|
491
|
-
|
|
|
492
|
-
|
|
|
493
|
-
|
|
|
501
|
+
| Situation | Command to use |
|
|
502
|
+
| --------------------------------------: | ------------------------------ |
|
|
503
|
+
| New project | generate |
|
|
504
|
+
| Existing project with a .env | reverse-env |
|
|
505
|
+
| Validate configuration in CI | assert |
|
|
506
|
+
| Validate config injected by the runtime | assert |
|
|
507
|
+
| Document variables | explain |
|
|
508
|
+
| Generate a clean .env | export env |
|
|
509
|
+
| Prepare a Docker build | export docker-\* |
|
|
510
|
+
| Inject variables in CI | export github-env / gitlab-env |
|
|
511
|
+
| Kubernetes (ConfigMap / Secret) | export k8s-\* |
|
|
494
512
|
|
|
495
|
-
|
|
513
|
+
Simple rule:
|
|
496
514
|
|
|
497
|
-
>
|
|
498
|
-
>
|
|
515
|
+
> The schema is always the source of truth.
|
|
516
|
+
> Commands only validate, document, or transform.
|
|
499
517
|
|
|
500
|
-
## FAQ /
|
|
518
|
+
## FAQ / Design choices
|
|
501
519
|
|
|
502
|
-
###
|
|
520
|
+
### Why so strict?
|
|
503
521
|
|
|
504
|
-
|
|
522
|
+
Because configuration errors are bugs, not warnings.
|
|
505
523
|
|
|
506
|
-
|
|
524
|
+
If a variable is missing or invalid:
|
|
507
525
|
|
|
508
|
-
-
|
|
509
|
-
-
|
|
526
|
+
- the application must not start
|
|
527
|
+
- the error must be immediate and explicit
|
|
510
528
|
|
|
511
|
-
|
|
529
|
+
Tolerating an invalid config is just moving the bug to production.
|
|
512
530
|
|
|
513
|
-
###
|
|
531
|
+
### Why Node.js only?
|
|
514
532
|
|
|
515
|
-
|
|
533
|
+
Because the target runtime is clear:
|
|
516
534
|
|
|
517
535
|
- APIs
|
|
518
536
|
- workers
|
|
519
537
|
- jobs
|
|
520
538
|
- CI
|
|
521
539
|
|
|
522
|
-
|
|
540
|
+
Edge runtimes (Deno, Bun, Cloudflare Workers…) have:
|
|
523
541
|
|
|
524
|
-
-
|
|
525
|
-
-
|
|
526
|
-
-
|
|
542
|
+
- different environment models
|
|
543
|
+
- different constraints
|
|
544
|
+
- different expectations
|
|
527
545
|
|
|
528
|
-
|
|
546
|
+
They are deliberately out of scope.
|
|
529
547
|
|
|
530
|
-
###
|
|
548
|
+
### Why Zod?
|
|
531
549
|
|
|
532
|
-
|
|
550
|
+
Because Zod provides:
|
|
533
551
|
|
|
534
|
-
-
|
|
535
|
-
-
|
|
536
|
-
-
|
|
552
|
+
- reliable TypeScript typing
|
|
553
|
+
- consistent runtime validation
|
|
554
|
+
- expressive transformations
|
|
537
555
|
|
|
538
|
-
|
|
556
|
+
The schema is both:
|
|
539
557
|
|
|
540
558
|
- documentation
|
|
541
|
-
-
|
|
559
|
+
- contract
|
|
542
560
|
- validation
|
|
543
|
-
- source
|
|
561
|
+
- typing source
|
|
544
562
|
|
|
545
|
-
|
|
563
|
+
No other tool covers these four points as cleanly today.
|
|
546
564
|
|
|
547
|
-
###
|
|
565
|
+
### Why not use dotenv-safe / env-schema / others?
|
|
548
566
|
|
|
549
|
-
|
|
567
|
+
These tools:
|
|
550
568
|
|
|
551
|
-
-
|
|
552
|
-
-
|
|
553
|
-
-
|
|
554
|
-
-
|
|
569
|
+
- partially validate
|
|
570
|
+
- provide little or weak typing
|
|
571
|
+
- do not really document
|
|
572
|
+
- do not offer a coherent CLI
|
|
555
573
|
|
|
556
|
-
dotenv-never-lies
|
|
557
|
-
|
|
558
|
-
|
|
574
|
+
dotenv-never-lies assumes a stricter scope,
|
|
575
|
+
but provides a full chain:
|
|
576
|
+
schema → validation → typing → CI → export.
|
|
559
577
|
|
|
560
|
-
###
|
|
578
|
+
### Why not manage secrets?
|
|
561
579
|
|
|
562
|
-
|
|
580
|
+
Because it is not the right level.
|
|
563
581
|
|
|
564
|
-
dotenv-never-lies
|
|
582
|
+
dotenv-never-lies:
|
|
565
583
|
|
|
566
|
-
-
|
|
567
|
-
-
|
|
584
|
+
- identifies secrets
|
|
585
|
+
- can exclude, mask, or export them
|
|
568
586
|
|
|
569
|
-
|
|
587
|
+
But it:
|
|
570
588
|
|
|
571
|
-
-
|
|
572
|
-
-
|
|
589
|
+
- encrypts nothing
|
|
590
|
+
- stores nothing
|
|
573
591
|
|
|
574
|
-
|
|
592
|
+
It integrates with existing tools; it does not compete with them.
|
|
575
593
|
|
|
576
|
-
# Conclusion
|
|
594
|
+
# Conclusion:
|
|
577
595
|
|
|
578
|
-
> dotenv-never-lies
|
|
596
|
+
> dotenv-never-lies does not aim to be flexible. It aims to be reliable, explicit, and predictable.
|