@danielszlaski/envguard 0.1.0
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/.envguardrc.example.json +17 -0
- package/LICENSE +21 -0
- package/README.md +320 -0
- package/dist/analyzer/envAnalyzer.d.ts +8 -0
- package/dist/analyzer/envAnalyzer.d.ts.map +1 -0
- package/dist/analyzer/envAnalyzer.js +112 -0
- package/dist/analyzer/envAnalyzer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/check.d.ts +5 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +9 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/fix.d.ts +4 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +115 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/scan.d.ts +9 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +274 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/config/configLoader.d.ts +35 -0
- package/dist/config/configLoader.d.ts.map +1 -0
- package/dist/config/configLoader.js +141 -0
- package/dist/config/configLoader.js.map +1 -0
- package/dist/constants/knownEnvVars.d.ts +38 -0
- package/dist/constants/knownEnvVars.d.ts.map +1 -0
- package/dist/constants/knownEnvVars.js +111 -0
- package/dist/constants/knownEnvVars.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/parser/envParser.d.ts +13 -0
- package/dist/parser/envParser.d.ts.map +1 -0
- package/dist/parser/envParser.js +126 -0
- package/dist/parser/envParser.js.map +1 -0
- package/dist/parser/serverlessParser.d.ts +27 -0
- package/dist/parser/serverlessParser.d.ts.map +1 -0
- package/dist/parser/serverlessParser.js +162 -0
- package/dist/parser/serverlessParser.js.map +1 -0
- package/dist/scanner/codeScanner.d.ts +13 -0
- package/dist/scanner/codeScanner.d.ts.map +1 -0
- package/dist/scanner/codeScanner.js +157 -0
- package/dist/scanner/codeScanner.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
- package/src/analyzer/envAnalyzer.ts +133 -0
- package/src/cli.ts +54 -0
- package/src/commands/check.ts +6 -0
- package/src/commands/fix.ts +104 -0
- package/src/commands/scan.ts +289 -0
- package/src/config/configLoader.ts +131 -0
- package/src/constants/knownEnvVars.ts +108 -0
- package/src/index.ts +4 -0
- package/src/parser/envParser.ts +114 -0
- package/src/parser/serverlessParser.ts +146 -0
- package/src/scanner/codeScanner.ts +148 -0
- package/src/types.ts +26 -0
- package/test-project/.envguardrc.json +7 -0
- package/test-project/src/lambda1/.env.example +11 -0
- package/test-project/src/lambda1/handler.js +14 -0
- package/test-project/src/lambda2/.env.example +9 -0
- package/test-project/src/lambda2/handler.js +11 -0
- package/test-project/src/lambda2/handler2.js +13 -0
- package/test-project/src/lambda2/serverless.yml +50 -0
- package/test-project/src/payment/.env.example +23 -0
- package/test-project/src/payment/payment.js +14 -0
- package/test-project/src/payment/server.ts +11 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft-07/schema",
|
|
3
|
+
"title": "EnvGuard Configuration",
|
|
4
|
+
"description": "Configuration file for EnvGuard - keep your environment variables in sync",
|
|
5
|
+
"ignoreVars": [
|
|
6
|
+
"MY_COMPANY_VAR",
|
|
7
|
+
"PLATFORM_PROVIDED_VAR"
|
|
8
|
+
],
|
|
9
|
+
"strict": false,
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/tmp/**",
|
|
12
|
+
"**/cache/**",
|
|
13
|
+
"**/node_modules/**",
|
|
14
|
+
"**/dist/**",
|
|
15
|
+
"**/test/**"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniel
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# EnvGuard 🔐
|
|
2
|
+
|
|
3
|
+
Keep your environment variables in sync with your codebase.
|
|
4
|
+
|
|
5
|
+
## The Problem
|
|
6
|
+
|
|
7
|
+
- `.env.example` is always out of sync with actual `.env`
|
|
8
|
+
- New developers don't know what environment variables they need
|
|
9
|
+
- Production secrets accidentally committed
|
|
10
|
+
- Dead environment variables cluttering your config
|
|
11
|
+
|
|
12
|
+
## The Solution
|
|
13
|
+
|
|
14
|
+
EnvGuard automatically:
|
|
15
|
+
- Scans your codebase for `process.env.*` usage
|
|
16
|
+
- Compares with your `.env` and `.env.example` files
|
|
17
|
+
- **Supports Serverless Framework** - scans `serverless.yml` environment configurations
|
|
18
|
+
- Alerts you to missing, unused, or undocumented variables
|
|
19
|
+
- Auto-generates `.env.example` with helpful comments
|
|
20
|
+
- **Supports multiple `.env` files** in subdirectories (monorepo-friendly!)
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g envguard
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or use with npx:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx envguard scan
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Scan for issues
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
envguard scan
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Example output:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
🔍 Scanning codebase for environment variables...
|
|
46
|
+
|
|
47
|
+
✓ Found 12 unique environment variables in code
|
|
48
|
+
✓ Found 10 variables in .env
|
|
49
|
+
✓ Found 8 variables in .env.example
|
|
50
|
+
|
|
51
|
+
⚠️ Found 5 issue(s):
|
|
52
|
+
|
|
53
|
+
🚨 Missing from .env:
|
|
54
|
+
1. STRIPE_SECRET_KEY
|
|
55
|
+
Used in: src/payment.js, src/checkout.ts
|
|
56
|
+
2. API_KEY
|
|
57
|
+
Used in: src/api/client.ts
|
|
58
|
+
|
|
59
|
+
⚠️ Unused variables (consider removing):
|
|
60
|
+
1. OLD_API_URL
|
|
61
|
+
Defined in .env but never used in code
|
|
62
|
+
|
|
63
|
+
📝 Missing from .env.example:
|
|
64
|
+
1. DATABASE_URL
|
|
65
|
+
Used in: src/db/connection.ts
|
|
66
|
+
2. JWT_SECRET
|
|
67
|
+
Used in: src/auth/jwt.ts
|
|
68
|
+
|
|
69
|
+
💡 Run `envguard fix` to auto-generate .env.example
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Auto-generate .env.example
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
envguard fix
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This will create/update `.env.example` files with:
|
|
79
|
+
- All environment variables used in your code
|
|
80
|
+
- Comments showing where each variable is used
|
|
81
|
+
- Format hints for common variable types (URLs, ports, etc.)
|
|
82
|
+
- **Creates `.env.example` next to each `.env` file** (great for monorepos!)
|
|
83
|
+
|
|
84
|
+
Example generated `.env.example`:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Auto-generated by envguard
|
|
88
|
+
# Do not put actual secrets in this file - use .env instead
|
|
89
|
+
|
|
90
|
+
# Used in: src/db/connection.ts:12, src/models/user.ts:5
|
|
91
|
+
# Format: postgresql://user:pass@host:5432/db
|
|
92
|
+
DATABASE_URL=
|
|
93
|
+
|
|
94
|
+
# Used in: src/payment.js:23
|
|
95
|
+
# Format: sk_test_...
|
|
96
|
+
STRIPE_SECRET_KEY=
|
|
97
|
+
|
|
98
|
+
# Used in: src/server.ts:8
|
|
99
|
+
# Format: 3000
|
|
100
|
+
PORT=
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### CI/CD Integration
|
|
104
|
+
|
|
105
|
+
Use the `check` command in your CI pipeline to fail builds if environment variables are out of sync:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
envguard check
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
This is equivalent to `envguard scan --ci` and will exit with code 1 if issues are found.
|
|
112
|
+
|
|
113
|
+
#### GitHub Actions Example
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
name: Check Env Sync
|
|
117
|
+
on: [pull_request]
|
|
118
|
+
|
|
119
|
+
jobs:
|
|
120
|
+
envguard:
|
|
121
|
+
runs-on: ubuntu-latest
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/checkout@v3
|
|
124
|
+
- uses: actions/setup-node@v3
|
|
125
|
+
- run: npx envguard check
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Supported Languages & Frameworks
|
|
129
|
+
|
|
130
|
+
### JavaScript/TypeScript
|
|
131
|
+
- JavaScript (`.js`, `.mjs`, `.cjs`)
|
|
132
|
+
- TypeScript (`.ts`, `.tsx`)
|
|
133
|
+
- JSX (`.jsx`)
|
|
134
|
+
|
|
135
|
+
Detects:
|
|
136
|
+
- `process.env.VAR_NAME`
|
|
137
|
+
- `process.env['VAR_NAME']`
|
|
138
|
+
- `const { VAR_NAME } = process.env`
|
|
139
|
+
|
|
140
|
+
### Serverless Framework
|
|
141
|
+
- Automatically detects `serverless.yml` and `serverless.yaml` files
|
|
142
|
+
- Scans `provider.environment` section
|
|
143
|
+
- Scans function-level `environment` sections
|
|
144
|
+
- Detects references to external sources (SSM, Secrets Manager, etc.)
|
|
145
|
+
- Validates that all defined variables are used in code
|
|
146
|
+
- Reports variables used in code but not defined in serverless.yml
|
|
147
|
+
|
|
148
|
+
## Configuration
|
|
149
|
+
|
|
150
|
+
EnvGuard works out of the box with sensible defaults. It automatically excludes:
|
|
151
|
+
- `node_modules`
|
|
152
|
+
- `dist`
|
|
153
|
+
- `build`
|
|
154
|
+
- `.git`
|
|
155
|
+
|
|
156
|
+
### Custom Configuration
|
|
157
|
+
|
|
158
|
+
Create a `.envguardrc.json` file in your project root to customize behavior:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"ignoreVars": [
|
|
163
|
+
"MY_CUSTOM_VAR",
|
|
164
|
+
"ANOTHER_VAR",
|
|
165
|
+
"COMPANY_INTERNAL_VAR"
|
|
166
|
+
],
|
|
167
|
+
"strict": false,
|
|
168
|
+
"exclude": [
|
|
169
|
+
"**/build/**",
|
|
170
|
+
"**/tmp/**"
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Configuration options:**
|
|
176
|
+
|
|
177
|
+
- `ignoreVars` (string[]): Custom environment variables to ignore in non-strict mode. These will be treated like AWS_REGION and won't trigger warnings.
|
|
178
|
+
- `strict` (boolean): Enable strict mode by default (can be overridden with CLI flag)
|
|
179
|
+
- `exclude` (string[]): Additional file patterns to exclude from scanning
|
|
180
|
+
|
|
181
|
+
**Alternative: package.json**
|
|
182
|
+
|
|
183
|
+
You can also add configuration to your `package.json`:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"envguard": {
|
|
188
|
+
"ignoreVars": ["MY_CUSTOM_VAR"],
|
|
189
|
+
"strict": false
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Use case for ignoreVars:**
|
|
195
|
+
- Company-wide variables that are always available (injected by infrastructure)
|
|
196
|
+
- Framework-specific variables you don't need to track
|
|
197
|
+
- Variables provided by your deployment platform (Vercel, Netlify, etc.)
|
|
198
|
+
- Custom variables for GitHub Apps or CI/CD integrations
|
|
199
|
+
|
|
200
|
+
**Priority:** CLI flags > `.envguardrc.json` > `package.json` > defaults
|
|
201
|
+
|
|
202
|
+
**GitHub Apps & CI/CD:**
|
|
203
|
+
When using EnvGuard as a GitHub App or in CI/CD pipelines, commit your `.envguardrc.json` to the repository. This ensures consistent behavior across all environments and team members.
|
|
204
|
+
|
|
205
|
+
### Monorepo Support
|
|
206
|
+
|
|
207
|
+
EnvGuard automatically detects all `.env` files in your project, including subdirectories. When you run `envguard fix`, it creates a `.env.example` file next to each `.env` file it finds.
|
|
208
|
+
|
|
209
|
+
Example structure:
|
|
210
|
+
```
|
|
211
|
+
project/
|
|
212
|
+
├── .env → generates .env.example
|
|
213
|
+
├── src/
|
|
214
|
+
│ └── lambda1/
|
|
215
|
+
│ ├── .env → generates lambda1/.env.example
|
|
216
|
+
│ └── handler.js
|
|
217
|
+
└── services/
|
|
218
|
+
└── api/
|
|
219
|
+
├── .env → generates api/.env.example
|
|
220
|
+
└── server.js
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Each `.env.example` only includes variables used in that directory and its subdirectories.
|
|
224
|
+
|
|
225
|
+
## Serverless Framework Support
|
|
226
|
+
|
|
227
|
+
EnvGuard can scan `serverless.yml` files as a standalone source of environment variable definitions. This is useful for AWS Lambda projects where environment variables are defined in the serverless configuration rather than `.env` files.
|
|
228
|
+
|
|
229
|
+
### How it works
|
|
230
|
+
|
|
231
|
+
1. **Detects** `serverless.yml` files in your project
|
|
232
|
+
2. **Extracts** environment variables from `provider.environment` and function-level `environment` sections
|
|
233
|
+
3. **Validates** that all defined variables are actually used in your Lambda code
|
|
234
|
+
4. **Reports** unused variables and missing definitions
|
|
235
|
+
|
|
236
|
+
### Example serverless.yml
|
|
237
|
+
|
|
238
|
+
```yaml
|
|
239
|
+
provider:
|
|
240
|
+
name: aws
|
|
241
|
+
runtime: nodejs20.x
|
|
242
|
+
environment:
|
|
243
|
+
NODE_ENV: ${opt:stage}
|
|
244
|
+
API_KEY: ${ssm:/my-app/api-key}
|
|
245
|
+
DATABASE_URL: ${self:custom.dbUrl}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Scan output for serverless.yml
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
📂 Checking src/lambda/serverless.yml
|
|
252
|
+
|
|
253
|
+
Found 3 variable(s) in serverless.yml
|
|
254
|
+
Found 2 variable(s) used in code
|
|
255
|
+
|
|
256
|
+
⚠️ Unused variables in serverless.yml:
|
|
257
|
+
1. DATABASE_URL
|
|
258
|
+
|
|
259
|
+
🚨 Missing from serverless.yml:
|
|
260
|
+
1. LOG_LEVEL
|
|
261
|
+
Used in: src/lambda/handler.js
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Key Features
|
|
265
|
+
|
|
266
|
+
- **No .env required** - serverless.yml is treated as a standalone configuration source
|
|
267
|
+
- **CloudFormation intrinsic functions** - Supports `!Ref`, `!GetAtt`, `!Sub`, `!ImportValue`, and all CF functions
|
|
268
|
+
- **External references** - Detects SSM parameters, Secrets Manager, CloudFormation outputs
|
|
269
|
+
- **Function-level variables** - Scans both provider-level and function-specific environment vars
|
|
270
|
+
- **Smart filtering** - Automatically skips AWS/runtime variables (disable with `--strict`)
|
|
271
|
+
- **CI/CD validation** - Use `envguard check` to enforce serverless config completeness
|
|
272
|
+
|
|
273
|
+
## Commands
|
|
274
|
+
|
|
275
|
+
- `envguard scan` - Scan for issues and display report
|
|
276
|
+
- `envguard scan --ci` - Scan and exit with error code if issues found
|
|
277
|
+
- `envguard scan --strict` - Report all variables including known runtime variables
|
|
278
|
+
- `envguard fix` - Auto-generate `.env.example`
|
|
279
|
+
- `envguard check` - Alias for `scan --ci`
|
|
280
|
+
- `envguard check --strict` - Check with strict mode enabled
|
|
281
|
+
|
|
282
|
+
### Strict Mode
|
|
283
|
+
|
|
284
|
+
By default, EnvGuard filters out well-known runtime variables that don't need to be explicitly defined:
|
|
285
|
+
|
|
286
|
+
**AWS Lambda variables**: `AWS_REGION`, `AWS_LAMBDA_FUNCTION_NAME`, etc.
|
|
287
|
+
**Node.js runtime**: `NODE_ENV`, `PATH`, etc.
|
|
288
|
+
**CI/CD environments**: `CI`, `GITHUB_ACTIONS`, etc.
|
|
289
|
+
**Serverless Framework**: `IS_OFFLINE`, `SLS_OFFLINE`, etc.
|
|
290
|
+
|
|
291
|
+
Use `--strict` mode to report ALL variables including these runtime-provided ones:
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
envguard scan --strict
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Example output (non-strict):
|
|
298
|
+
```
|
|
299
|
+
ℹ️ Skipped known runtime variables (use --strict to show):
|
|
300
|
+
Serverless Framework: IS_OFFLINE, SLS_OFFLINE
|
|
301
|
+
CI/CD: CI
|
|
302
|
+
AWS Lambda: AWS_REGION
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Development
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Install dependencies
|
|
309
|
+
npm install
|
|
310
|
+
|
|
311
|
+
# Build
|
|
312
|
+
npm run build
|
|
313
|
+
|
|
314
|
+
# Run locally
|
|
315
|
+
npm start scan
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## License
|
|
319
|
+
|
|
320
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ScanResult } from '../types';
|
|
2
|
+
import { EnvEntry } from '../parser/envParser';
|
|
3
|
+
export declare class EnvAnalyzer {
|
|
4
|
+
analyze(usedVars: Map<string, string[]>, definedVars: Map<string, EnvEntry>, exampleVars: Set<string>): ScanResult;
|
|
5
|
+
generateExampleContent(usedVars: Map<string, string[]>, existingEntries: Map<string, EnvEntry>): string;
|
|
6
|
+
private getFormatHint;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=envAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envAnalyzer.d.ts","sourceRoot":"","sources":["../../src/analyzer/envAnalyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,UAAU,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,qBAAa,WAAW;IACtB,OAAO,CACL,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAC/B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAClC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,GACvB,UAAU;IA8Cb,sBAAsB,CACpB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAC/B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,GACrC,MAAM;IAyCT,OAAO,CAAC,aAAa;CAkCtB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EnvAnalyzer = void 0;
|
|
4
|
+
class EnvAnalyzer {
|
|
5
|
+
analyze(usedVars, definedVars, exampleVars) {
|
|
6
|
+
const issues = [];
|
|
7
|
+
// Issue 1: Variables used in code but missing from .env
|
|
8
|
+
for (const [varName, locations] of usedVars.entries()) {
|
|
9
|
+
if (!definedVars.has(varName)) {
|
|
10
|
+
issues.push({
|
|
11
|
+
type: 'missing',
|
|
12
|
+
varName,
|
|
13
|
+
details: `Used in code but not defined in .env`,
|
|
14
|
+
locations,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
// Issue 2: Variables defined in .env but never used
|
|
19
|
+
for (const [varName] of definedVars.entries()) {
|
|
20
|
+
if (!usedVars.has(varName)) {
|
|
21
|
+
issues.push({
|
|
22
|
+
type: 'unused',
|
|
23
|
+
varName,
|
|
24
|
+
details: `Defined in .env but never used in code`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Issue 3: Variables used in code but not in .env.example
|
|
29
|
+
for (const [varName, locations] of usedVars.entries()) {
|
|
30
|
+
if (!exampleVars.has(varName)) {
|
|
31
|
+
issues.push({
|
|
32
|
+
type: 'undocumented',
|
|
33
|
+
varName,
|
|
34
|
+
details: `Used in code but missing from .env.example`,
|
|
35
|
+
locations,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
issues,
|
|
41
|
+
usedVars,
|
|
42
|
+
definedVars: new Set(definedVars.keys()),
|
|
43
|
+
exampleVars,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
generateExampleContent(usedVars, existingEntries) {
|
|
47
|
+
let content = '# Auto-generated by envguard\n';
|
|
48
|
+
content += '# Do not put actual secrets in this file - use .env instead\n\n';
|
|
49
|
+
const sortedVars = Array.from(usedVars.keys()).sort();
|
|
50
|
+
for (const varName of sortedVars) {
|
|
51
|
+
const locations = usedVars.get(varName);
|
|
52
|
+
const existingEntry = existingEntries.get(varName);
|
|
53
|
+
// Add location comments
|
|
54
|
+
content += `# Used in: ${locations.slice(0, 3).join(', ')}`;
|
|
55
|
+
if (locations.length > 3) {
|
|
56
|
+
content += ` (+${locations.length - 3} more)`;
|
|
57
|
+
}
|
|
58
|
+
content += '\n';
|
|
59
|
+
// Add existing comment if available
|
|
60
|
+
if (existingEntry?.comment) {
|
|
61
|
+
content += `# ${existingEntry.comment}\n`;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Add a format hint based on common patterns
|
|
65
|
+
const hint = this.getFormatHint(varName);
|
|
66
|
+
if (hint) {
|
|
67
|
+
content += `# Format: ${hint}\n`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Add the variable with empty value or existing value
|
|
71
|
+
if (existingEntry) {
|
|
72
|
+
content += `${varName}=${existingEntry.value}\n`;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
content += `${varName}=\n`;
|
|
76
|
+
}
|
|
77
|
+
content += '\n';
|
|
78
|
+
}
|
|
79
|
+
return content;
|
|
80
|
+
}
|
|
81
|
+
getFormatHint(varName) {
|
|
82
|
+
const patterns = {
|
|
83
|
+
'DATABASE_URL': 'postgresql://user:pass@host:5432/db',
|
|
84
|
+
'MONGODB_URI': 'mongodb://localhost:27017/dbname',
|
|
85
|
+
'REDIS_URL': 'redis://localhost:6379',
|
|
86
|
+
'PORT': '3000',
|
|
87
|
+
'NODE_ENV': 'development|production|test',
|
|
88
|
+
'API_KEY': 'your-api-key-here',
|
|
89
|
+
'SECRET': 'your-secret-here',
|
|
90
|
+
'JWT_SECRET': 'your-jwt-secret',
|
|
91
|
+
'STRIPE_': 'sk_test_...',
|
|
92
|
+
'AWS_': 'aws-credentials',
|
|
93
|
+
};
|
|
94
|
+
for (const [pattern, hint] of Object.entries(patterns)) {
|
|
95
|
+
if (varName.includes(pattern)) {
|
|
96
|
+
return hint;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (varName.endsWith('_URL') || varName.endsWith('_URI')) {
|
|
100
|
+
return 'https://example.com';
|
|
101
|
+
}
|
|
102
|
+
if (varName.endsWith('_PORT')) {
|
|
103
|
+
return '8080';
|
|
104
|
+
}
|
|
105
|
+
if (varName.endsWith('_KEY') || varName.endsWith('_SECRET') || varName.endsWith('_TOKEN')) {
|
|
106
|
+
return 'your-secret-here';
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.EnvAnalyzer = EnvAnalyzer;
|
|
112
|
+
//# sourceMappingURL=envAnalyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/envAnalyzer.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const scan_1 = require("./commands/scan");
|
|
6
|
+
const fix_1 = require("./commands/fix");
|
|
7
|
+
const program = new commander_1.Command();
|
|
8
|
+
program
|
|
9
|
+
.name('envguard')
|
|
10
|
+
.description('Keep your environment variables in sync with your codebase')
|
|
11
|
+
.version('0.1.0');
|
|
12
|
+
program
|
|
13
|
+
.command('scan')
|
|
14
|
+
.description('Scan codebase and compare with .env files')
|
|
15
|
+
.option('--ci', 'Exit with error code if issues found (for CI/CD)')
|
|
16
|
+
.option('--strict', 'Report all variables including known runtime variables (AWS_REGION, NODE_ENV, etc.)')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
try {
|
|
19
|
+
await (0, scan_1.scanCommand)(options);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error('Error:', error);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
program
|
|
27
|
+
.command('fix')
|
|
28
|
+
.description('Auto-generate .env.example from codebase')
|
|
29
|
+
.action(async () => {
|
|
30
|
+
try {
|
|
31
|
+
await (0, fix_1.fixCommand)();
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error('Error:', error);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
program
|
|
39
|
+
.command('check')
|
|
40
|
+
.description('Check for issues (alias for scan --ci)')
|
|
41
|
+
.option('--strict', 'Report all variables including known runtime variables (AWS_REGION, NODE_ENV, etc.)')
|
|
42
|
+
.action(async (options) => {
|
|
43
|
+
try {
|
|
44
|
+
await (0, scan_1.scanCommand)({ ci: true, strict: options.strict });
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
console.error('Error:', error);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
program.parse();
|
|
52
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,0CAA8C;AAC9C,wCAA4C;AAG5C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,4DAA4D,CAAC;KACzE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2CAA2C,CAAC;KACxD,MAAM,CAAC,MAAM,EAAE,kDAAkD,CAAC;KAClE,MAAM,CAAC,UAAU,EAAE,qFAAqF,CAAC;KACzG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAA,gBAAU,GAAE,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,UAAU,EAAE,qFAAqF,CAAC;KACzG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,MAAM,IAAA,kBAAW,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY;;;GAGjC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkCommand = checkCommand;
|
|
4
|
+
const scan_1 = require("./scan");
|
|
5
|
+
async function checkCommand() {
|
|
6
|
+
// Check command is the same as scan but with --ci flag
|
|
7
|
+
return (0, scan_1.scanCommand)({ ci: true });
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":";;AAEA,oCAGC;AALD,iCAAqC;AAE9B,KAAK,UAAU,YAAY;IAChC,uDAAuD;IACvD,OAAO,IAAA,kBAAW,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/commands/fix.ts"],"names":[],"mappings":"AAOA,wBAAsB,UAAU;;GAgE/B"}
|