@claude-agent/envcheck 1.5.0 → 1.5.2
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 +27 -2
- package/package.json +18 -4
- package/types/index.d.ts +431 -0
package/README.md
CHANGED
|
@@ -3,10 +3,29 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@claude-agent/envcheck)
|
|
4
4
|
[](https://www.npmjs.com/package/@claude-agent/envcheck)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
6
8
|
|
|
7
|
-
> Validate
|
|
9
|
+
> **Static environment validation for CI/CD and monorepos.** Validate `.env` files against `.env.example`, detect secrets, check types - all before your app runs.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## The Problem
|
|
12
|
+
|
|
13
|
+
You've seen this before:
|
|
14
|
+
- "It works on my machine" → missing env var in production
|
|
15
|
+
- Deployment fails → forgot to add new API key
|
|
16
|
+
- Secret leaked → accidentally committed real credentials
|
|
17
|
+
- Monorepo chaos → different apps have inconsistent env configs
|
|
18
|
+
|
|
19
|
+
**envcheck catches these issues in CI/CD, before they reach production.**
|
|
20
|
+
|
|
21
|
+
## Key Features
|
|
22
|
+
|
|
23
|
+
- **Shift-left validation** - Catch missing vars before deployment, not at runtime
|
|
24
|
+
- **Monorepo support** - Scan all apps/packages with one command (`envcheck monorepo`)
|
|
25
|
+
- **Secret detection** - Warns about AWS keys, GitHub tokens, Stripe keys in your .env
|
|
26
|
+
- **Type validation** - Validate URLs, ports, emails, JSON without running your app
|
|
27
|
+
- **GitHub Action** - Drop-in CI/CD integration
|
|
28
|
+
- **Zero dependencies** - Fast install, minimal footprint
|
|
10
29
|
|
|
11
30
|
**Built autonomously by [Claude](https://claude.ai)** - an AI assistant by Anthropic.
|
|
12
31
|
|
|
@@ -459,8 +478,14 @@ WITH_EQUALS=postgres://user:pass@host/db?opt=val
|
|
|
459
478
|
- **CI-friendly** - Exit codes and JSON output
|
|
460
479
|
- **Comprehensive** - Parse, validate, compare, generate
|
|
461
480
|
- **Monorepo support** - Scan all apps/packages in one command
|
|
481
|
+
- **TypeScript support** - Full type definitions included
|
|
462
482
|
- **Well-tested** - 87 tests covering edge cases
|
|
463
483
|
|
|
484
|
+
## Examples
|
|
485
|
+
|
|
486
|
+
See the [examples directory](./examples) for complete demos:
|
|
487
|
+
- [Monorepo Demo](./examples/monorepo-demo) - Demonstrates scanning a full monorepo structure
|
|
488
|
+
|
|
464
489
|
## vs. dotenv-safe / envalid / dotenv-mono
|
|
465
490
|
|
|
466
491
|
| Feature | envcheck | dotenv-safe | envalid | dotenv-mono |
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-agent/envcheck",
|
|
3
|
-
"version": "1.5.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.5.2",
|
|
4
|
+
"description": "Static .env validation for CI/CD and monorepos. Validate against .env.example, detect secrets, check types - before deployment.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"types": "types/index.d.ts",
|
|
6
7
|
"bin": {
|
|
7
8
|
"envcheck": "bin/cli.js"
|
|
8
9
|
},
|
|
@@ -15,17 +16,26 @@
|
|
|
15
16
|
"environment",
|
|
16
17
|
"variables",
|
|
17
18
|
"validate",
|
|
19
|
+
"validation",
|
|
18
20
|
"lint",
|
|
21
|
+
"linter",
|
|
19
22
|
"cli",
|
|
20
23
|
"github-action",
|
|
21
24
|
"ci-cd",
|
|
25
|
+
"cicd",
|
|
22
26
|
"pre-commit",
|
|
23
27
|
"git-hooks",
|
|
24
28
|
"secrets",
|
|
25
29
|
"security",
|
|
26
30
|
"monorepo",
|
|
27
31
|
"turborepo",
|
|
28
|
-
"
|
|
32
|
+
"nx",
|
|
33
|
+
"lerna",
|
|
34
|
+
"workspaces",
|
|
35
|
+
"static-analysis",
|
|
36
|
+
"type-validation",
|
|
37
|
+
"envfile",
|
|
38
|
+
"config"
|
|
29
39
|
],
|
|
30
40
|
"author": "Claude Agent <claude-agent@agentmail.to>",
|
|
31
41
|
"license": "MIT",
|
|
@@ -43,6 +53,10 @@
|
|
|
43
53
|
"files": [
|
|
44
54
|
"src/",
|
|
45
55
|
"bin/",
|
|
56
|
+
"types/",
|
|
46
57
|
"pre-commit-hook.sh"
|
|
47
|
-
]
|
|
58
|
+
],
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"typescript": "^5.9.3"
|
|
61
|
+
}
|
|
48
62
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for @claude-agent/envcheck
|
|
3
|
+
* Static environment variable validation for Node.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Basic Types
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Validation type names supported by envcheck
|
|
12
|
+
*/
|
|
13
|
+
export type ValidationType =
|
|
14
|
+
| 'url'
|
|
15
|
+
| 'port'
|
|
16
|
+
| 'boolean'
|
|
17
|
+
| 'bool'
|
|
18
|
+
| 'email'
|
|
19
|
+
| 'number'
|
|
20
|
+
| 'integer'
|
|
21
|
+
| 'int'
|
|
22
|
+
| 'string'
|
|
23
|
+
| 'str'
|
|
24
|
+
| 'json'
|
|
25
|
+
| 'uuid';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Issue severity level
|
|
29
|
+
*/
|
|
30
|
+
export type IssueType = 'error' | 'warning';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Issue found during validation
|
|
34
|
+
*/
|
|
35
|
+
export interface Issue {
|
|
36
|
+
type: IssueType;
|
|
37
|
+
message: string;
|
|
38
|
+
line?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Result of type validation
|
|
43
|
+
*/
|
|
44
|
+
export interface TypeValidationResult {
|
|
45
|
+
valid: boolean;
|
|
46
|
+
message?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Type validator function
|
|
51
|
+
*/
|
|
52
|
+
export type TypeValidator = (value: string) => TypeValidationResult;
|
|
53
|
+
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Parse Types
|
|
56
|
+
// ============================================================================
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Result of parsing a .env file
|
|
60
|
+
*/
|
|
61
|
+
export interface ParseResult {
|
|
62
|
+
variables: Record<string, string>;
|
|
63
|
+
errors: Array<{
|
|
64
|
+
line: number;
|
|
65
|
+
message: string;
|
|
66
|
+
content: string;
|
|
67
|
+
}>;
|
|
68
|
+
warnings: Array<{
|
|
69
|
+
line: number;
|
|
70
|
+
message: string;
|
|
71
|
+
content: string;
|
|
72
|
+
}>;
|
|
73
|
+
lineInfo: Record<string, number>;
|
|
74
|
+
typeHints: Record<string, string>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Result of reading an env file
|
|
79
|
+
*/
|
|
80
|
+
export interface EnvFileResult extends ParseResult {
|
|
81
|
+
exists: boolean;
|
|
82
|
+
path: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ============================================================================
|
|
86
|
+
// Compare Types
|
|
87
|
+
// ============================================================================
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Item missing from env file
|
|
91
|
+
*/
|
|
92
|
+
export interface MissingItem {
|
|
93
|
+
key: string;
|
|
94
|
+
exampleValue: string;
|
|
95
|
+
line: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Extra item in env file
|
|
100
|
+
*/
|
|
101
|
+
export interface ExtraItem {
|
|
102
|
+
key: string;
|
|
103
|
+
value: string;
|
|
104
|
+
line: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Empty item in env file
|
|
109
|
+
*/
|
|
110
|
+
export interface EmptyItem {
|
|
111
|
+
key: string;
|
|
112
|
+
line: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Result of comparing two env files
|
|
117
|
+
*/
|
|
118
|
+
export interface CompareResult {
|
|
119
|
+
env: EnvFileResult;
|
|
120
|
+
example: EnvFileResult;
|
|
121
|
+
missing: MissingItem[];
|
|
122
|
+
extra: ExtraItem[];
|
|
123
|
+
empty: EmptyItem[];
|
|
124
|
+
different: Array<{
|
|
125
|
+
key: string;
|
|
126
|
+
envValue: string;
|
|
127
|
+
exampleValue: string;
|
|
128
|
+
}>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ============================================================================
|
|
132
|
+
// Validate Types
|
|
133
|
+
// ============================================================================
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Options for validate function
|
|
137
|
+
*/
|
|
138
|
+
export interface ValidateOptions {
|
|
139
|
+
/** List of required variable names */
|
|
140
|
+
required?: string[];
|
|
141
|
+
/** Warn on empty values */
|
|
142
|
+
noEmpty?: boolean;
|
|
143
|
+
/** Type specifications for variables */
|
|
144
|
+
types?: Record<string, ValidationType>;
|
|
145
|
+
/** Enable type validation from hints */
|
|
146
|
+
validateTypes?: boolean;
|
|
147
|
+
/** Enable secret detection */
|
|
148
|
+
detectSecrets?: boolean;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Result of validation
|
|
153
|
+
*/
|
|
154
|
+
export interface ValidateResult {
|
|
155
|
+
valid: boolean;
|
|
156
|
+
env: EnvFileResult;
|
|
157
|
+
issues: Issue[];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Check Types
|
|
162
|
+
// ============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Options for check function
|
|
166
|
+
*/
|
|
167
|
+
export interface CheckOptions {
|
|
168
|
+
/** Path to example file */
|
|
169
|
+
examplePath?: string;
|
|
170
|
+
/** List of required variable names */
|
|
171
|
+
required?: string[];
|
|
172
|
+
/** Warn on empty values */
|
|
173
|
+
noEmpty?: boolean;
|
|
174
|
+
/** Error on extra variables */
|
|
175
|
+
noExtra?: boolean;
|
|
176
|
+
/** Treat warnings as errors */
|
|
177
|
+
strict?: boolean;
|
|
178
|
+
/** Type specifications for variables */
|
|
179
|
+
types?: Record<string, ValidationType>;
|
|
180
|
+
/** Enable type validation */
|
|
181
|
+
validateTypes?: boolean;
|
|
182
|
+
/** Enable secret detection */
|
|
183
|
+
detectSecrets?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Result of check function
|
|
188
|
+
*/
|
|
189
|
+
export interface CheckResult {
|
|
190
|
+
valid: boolean;
|
|
191
|
+
issues: Issue[];
|
|
192
|
+
summary: {
|
|
193
|
+
errors: number;
|
|
194
|
+
warnings: number;
|
|
195
|
+
};
|
|
196
|
+
env?: EnvFileResult;
|
|
197
|
+
comparison?: CompareResult;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Secret Detection Types
|
|
202
|
+
// ============================================================================
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Secret pattern definition
|
|
206
|
+
*/
|
|
207
|
+
export interface SecretPattern {
|
|
208
|
+
regex: RegExp;
|
|
209
|
+
description: string;
|
|
210
|
+
keyPattern?: RegExp;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Result of secret detection
|
|
215
|
+
*/
|
|
216
|
+
export interface SecretDetectionResult {
|
|
217
|
+
detected: boolean;
|
|
218
|
+
description: string;
|
|
219
|
+
message: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Monorepo Types
|
|
224
|
+
// ============================================================================
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Options for monorepo scanning
|
|
228
|
+
*/
|
|
229
|
+
export interface ScanMonorepoOptions {
|
|
230
|
+
/** Warn on empty values */
|
|
231
|
+
noEmpty?: boolean;
|
|
232
|
+
/** Error on extra variables */
|
|
233
|
+
noExtra?: boolean;
|
|
234
|
+
/** Treat warnings as errors */
|
|
235
|
+
strict?: boolean;
|
|
236
|
+
/** Check consistency across apps */
|
|
237
|
+
checkConsistency?: boolean;
|
|
238
|
+
/** Enable secret detection */
|
|
239
|
+
detectSecrets?: boolean;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Result for a single app in monorepo scan
|
|
244
|
+
*/
|
|
245
|
+
export interface MonorepoAppResult {
|
|
246
|
+
name: string;
|
|
247
|
+
path: string;
|
|
248
|
+
hasEnv: boolean;
|
|
249
|
+
hasExample: boolean;
|
|
250
|
+
valid: boolean;
|
|
251
|
+
issues: Issue[];
|
|
252
|
+
variables: string[];
|
|
253
|
+
skipped?: boolean;
|
|
254
|
+
reason?: string;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Consistency mismatch in monorepo
|
|
259
|
+
*/
|
|
260
|
+
export interface ConsistencyMismatch {
|
|
261
|
+
variable: string;
|
|
262
|
+
issue: string;
|
|
263
|
+
details: Array<{
|
|
264
|
+
app: string;
|
|
265
|
+
type: string | null;
|
|
266
|
+
value?: string;
|
|
267
|
+
}>;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Result of scanning a monorepo
|
|
272
|
+
*/
|
|
273
|
+
export interface MonorepoScanResult {
|
|
274
|
+
root: string;
|
|
275
|
+
valid: boolean;
|
|
276
|
+
apps: MonorepoAppResult[];
|
|
277
|
+
summary: {
|
|
278
|
+
total: number;
|
|
279
|
+
passed: number;
|
|
280
|
+
failed: number;
|
|
281
|
+
skipped: number;
|
|
282
|
+
errors: number;
|
|
283
|
+
warnings: number;
|
|
284
|
+
};
|
|
285
|
+
consistency: {
|
|
286
|
+
sharedVars: Record<string, string[]>;
|
|
287
|
+
mismatches: ConsistencyMismatch[];
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Options for formatting monorepo result
|
|
293
|
+
*/
|
|
294
|
+
export interface FormatMonorepoOptions {
|
|
295
|
+
/** Enable ANSI colors */
|
|
296
|
+
colors?: boolean;
|
|
297
|
+
/** Show detailed issues */
|
|
298
|
+
verbose?: boolean;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ============================================================================
|
|
302
|
+
// Exported Functions
|
|
303
|
+
// ============================================================================
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Parse .env file content into an object
|
|
307
|
+
* @param content - Raw .env file content
|
|
308
|
+
* @returns Parsed result with variables and metadata
|
|
309
|
+
*/
|
|
310
|
+
export function parse(content: string): ParseResult;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Parse a single value, handling quotes and escapes
|
|
314
|
+
* @param raw - Raw value string
|
|
315
|
+
* @returns Parsed value
|
|
316
|
+
*/
|
|
317
|
+
export function parseValue(raw: string): string;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Read and parse a .env file
|
|
321
|
+
* @param filePath - Path to .env file
|
|
322
|
+
* @returns Parsed file result
|
|
323
|
+
*/
|
|
324
|
+
export function readEnvFile(filePath: string): EnvFileResult;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Compare two env files
|
|
328
|
+
* @param envPath - Path to .env file
|
|
329
|
+
* @param examplePath - Path to .env.example file
|
|
330
|
+
* @returns Comparison result
|
|
331
|
+
*/
|
|
332
|
+
export function compare(envPath: string, examplePath: string): CompareResult;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Validate an env file
|
|
336
|
+
* @param filePath - Path to .env file
|
|
337
|
+
* @param options - Validation options
|
|
338
|
+
* @returns Validation result
|
|
339
|
+
*/
|
|
340
|
+
export function validate(filePath: string, options?: ValidateOptions): ValidateResult;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Validate a value against a type
|
|
344
|
+
* @param value - Value to validate
|
|
345
|
+
* @param type - Type name
|
|
346
|
+
* @returns Validation result
|
|
347
|
+
*/
|
|
348
|
+
export function validateType(value: string, type: ValidationType): TypeValidationResult;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Check an env file against example and validate
|
|
352
|
+
* @param envPath - Path to .env file
|
|
353
|
+
* @param options - Check options
|
|
354
|
+
* @returns Check result
|
|
355
|
+
*/
|
|
356
|
+
export function check(envPath: string, options?: CheckOptions): CheckResult;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Generate a .env file from .env.example
|
|
360
|
+
* @param examplePath - Path to .env.example
|
|
361
|
+
* @param defaults - Default values to fill in
|
|
362
|
+
* @returns Generated .env content
|
|
363
|
+
*/
|
|
364
|
+
export function generate(examplePath: string, defaults?: Record<string, string>): string;
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get list of variable names from file
|
|
368
|
+
* @param filePath - Path to env file
|
|
369
|
+
* @returns Array of variable names
|
|
370
|
+
*/
|
|
371
|
+
export function list(filePath: string): string[];
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get a specific variable value
|
|
375
|
+
* @param filePath - Path to env file
|
|
376
|
+
* @param key - Variable name
|
|
377
|
+
* @returns Value or undefined
|
|
378
|
+
*/
|
|
379
|
+
export function get(filePath: string, key: string): string | undefined;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Detect potential secrets in environment variables
|
|
383
|
+
* @param key - Variable name
|
|
384
|
+
* @param value - Variable value
|
|
385
|
+
* @returns Detection result or null if no secret detected
|
|
386
|
+
*/
|
|
387
|
+
export function detectSecret(key: string, value: string): SecretDetectionResult | null;
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Check if a value looks like a placeholder
|
|
391
|
+
* @param value - Value to check
|
|
392
|
+
* @returns True if it looks like a placeholder
|
|
393
|
+
*/
|
|
394
|
+
export function isPlaceholder(value: string): boolean;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Find directories that might contain apps/packages in a monorepo
|
|
398
|
+
* @param rootDir - Root directory to scan
|
|
399
|
+
* @returns Array of directory paths
|
|
400
|
+
*/
|
|
401
|
+
export function findMonorepoApps(rootDir: string): string[];
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Scan a monorepo for env file issues
|
|
405
|
+
* @param rootDir - Root directory of monorepo
|
|
406
|
+
* @param options - Scan options
|
|
407
|
+
* @returns Monorepo scan result
|
|
408
|
+
*/
|
|
409
|
+
export function scanMonorepo(rootDir: string, options?: ScanMonorepoOptions): MonorepoScanResult;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Format monorepo result for CLI output
|
|
413
|
+
* @param result - Monorepo scan result
|
|
414
|
+
* @param options - Format options
|
|
415
|
+
* @returns Formatted string
|
|
416
|
+
*/
|
|
417
|
+
export function formatMonorepoResult(result: MonorepoScanResult, options?: FormatMonorepoOptions): string;
|
|
418
|
+
|
|
419
|
+
// ============================================================================
|
|
420
|
+
// Exported Constants
|
|
421
|
+
// ============================================================================
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Map of type names to validator functions
|
|
425
|
+
*/
|
|
426
|
+
export const typeValidators: Record<ValidationType, TypeValidator>;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Array of secret detection patterns
|
|
430
|
+
*/
|
|
431
|
+
export const secretPatterns: SecretPattern[];
|