@anhuijie/envguard 1.0.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/LICENSE +21 -0
- package/README.md +444 -0
- package/package.json +39 -0
- package/src/cli.js +118 -0
- package/src/commands/check.js +63 -0
- package/src/commands/diff.js +59 -0
- package/src/commands/docs.js +45 -0
- package/src/commands/init.js +101 -0
- package/src/commands/validate.js +72 -0
- package/src/core/diff.js +111 -0
- package/src/core/docs.js +120 -0
- package/src/core/index.js +22 -0
- package/src/core/schema.js +74 -0
- package/src/core/security.js +128 -0
- package/src/core/validator.js +170 -0
- package/src/index.js +9 -0
- package/src/utils/file.js +102 -0
- package/src/utils/format.js +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EnvGuard Contributors
|
|
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,444 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🛡️ EnvGuard
|
|
4
|
+
|
|
5
|
+
**Environment Variable Validation, Security Scanning & Documentation Generator**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/AnhuiJie/envguard/actions/workflows/ci.yml)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://nodejs.org/)
|
|
10
|
+
|
|
11
|
+
[English](#english) · [中文](#中文) · [日本語](#日本語)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<a id="english"></a>
|
|
18
|
+
|
|
19
|
+
## 🇬🇧 English
|
|
20
|
+
|
|
21
|
+
### Why EnvGuard?
|
|
22
|
+
|
|
23
|
+
Misconfigured environment variables are a leading cause of production incidents. EnvGuard provides a **single tool** to validate, secure, and document your project's configuration — catching errors before they reach production.
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
- **Schema Validation** — Define types, required fields, enums, ranges, and patterns for every variable
|
|
28
|
+
- **Security Scanning** — Detect accidentally committed secrets (AWS keys, GitHub tokens, private keys, etc.)
|
|
29
|
+
- **Auto Documentation** — Generate `.env.example` and markdown docs from your schema
|
|
30
|
+
- **Environment Diff** — Compare `.env` files across dev/staging/prod to find drift
|
|
31
|
+
- **CI/CD Ready** — Exit codes and GitHub Action integration for automated checks
|
|
32
|
+
- **Zero Dependencies** — Pure Node.js, no external packages required
|
|
33
|
+
- **Multi-format Support** — Works with `.env`, `.env.local`, `.env.production`, and more
|
|
34
|
+
|
|
35
|
+
### Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install
|
|
39
|
+
npm install -g envguard
|
|
40
|
+
|
|
41
|
+
# Create config
|
|
42
|
+
envguard init
|
|
43
|
+
|
|
44
|
+
# Validate environment variables
|
|
45
|
+
envguard validate
|
|
46
|
+
|
|
47
|
+
# Scan for secrets
|
|
48
|
+
envguard check
|
|
49
|
+
|
|
50
|
+
# Generate documentation
|
|
51
|
+
envguard docs
|
|
52
|
+
|
|
53
|
+
# Compare environments
|
|
54
|
+
envguard diff .env.development .env.production
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Configuration
|
|
58
|
+
|
|
59
|
+
Create `envguard.config.js` in your project root:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
module.exports = {
|
|
63
|
+
schema: {
|
|
64
|
+
NODE_ENV: {
|
|
65
|
+
required: true,
|
|
66
|
+
type: 'string',
|
|
67
|
+
enum: ['development', 'staging', 'production', 'test'],
|
|
68
|
+
description: 'Application environment',
|
|
69
|
+
},
|
|
70
|
+
PORT: {
|
|
71
|
+
required: false,
|
|
72
|
+
type: 'port',
|
|
73
|
+
default: '3000',
|
|
74
|
+
description: 'Server port',
|
|
75
|
+
},
|
|
76
|
+
DATABASE_URL: {
|
|
77
|
+
required: true,
|
|
78
|
+
type: 'url',
|
|
79
|
+
description: 'Database connection string',
|
|
80
|
+
},
|
|
81
|
+
JWT_SECRET: {
|
|
82
|
+
required: true,
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Secret key for JWT signing',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
security: {
|
|
88
|
+
minSeverity: 'medium',
|
|
89
|
+
ignoreKeys: [],
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Supported Types
|
|
95
|
+
|
|
96
|
+
| Type | Description | Example |
|
|
97
|
+
|------|-------------|---------|
|
|
98
|
+
| `string` | Any string value | `any text` |
|
|
99
|
+
| `number` | Numeric value with optional min/max | `42` |
|
|
100
|
+
| `boolean` | true/false, 1/0, yes/no | `true` |
|
|
101
|
+
| `url` | Valid URL | `https://example.com` |
|
|
102
|
+
| `email` | Valid email address | `user@example.com` |
|
|
103
|
+
| `port` | Valid port number (0-65535) | `3000` |
|
|
104
|
+
| `json` | Valid JSON string | `'{"key":"value"}'` |
|
|
105
|
+
| `regex` | Valid regex pattern | `^\\d+$` |
|
|
106
|
+
|
|
107
|
+
### Rule Options
|
|
108
|
+
|
|
109
|
+
| Option | Type | Description |
|
|
110
|
+
|--------|------|-------------|
|
|
111
|
+
| `required` | boolean | Variable must be set |
|
|
112
|
+
| `type` | string | Value type validation |
|
|
113
|
+
| `default` | any | Default value if not set |
|
|
114
|
+
| `enum` | array | Allowed values |
|
|
115
|
+
| `min` / `max` | number | Range constraints (for `number` type) |
|
|
116
|
+
| `pattern` | string | Regex pattern the value must match |
|
|
117
|
+
| `deprecated` | boolean | Mark as deprecated |
|
|
118
|
+
| `replacement` | string | Suggested replacement for deprecated vars |
|
|
119
|
+
| `description` | string | Human-readable description |
|
|
120
|
+
|
|
121
|
+
### Security Scanning
|
|
122
|
+
|
|
123
|
+
EnvGuard detects these secret types:
|
|
124
|
+
|
|
125
|
+
- AWS Access Keys & Secret Keys
|
|
126
|
+
- GitHub / GitLab Tokens
|
|
127
|
+
- Slack Tokens
|
|
128
|
+
- Stripe Live Keys
|
|
129
|
+
- Private Keys (RSA, EC, DSA)
|
|
130
|
+
- JWT Secrets
|
|
131
|
+
- Database URLs with embedded passwords
|
|
132
|
+
- Generic API Keys, Passwords, and Secrets
|
|
133
|
+
|
|
134
|
+
### CI/CD Integration
|
|
135
|
+
|
|
136
|
+
**GitHub Actions:**
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
- name: Validate env config
|
|
140
|
+
run: npx envguard validate
|
|
141
|
+
|
|
142
|
+
- name: Security check
|
|
143
|
+
run: npx envguard check
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The command exits with code `1` on validation errors or critical security findings, failing the build.
|
|
147
|
+
|
|
148
|
+
### Programmatic API
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
const { validateEnv, scanForSecrets, generateEnvExample } = require('envguard');
|
|
152
|
+
|
|
153
|
+
const schema = { PORT: { required: true, type: 'port' } };
|
|
154
|
+
const result = validateEnv(process.env, schema);
|
|
155
|
+
// { valid: true, errors: [], warnings: [], checked: 1 }
|
|
156
|
+
|
|
157
|
+
const secrets = scanForSecrets(process.env);
|
|
158
|
+
// { findings: [], hasCritical: false, total: 0 }
|
|
159
|
+
|
|
160
|
+
const example = generateEnvExample(schema);
|
|
161
|
+
// "# Server port\n# type: port\nPORT=\n"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### License
|
|
165
|
+
|
|
166
|
+
[MIT](LICENSE)
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
<a id="中文"></a>
|
|
171
|
+
|
|
172
|
+
## 🇨🇳 中文
|
|
173
|
+
|
|
174
|
+
### 为什么需要 EnvGuard?
|
|
175
|
+
|
|
176
|
+
环境变量配置错误是生产事故的主要原因之一。EnvGuard 提供**一站式工具**来验证、保护和文档化项目配置——在错误到达生产环境之前就将其捕获。
|
|
177
|
+
|
|
178
|
+
### 功能特性
|
|
179
|
+
|
|
180
|
+
- **Schema 验证** — 为每个变量定义类型、必填、枚举、范围和正则模式
|
|
181
|
+
- **安全扫描** — 检测意外提交的密钥(AWS 密钥、GitHub Token、私钥等)
|
|
182
|
+
- **自动文档** — 从 Schema 生成 `.env.example` 和 Markdown 文档
|
|
183
|
+
- **环境对比** — 比较 dev/staging/prod 的 `.env` 文件差异
|
|
184
|
+
- **CI/CD 就绪** — 退出码和 GitHub Action 集成,支持自动化检查
|
|
185
|
+
- **零依赖** — 纯 Node.js 实现,无需外部包
|
|
186
|
+
- **多格式支持** — 支持 `.env`、`.env.local`、`.env.production` 等
|
|
187
|
+
|
|
188
|
+
### 快速开始
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
# 安装
|
|
192
|
+
npm install -g envguard
|
|
193
|
+
|
|
194
|
+
# 创建配置
|
|
195
|
+
envguard init
|
|
196
|
+
|
|
197
|
+
# 验证环境变量
|
|
198
|
+
envguard validate
|
|
199
|
+
|
|
200
|
+
# 扫描敏感信息
|
|
201
|
+
envguard check
|
|
202
|
+
|
|
203
|
+
# 生成文档
|
|
204
|
+
envguard docs
|
|
205
|
+
|
|
206
|
+
# 对比环境差异
|
|
207
|
+
envguard diff .env.development .env.production
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 配置
|
|
211
|
+
|
|
212
|
+
在项目根目录创建 `envguard.config.js`:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
module.exports = {
|
|
216
|
+
schema: {
|
|
217
|
+
NODE_ENV: {
|
|
218
|
+
required: true,
|
|
219
|
+
type: 'string',
|
|
220
|
+
enum: ['development', 'staging', 'production', 'test'],
|
|
221
|
+
description: '应用运行环境',
|
|
222
|
+
},
|
|
223
|
+
PORT: {
|
|
224
|
+
required: false,
|
|
225
|
+
type: 'port',
|
|
226
|
+
default: '3000',
|
|
227
|
+
description: '服务端口',
|
|
228
|
+
},
|
|
229
|
+
DATABASE_URL: {
|
|
230
|
+
required: true,
|
|
231
|
+
type: 'url',
|
|
232
|
+
description: '数据库连接字符串',
|
|
233
|
+
},
|
|
234
|
+
JWT_SECRET: {
|
|
235
|
+
required: true,
|
|
236
|
+
type: 'string',
|
|
237
|
+
description: 'JWT 签名密钥',
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
security: {
|
|
241
|
+
minSeverity: 'medium',
|
|
242
|
+
ignoreKeys: [],
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### 支持的类型
|
|
248
|
+
|
|
249
|
+
| 类型 | 说明 | 示例 |
|
|
250
|
+
|------|------|------|
|
|
251
|
+
| `string` | 任意字符串 | `任意文本` |
|
|
252
|
+
| `number` | 数值,支持 min/max | `42` |
|
|
253
|
+
| `boolean` | true/false、1/0、yes/no | `true` |
|
|
254
|
+
| `url` | 合法 URL | `https://example.com` |
|
|
255
|
+
| `email` | 合法邮箱 | `user@example.com` |
|
|
256
|
+
| `port` | 合法端口号 (0-65535) | `3000` |
|
|
257
|
+
| `json` | 合法 JSON 字符串 | `'{"key":"value"}'` |
|
|
258
|
+
| `regex` | 合法正则表达式 | `^\\d+$` |
|
|
259
|
+
|
|
260
|
+
### 安全扫描
|
|
261
|
+
|
|
262
|
+
EnvGuard 可检测以下密钥类型:
|
|
263
|
+
|
|
264
|
+
- AWS 访问密钥和密钥
|
|
265
|
+
- GitHub / GitLab Token
|
|
266
|
+
- Slack Token
|
|
267
|
+
- Stripe Live Key
|
|
268
|
+
- 私钥(RSA、EC、DSA)
|
|
269
|
+
- JWT 密钥
|
|
270
|
+
- 包含密码的数据库连接 URL
|
|
271
|
+
- 通用 API Key、密码和密钥
|
|
272
|
+
|
|
273
|
+
### CI/CD 集成
|
|
274
|
+
|
|
275
|
+
**GitHub Actions:**
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
- name: 验证环境配置
|
|
279
|
+
run: npx envguard validate
|
|
280
|
+
|
|
281
|
+
- name: 安全检查
|
|
282
|
+
run: npx envguard check
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
验证失败或发现严重安全问题时,命令以退出码 `1` 退出,使构建失败。
|
|
286
|
+
|
|
287
|
+
### 编程式 API
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
const { validateEnv, scanForSecrets, generateEnvExample } = require('envguard');
|
|
291
|
+
|
|
292
|
+
const schema = { PORT: { required: true, type: 'port' } };
|
|
293
|
+
const result = validateEnv(process.env, schema);
|
|
294
|
+
// { valid: true, errors: [], warnings: [], checked: 1 }
|
|
295
|
+
|
|
296
|
+
const secrets = scanForSecrets(process.env);
|
|
297
|
+
// { findings: [], hasCritical: false, total: 0 }
|
|
298
|
+
|
|
299
|
+
const example = generateEnvExample(schema);
|
|
300
|
+
// "# Server port\n# type: port\nPORT=\n"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 许可证
|
|
304
|
+
|
|
305
|
+
[MIT](LICENSE)
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
<a id="日本語"></a>
|
|
310
|
+
|
|
311
|
+
## 🇯🇵 日本語
|
|
312
|
+
|
|
313
|
+
### なぜ EnvGuard が必要か?
|
|
314
|
+
|
|
315
|
+
環境変数の設定ミスは本番障害の主要な原因の一つです。EnvGuard は、プロジェクトの設定を検証・保護・文書化する**オールインワンツール**を提供し、エラーが本番環境に到達する前に検出します。
|
|
316
|
+
|
|
317
|
+
### 機能
|
|
318
|
+
|
|
319
|
+
- **スキーマ検証** — 各変数の型、必須、列挙、範囲、正規表現パターンを定義
|
|
320
|
+
- **セキュリティスキャン** — 誤ってコミットされたシークレットの検出(AWS キー、GitHub トークン、秘密鍵など)
|
|
321
|
+
- **自動ドキュメント生成** — スキーマから `.env.example` と Markdown ドキュメントを生成
|
|
322
|
+
- **環境比較** — dev/staging/prod の `.env` ファイルの差分を検出
|
|
323
|
+
- **CI/CD 対応** — 終了コードと GitHub Action 統合による自動チェック
|
|
324
|
+
- **ゼロ依存** — 外部パッケージ不要のピュア Node.js 実装
|
|
325
|
+
- **マルチフォーマット対応** — `.env`、`.env.local`、`.env.production` などに対応
|
|
326
|
+
|
|
327
|
+
### クイックスタート
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# インストール
|
|
331
|
+
npm install -g envguard
|
|
332
|
+
|
|
333
|
+
# 設定ファイルの作成
|
|
334
|
+
envguard init
|
|
335
|
+
|
|
336
|
+
# 環境変数の検証
|
|
337
|
+
envguard validate
|
|
338
|
+
|
|
339
|
+
# セキュリティスキャン
|
|
340
|
+
envguard check
|
|
341
|
+
|
|
342
|
+
# ドキュメント生成
|
|
343
|
+
envguard docs
|
|
344
|
+
|
|
345
|
+
# 環境の比較
|
|
346
|
+
envguard diff .env.development .env.production
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 設定
|
|
350
|
+
|
|
351
|
+
プロジェクトルートに `envguard.config.js` を作成:
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
module.exports = {
|
|
355
|
+
schema: {
|
|
356
|
+
NODE_ENV: {
|
|
357
|
+
required: true,
|
|
358
|
+
type: 'string',
|
|
359
|
+
enum: ['development', 'staging', 'production', 'test'],
|
|
360
|
+
description: 'アプリケーション環境',
|
|
361
|
+
},
|
|
362
|
+
PORT: {
|
|
363
|
+
required: false,
|
|
364
|
+
type: 'port',
|
|
365
|
+
default: '3000',
|
|
366
|
+
description: 'サーバーポート',
|
|
367
|
+
},
|
|
368
|
+
DATABASE_URL: {
|
|
369
|
+
required: true,
|
|
370
|
+
type: 'url',
|
|
371
|
+
description: 'データベース接続文字列',
|
|
372
|
+
},
|
|
373
|
+
JWT_SECRET: {
|
|
374
|
+
required: true,
|
|
375
|
+
type: 'string',
|
|
376
|
+
description: 'JWT 署名用シークレットキー',
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
security: {
|
|
380
|
+
minSeverity: 'medium',
|
|
381
|
+
ignoreKeys: [],
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### サポート型
|
|
387
|
+
|
|
388
|
+
| 型 | 説明 | 例 |
|
|
389
|
+
|----|------|-----|
|
|
390
|
+
| `string` | 任意の文字列 | `任意のテキスト` |
|
|
391
|
+
| `number` | 数値(min/max 対応) | `42` |
|
|
392
|
+
| `boolean` | true/false、1/0、yes/no | `true` |
|
|
393
|
+
| `url` | 有効な URL | `https://example.com` |
|
|
394
|
+
| `email` | 有効なメールアドレス | `user@example.com` |
|
|
395
|
+
| `port` | 有効なポート番号 (0-65535) | `3000` |
|
|
396
|
+
| `json` | 有効な JSON 文字列 | `'{"key":"value"}'` |
|
|
397
|
+
| `regex` | 有効な正規表現パターン | `^\\d+$` |
|
|
398
|
+
|
|
399
|
+
### セキュリティスキャン
|
|
400
|
+
|
|
401
|
+
EnvGuard は以下のシークレットタイプを検出します:
|
|
402
|
+
|
|
403
|
+
- AWS アクセスキー・シークレットキー
|
|
404
|
+
- GitHub / GitLab トークン
|
|
405
|
+
- Slack トークン
|
|
406
|
+
- Stripe ライブキー
|
|
407
|
+
- 秘密鍵(RSA、EC、DSA)
|
|
408
|
+
- JWT シークレット
|
|
409
|
+
- パスワード埋め込みデータベース URL
|
|
410
|
+
- 汎用 API キー、パスワード、シークレット
|
|
411
|
+
|
|
412
|
+
### CI/CD 統合
|
|
413
|
+
|
|
414
|
+
**GitHub Actions:**
|
|
415
|
+
|
|
416
|
+
```yaml
|
|
417
|
+
- name: 環境設定の検証
|
|
418
|
+
run: npx envguard validate
|
|
419
|
+
|
|
420
|
+
- name: セキュリティチェック
|
|
421
|
+
run: npx envguard check
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
検証エラーや重大なセキュリティ問題が見つかった場合、コマンドは終了コード `1` で終了し、ビルドを失敗させます。
|
|
425
|
+
|
|
426
|
+
### プログラマティック API
|
|
427
|
+
|
|
428
|
+
```js
|
|
429
|
+
const { validateEnv, scanForSecrets, generateEnvExample } = require('envguard');
|
|
430
|
+
|
|
431
|
+
const schema = { PORT: { required: true, type: 'port' } };
|
|
432
|
+
const result = validateEnv(process.env, schema);
|
|
433
|
+
// { valid: true, errors: [], warnings: [], checked: 1 }
|
|
434
|
+
|
|
435
|
+
const secrets = scanForSecrets(process.env);
|
|
436
|
+
// { findings: [], hasCritical: false, total: 0 }
|
|
437
|
+
|
|
438
|
+
const example = generateEnvExample(schema);
|
|
439
|
+
// "# Server port\n# type: port\nPORT=\n"
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### ライセンス
|
|
443
|
+
|
|
444
|
+
[MIT](LICENSE)
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anhuijie/envguard",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Environment variable & config validation, security scanning, and documentation generator for modern projects",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"envguard": "./src/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node src/cli.js",
|
|
11
|
+
"test": "node --test test/**/*.test.js",
|
|
12
|
+
"lint": "eslint src/"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"env",
|
|
16
|
+
"environment-variables",
|
|
17
|
+
"config",
|
|
18
|
+
"validation",
|
|
19
|
+
"security",
|
|
20
|
+
"dotenv",
|
|
21
|
+
"schema",
|
|
22
|
+
"documentation",
|
|
23
|
+
"ci-cd"
|
|
24
|
+
],
|
|
25
|
+
"author": "AnhuiJie <anhuijie@example.com>",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/AnhuiJie/envguard"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.0.0"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"src/",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
]
|
|
39
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* EnvGuard CLI — Environment variable & config validation, security scanning, and documentation generator
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { runInit } = require('./commands/init');
|
|
8
|
+
const { runValidate } = require('./commands/validate');
|
|
9
|
+
const { runCheck } = require('./commands/check');
|
|
10
|
+
const { runDocs } = require('./commands/docs');
|
|
11
|
+
const { runDiff } = require('./commands/diff');
|
|
12
|
+
|
|
13
|
+
const VERSION = '1.0.0';
|
|
14
|
+
|
|
15
|
+
function parseArgs(argv) {
|
|
16
|
+
const args = argv.slice(2);
|
|
17
|
+
const command = args[0];
|
|
18
|
+
const options = {};
|
|
19
|
+
const positional = [];
|
|
20
|
+
|
|
21
|
+
for (let i = 1; i < args.length; i++) {
|
|
22
|
+
if (args[i].startsWith('--')) {
|
|
23
|
+
const key = args[i].slice(2);
|
|
24
|
+
const next = args[i + 1];
|
|
25
|
+
if (next && !next.startsWith('--')) {
|
|
26
|
+
options[key] = next;
|
|
27
|
+
i++;
|
|
28
|
+
} else {
|
|
29
|
+
options[key] = true;
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
positional.push(args[i]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Map positional args to command-specific options
|
|
37
|
+
if (command === 'diff' && positional.length >= 2) {
|
|
38
|
+
options.fileA = positional[0];
|
|
39
|
+
options.fileB = positional[1];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return { command, options };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function printHelp() {
|
|
46
|
+
console.log(`
|
|
47
|
+
EnvGuard v${VERSION} — Environment variable & config validation, security scanning, and documentation generator
|
|
48
|
+
|
|
49
|
+
Usage:
|
|
50
|
+
envguard <command> [options]
|
|
51
|
+
|
|
52
|
+
Commands:
|
|
53
|
+
init Create envguard.config.js template
|
|
54
|
+
validate Validate environment variables against schema
|
|
55
|
+
check Scan .env files for sensitive information
|
|
56
|
+
docs Generate .env.example and documentation
|
|
57
|
+
diff Compare two .env files
|
|
58
|
+
|
|
59
|
+
Options:
|
|
60
|
+
--config <path> Path to config file
|
|
61
|
+
--env-file <path> Path to .env file
|
|
62
|
+
--output <dir> Output directory for docs
|
|
63
|
+
--severity <level> Minimum severity for security check (low|medium|high|critical)
|
|
64
|
+
--recursive Scan subdirectories for .env files
|
|
65
|
+
--force Overwrite existing files
|
|
66
|
+
--allow-failure Exit with code 0 even on errors
|
|
67
|
+
--help Show this help message
|
|
68
|
+
--version Show version number
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
envguard init
|
|
72
|
+
envguard validate
|
|
73
|
+
envguard validate --env-file .env.production
|
|
74
|
+
envguard check --recursive
|
|
75
|
+
envguard docs --output ./docs
|
|
76
|
+
envguard diff .env.development .env.production
|
|
77
|
+
`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function main() {
|
|
81
|
+
const { command, options } = parseArgs(process.argv);
|
|
82
|
+
|
|
83
|
+
if (options.help) {
|
|
84
|
+
printHelp();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (options.version) {
|
|
89
|
+
console.log(`EnvGuard v${VERSION}`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
switch (command) {
|
|
94
|
+
case 'init':
|
|
95
|
+
runInit({ ...options, cwd: process.cwd() });
|
|
96
|
+
break;
|
|
97
|
+
case 'validate':
|
|
98
|
+
runValidate({ ...options, cwd: process.cwd() });
|
|
99
|
+
break;
|
|
100
|
+
case 'check':
|
|
101
|
+
runCheck({ ...options, cwd: process.cwd() });
|
|
102
|
+
break;
|
|
103
|
+
case 'docs':
|
|
104
|
+
runDocs({ ...options, cwd: process.cwd() });
|
|
105
|
+
break;
|
|
106
|
+
case 'diff':
|
|
107
|
+
runDiff({ ...options, cwd: process.cwd() });
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
printHelp();
|
|
111
|
+
if (command) {
|
|
112
|
+
console.log(`Unknown command: ${command}`);
|
|
113
|
+
}
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
main();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* envguard check — scan for sensitive information in .env files
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { scanForSecrets } = require('../core/security');
|
|
6
|
+
const { formatFinding, printHeader, colorize } = require('../utils/format');
|
|
7
|
+
const { findEnvFiles, loadEnvFile } = require('../utils/file');
|
|
8
|
+
|
|
9
|
+
function runCheck(options = {}) {
|
|
10
|
+
const cwd = options.cwd || process.cwd();
|
|
11
|
+
|
|
12
|
+
printHeader('EnvGuard — Security Check');
|
|
13
|
+
|
|
14
|
+
// Find .env files
|
|
15
|
+
const envFiles = findEnvFiles(cwd, { recursive: options.recursive });
|
|
16
|
+
|
|
17
|
+
if (envFiles.length === 0) {
|
|
18
|
+
console.log(colorize('No .env files found.', 'yellow'));
|
|
19
|
+
return { findings: [], total: 0 };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log(`Scanning ${envFiles.length} file(s)...\n`);
|
|
23
|
+
|
|
24
|
+
let allFindings = [];
|
|
25
|
+
|
|
26
|
+
for (const filePath of envFiles) {
|
|
27
|
+
const envObj = loadEnvFile(filePath);
|
|
28
|
+
const result = scanForSecrets(envObj, {
|
|
29
|
+
ignoreKeys: options.ignoreKeys,
|
|
30
|
+
minSeverity: options.severity || 'medium',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (result.findings.length > 0) {
|
|
34
|
+
console.log(colorize(`📄 ${filePath}`, 'bold'));
|
|
35
|
+
for (const finding of result.findings) {
|
|
36
|
+
console.log(` ${formatFinding(finding)}`);
|
|
37
|
+
}
|
|
38
|
+
console.log('');
|
|
39
|
+
allFindings = allFindings.concat(
|
|
40
|
+
result.findings.map((f) => ({ ...f, file: filePath }))
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (allFindings.length === 0) {
|
|
46
|
+
console.log(colorize('✓ No sensitive information detected!', 'green'));
|
|
47
|
+
} else {
|
|
48
|
+
console.log(colorize(`Found ${allFindings.length} potential issue(s)`, 'yellow'));
|
|
49
|
+
if (allFindings.some((f) => f.severity === 'critical')) {
|
|
50
|
+
console.log(colorize(' Critical issues found! Do not commit these files.', 'red'));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log('');
|
|
55
|
+
|
|
56
|
+
if (allFindings.some((f) => f.severity === 'critical') && !options.allowFailure) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { findings: allFindings, total: allFindings.length };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { runCheck };
|