api-key-guard 1.0.3 → 1.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/README.md CHANGED
@@ -1,84 +1,486 @@
1
- # 🔐 api-key-guard
1
+ # 🔐 API Key Guard
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/api-key-guard.svg)](https://www.npmjs.com/package/api-key-guard)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/api-key-guard.svg)](https://www.npmjs.com/package/api-key-guard)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
- ## Project Title & Description
7
+ A comprehensive CLI tool for detecting, preventing, and managing API key leaks in your codebase with AI-powered documentation generation.
8
8
 
9
- **api-key-guard** is a comprehensive Node.js CLI tool designed to help developers and teams detect, prevent, and manage API key leaks within their codebases. It provides powerful scanning capabilities, integrates seamlessly with Git hooks, and even offers AI-powered assistance for project documentation, ensuring your secrets stay secret.
9
+ ## Quick Start
10
10
 
11
- ## ⚠️ Problem Statement: The Silent Threat of API Key Leaks
11
+ ```bash
12
+ # Install globally
13
+ npm install -g api-key-guard
12
14
 
13
- Accidentally committing API keys, private tokens, or sensitive credentials to a public or even private repository is a widespread and critical security vulnerability. A single leaked key can lead to:
15
+ # Scan for API key leaks
16
+ api-key-guard scan
14
17
 
15
- * **Data Breaches:** Unauthorized access to sensitive user data.
16
- * **Financial Loss:** Misuse of cloud resources, payment gateways, or premium services.
17
- * **Reputational Damage:** Erosion of trust from customers and partners.
18
- * **Service Interruptions:** Malicious actors disabling or disrupting your services.
18
+ # Setup git hooks for automatic scanning
19
+ api-key-guard setup-hooks
19
20
 
20
- Traditional methods often rely on manual reviews or simplistic grep commands, which are prone to error and can't keep pace with rapid development cycles. **api-key-guard** provides an automated, intelligent solution to proactively safeguard your repositories against this silent, yet devastating, threat.
21
+ # Generate AI-powered README (requires GEMINI_API_KEY)
22
+ export GEMINI_API_KEY=your_api_key_here
23
+ api-key-guard readme
24
+ ```
21
25
 
22
- ## Features List
26
+ ## 🚨 The Problem
23
27
 
24
- **api-key-guard** comes packed with features to make API key management robust and effortless:
28
+ API key leaks in code repositories are a critical security vulnerability that can lead to:
25
29
 
26
- * 🔍 **Advanced API Key Detection:**
27
- * Utilizes a combination of regex patterns and entropy analysis to identify a wide range of common API keys (AWS, Google Cloud, Stripe, GitHub, etc.) and high-entropy strings that might be custom secrets.
28
- * Scans various file types including JavaScript, TypeScript, Python, Ruby, JSON, YAML, Markdown, and more.
29
- * 🎣 **Seamless Git Hooks Integration:**
30
- * Set up pre-commit hooks to automatically scan staged files before every commit, preventing secrets from ever reaching your repository.
31
- * Provides clear feedback and blocks commits if a leak is detected.
32
- * 🚀 **Powerful CLI Commands:**
33
- * `scan`: On-demand scanning of entire directories or specific files.
34
- * `setup-hooks`: Automates the installation of Git pre-commit hooks.
35
- * `readme`: Leverages AI to generate comprehensive `README.md` files based on your project's structure and existing documentation.
36
- * 🤖 **AI-Powered README Generation:**
37
- * A unique feature that helps you quickly generate professional and informative `README.md` files, improving project documentation and onboarding.
38
- * 📁 **Multiple File Format Support:**
39
- * Intelligently parses and scans a broad spectrum of text-based file formats, ensuring no stone is left unturned.
40
- * ⚙️ **Configurable Ignore Patterns:**
41
- * Define custom ignore rules in configuration files or via CLI flags to exclude specific files, directories (e.g., `node_modules`, `dist`), or even patterns of "false positive" keys, reducing noise.
42
- * 🌈 **Colorful and Clear Output:**
43
- * Leverages `chalk` to provide easy-to-read, color-coded output in the terminal, highlighting detected keys and scan results.
30
+ - **Data breaches** and unauthorized access
31
+ - **Financial losses** from misused cloud resources
32
+ - **Service disruptions** and security incidents
33
+ - **Reputational damage** from exposed credentials
44
34
 
45
- ## 🛠️ Installation
35
+ ## Features
36
+
37
+ - 🔍 **Smart Detection**: Advanced regex patterns detect AWS keys, GitHub tokens, Google API keys, and more
38
+ - � **Auto-Fix Keys**: Automatically replace hardcoded keys with environment variables
39
+ - �🔒 **Git Hooks Integration**: Automatic pre-commit scanning to prevent leaks
40
+ - 🤖 **AI-Powered README**: Generate professional documentation using Google's Gemini API
41
+ - ⚡ **Fast Scanning**: Efficient file parsing with configurable ignore patterns
42
+ - 🌈 **Clear Output**: Color-coded results with detailed reporting
43
+ - 📋 **Multiple Formats**: Support for JS, TS, Python, JSON, YAML, ENV files, and more
46
44
 
47
- **Prerequisites:**
45
+ ## 📋 CLI Commands
48
46
 
49
- * Node.js (v14 or higher)
50
- * npm (v6 or higher)
47
+ ### Scan for API Keys
48
+ ```bash
49
+ # Scan current directory
50
+ api-key-guard scan
51
+
52
+ # Scan specific path
53
+ api-key-guard scan --path ./src
51
54
 
52
- Install `api-key-guard` globally using npm:
55
+ # Verbose output with pattern details
56
+ api-key-guard scan --verbose
57
+ ```
53
58
 
59
+ ### Fix Hardcoded Keys
54
60
  ```bash
55
- npm install -g api-key-guard
61
+ # Automatically fix hardcoded API keys
62
+ api-key-guard fix
63
+
64
+ # Preview fixes without applying
65
+ api-key-guard fix --dry-run
66
+
67
+ # Fix specific file only
68
+ api-key-guard fix --file src/config.js
69
+
70
+ # Fix without creating backups
71
+ api-key-guard fix --no-backup
56
72
  ```
57
73
 
58
- Verify the installation by checking the version:
74
+ ### Git Hooks Setup
75
+ ```bash
76
+ # Install pre-commit hook
77
+ api-key-guard setup-hooks
78
+ ```
59
79
 
80
+ ### AI README Generation
81
+ ```bash
82
+ # Generate README.md
83
+ api-key-guard readme
84
+
85
+ # Force overwrite existing file
86
+ api-key-guard readme --force
87
+
88
+ # Custom output file
89
+ api-key-guard readme --output DOCUMENTATION.md
90
+ ```
91
+
92
+ ## 🛠️ Installation
93
+
94
+ **Prerequisites:** Node.js 14+ and npm
95
+
96
+ ```bash
97
+ # Global installation (recommended)
98
+ npm install -g api-key-guard
99
+
100
+ # Local project installation
101
+ npm install --save-dev api-key-guard
102
+ ```
103
+
104
+ **Verify installation:**
60
105
  ```bash
61
106
  api-key-guard --version
62
107
  ```
63
108
 
109
+ ## 🔑 API Key Types Detected
110
+
111
+ - **AWS Access Keys**: `AKIA...`
112
+ - **GitHub Tokens**: `ghp_...`, `github_pat_...`
113
+ - **Google API Keys**: `AIza...`
114
+ - **Generic Patterns**: `api_key`, `secret_key`, `access_token`
115
+ - **Bearer Tokens**: `Bearer ...`
116
+ - **Custom Patterns**: High-entropy strings
117
+
118
+ ## 🤖 AI README Generation
119
+
120
+ The `readme` command uses Google's Gemini API to generate comprehensive documentation:
121
+
122
+ ### Setup
123
+ 1. Get API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
124
+ 2. Set environment variable:
125
+ ```bash
126
+ export GEMINI_API_KEY=your_api_key_here
127
+ ```
128
+
129
+ ### Generated Content
130
+ - Project overview and description
131
+ - Installation instructions
132
+ - Usage examples and CLI documentation
133
+ - Security best practices
134
+ - Contributing guidelines
135
+
136
+ ## ⚙️ Configuration
137
+
138
+ Create `.api-key-guard.json` in your project root:
139
+
140
+ ```json
141
+ {
142
+ "ignorePatterns": [
143
+ "node_modules/**",
144
+ "dist/**",
145
+ "*.min.js",
146
+ "test/**/*.fixture.js"
147
+ ],
148
+ "customPatterns": [
149
+ {
150
+ "name": "Custom API Key",
151
+ "pattern": "custom_key_[0-9a-f]{32}"
152
+ }
153
+ ]
154
+ }
155
+ ```
156
+
157
+ ## 🔐 Git Hooks
158
+
159
+ The `setup-hooks` command creates a pre-commit hook that:
160
+
161
+ 1. Scans staged files for API keys
162
+ 2. Blocks commits if leaks are detected
163
+ 3. Provides clear feedback on detected patterns
164
+ 4. Allows bypass with `--no-verify` if needed
165
+
166
+ ## 🛡️ Security Features
167
+
168
+ - **Zero Storage**: API keys are never stored or logged
169
+ - **Environment Variables**: Secure handling of authentication tokens
170
+ - **Pattern Matching**: Regular expressions detect common key formats
171
+ - **Entropy Analysis**: Identifies high-entropy strings that may be secrets
172
+ - **Configurable Scanning**: Customize patterns and ignore rules
173
+
174
+ ## 📊 Usage Examples
175
+
176
+ **Basic Scanning:**
177
+ ```bash
178
+ api-key-guard scan
179
+ # ✅ No potential API key leaks detected!
180
+ ```
181
+
182
+ **With API Key Detection:**
183
+ ```bash
184
+ api-key-guard scan --verbose
185
+ # 🚨 Found 2 potential API key leak(s):
186
+ # 📄 src/config.js:15
187
+ # Pattern: AKIA1234567890ABCDEF
188
+ # 📄 .env.example:3
189
+ # Pattern: sk-1234567890abcdef...
190
+ ```
191
+
192
+ **Automatic Key Fixing:**
193
+ ```bash
194
+ api-key-guard fix --dry-run
195
+ # 📋 Found 3 fixable API key(s):
196
+ # 📄 src/config.js:15
197
+ # const apiKey = "sk-1234567890abcdef"
198
+ # → const apiKey = process.env.API_KEY
199
+ #
200
+ # 📄 src/auth.js:8
201
+ # const token = "ghp_abcdefghijklmnop"
202
+ # → const token = process.env.GITHUB_TOKEN
203
+
204
+ # Apply fixes
205
+ api-key-guard fix
206
+ # 🔧 Applying fixes...
207
+ # ✅ Successfully fixed 3 API keys!
208
+ # 📝 Updated 2 file(s)
209
+ # 🔐 Added 3 environment variable(s)
210
+ ```
211
+
212
+ ## 🤝 Contributing
213
+
214
+ 1. Fork the repository
215
+ 2. Create a feature branch: `git checkout -b feature/amazing-feature`
216
+ 3. Commit changes: `git commit -m 'Add amazing feature'`
217
+ 4. Push to branch: `git push origin feature/amazing-feature`
218
+ 5. Open a Pull Request
219
+
220
+ ## 📄 License
221
+
222
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
223
+
224
+ ## 🙋‍♂️ Support
225
+
226
+ - 📖 [Documentation](https://www.npmjs.com/package/api-key-guard)
227
+ - 🐛 [Report Issues](https://github.com/yourusername/api-key-guard/issues)
228
+ - 💬 [Discussions](https://github.com/yourusername/api-key-guard/discussions)
229
+
230
+ ---
231
+
232
+ **Made with ❤️ for developer security**
233
+ npm install --save-dev api-key-guard
234
+ ```
235
+
64
236
  ## 🚀 CLI Usage Examples
65
237
 
66
- `api-key-guard` provides a simple yet powerful command-line interface.
238
+ `api-key-guard` provides several commands for different use cases.
67
239
 
68
- ### 1. `api-key-guard scan` - Scan your codebase for API keys
240
+ ### 🔍 `api-key-guard scan` - Detect API Keys
69
241
 
70
- Scan a directory or specific files for potential API key leaks.
242
+ Scans your project for potential API key leaks.
71
243
 
72
- #### Basic Scan of Current Directory:
244
+ **Basic Scan (current directory):**
73
245
 
74
246
  ```bash
75
247
  api-key-guard scan .
76
248
  ```
77
249
 
78
- #### Scan a Specific File:
250
+ **Scan a specific directory:**
251
+
252
+ ```bash
253
+ api-key-guard scan src/
254
+ ```
255
+
256
+ **Scan a specific file:**
257
+
258
+ ```bash
259
+ api-key-guard scan config/secrets.js
260
+ ```
261
+
262
+ **Verbose output (shows more details about detection):**
263
+
264
+ ```bash
265
+ api-key-guard scan . --verbose
266
+ ```
267
+
268
+ **Fail on leak (exit with a non-zero code if leaks are found, useful for CI/CD):**
269
+
270
+ ```bash
271
+ api-key-guard scan . --fail-on-leak
272
+ ```
273
+
274
+ **Include specific file types (comma-separated):**
275
+
276
+ ```bash
277
+ api-key-guard scan . --include "*.js,*.ts,*.env"
278
+ ```
279
+
280
+ **Exclude specific file types (comma-separated):**
281
+
282
+ ```bash
283
+ api-key-guard scan . --exclude "*.min.js,*.lock"
284
+ ```
285
+
286
+ **Ignore files or directories using patterns (shell-like glob patterns):**
287
+
288
+ ```bash
289
+ api-key-guard scan . --ignore-pattern "node_modules/**" --ignore-pattern "dist/*"
290
+ ```
291
+
292
+ **Use a `.gitignore` file for ignore patterns:**
293
+
294
+ ```bash
295
+ api-key-guard scan . --ignore-file .gitignore
296
+ ```
297
+
298
+ **Combine options:**
299
+
300
+ ```bash
301
+ api-key-guard scan src/ --fail-on-leak --verbose --ignore-file .gitignore --include "*.js,*.ts"
302
+ ```
303
+
304
+ ### 🎣 `api-key-guard setup-hooks` - Integrate Git Hooks
305
+
306
+ Sets up Git pre-commit and/or pre-push hooks to automatically scan for keys before commits or pushes.
307
+
308
+ **Set up pre-commit hook (default):**
309
+
310
+ ```bash
311
+ api-key-guard setup-hooks
312
+ ```
313
+
314
+ This will configure your local `.git/hooks/pre-commit` script to run `api-key-guard scan --fail-on-leak` on staged files.
315
+
316
+ **Set up pre-push hook:**
317
+
318
+ ```bash
319
+ api-key-guard setup-hooks --hook pre-push
320
+ ```
321
+
322
+ This will configure your local `.git/hooks/pre-push` script to run `api-key-guard scan --fail-on-leak` on all changes being pushed.
323
+
324
+ **Remove existing hooks (if you need to clean up):**
79
325
 
80
326
  ```bash
81
- api-key-guard scan src/utils/api.js
327
+ api-key-guard setup-hooks --remove
82
328
  ```
83
329
 
84
- #### Scan a Specific Directory with
330
+ ### 📝 `api-key-guard readme` - Generate READMEs with AI
331
+
332
+ Leverages AI to help you generate a professional README.md for your project. (Requires an active internet connection and potentially an API key for the AI service, configured via environment variables).
333
+
334
+ **Generate a README with a prompt:**
335
+
336
+ ```bash
337
+ api-key-guard readme "Generate a README for a Node.js CLI tool that detects API keys, focusing on its security benefits and ease of use."
338
+ ```
339
+
340
+ **Generate and save to a specific file:**
341
+
342
+ ```bash
343
+ api-key-guard readme --output docs/PROJECT_README.md "Generate a simple README for a web application using React and Node.js."
344
+ ```
345
+
346
+ ## 🎣 Git Hooks Usage
347
+
348
+ Once you've set up Git hooks using `api-key-guard setup-hooks`, the tool will automatically run during your `git commit` or `git push` operations.
349
+
350
+ **Example of a pre-commit hook in action:**
351
+
352
+ 1. You have `api-key-guard` pre-commit hook enabled.
353
+ 2. You accidentally add a file containing a hardcoded API key:
354
+ ```javascript
355
+ // src/config.js
356
+ const API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // BAD PRACTICE!
357
+ ```
358
+ 3. You stage the file:
359
+ ```bash
360
+ git add src/config.js
361
+ ```
362
+ 4. You try to commit:
363
+ ```bash
364
+ git commit -m "Add new config"
365
+ ```
366
+ 5. `api-key-guard` will detect the leak, prevent the commit, and display a warning:
367
+ ```
368
+ 🚨 api-key-guard: Potential API key leak detected in staged files! 🚨
369
+ Path: src/config.js
370
+ Line 2: const API_KEY = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
371
+
372
+ Commit aborted. Please remove or secure the sensitive information.
373
+ If you need to bypass, use 'git commit --no-verify'.
374
+ ```
375
+
376
+ To bypass the hook for a single commit (use with extreme caution!):
377
+
378
+ ```bash
379
+ git commit -m "Temporary commit, will fix secrets later" --no-verify
380
+ ```
381
+
382
+ ## ⚙️ Configuration
383
+
384
+ `api-key-guard` can be configured using a `api-key-guard.config.json` file at the root of your project. This allows you to define custom rules, ignore patterns, and scanner settings.
385
+
386
+ **Example `api-key-guard.config.json`:**
387
+
388
+ ```json
389
+ {
390
+ "scanPaths": [
391
+ "src/",
392
+ "config/",
393
+ "server/"
394
+ ],
395
+ "ignorePatterns": [
396
+ "node_modules/**",
397
+ "dist/**",
398
+ "*.min.js",
399
+ "*.log",
400
+ "testdata/**"
401
+ ],
402
+ "ignoreFiles": [
403
+ ".gitignore",
404
+ ".dockerignore"
405
+ ],
406
+ "includeFileTypes": [
407
+ "*.js",
408
+ "*.ts",
409
+ "*.env",
410
+ "*.json",
411
+ "*.yaml",
412
+ "*.yml"
413
+ ],
414
+ "excludeFileTypes": [
415
+ "*.lock",
416
+ "package-lock.json"
417
+ ],
418
+ "customRules": [
419
+ {
420
+ "name": "Custom-API-Key",
421
+ "regex": "MY_CUSTOM_API_KEY_[a-zA-Z0-9]{32,64}",
422
+ "description": "Detects specific internal API keys."
423
+ }
424
+ ],
425
+ "failOnLeak": true,
426
+ "verbose": false
427
+ }
428
+ ```
429
+
430
+ * **`scanPaths`**: An array of glob patterns for directories or files to explicitly scan. If empty, the current directory (`.`) is scanned.
431
+ * **`ignorePatterns`**: An array of glob patterns for files or directories to ignore during scanning.
432
+ * **`ignoreFiles`**: An array of filenames (e.g., `.gitignore`) whose contents will be used as additional ignore patterns.
433
+ * **`includeFileTypes`**: An array of glob patterns for file types to explicitly include. If specified, only these types will be scanned.
434
+ * **`excludeFileTypes`**: An array of glob patterns for file types to explicitly exclude.
435
+ * **`customRules`**: An array of custom regex rules for detecting specific patterns. Each rule should have a `name`, `regex`, and `description`.
436
+ * **`failOnLeak`**: Boolean. If `true`, the CLI will exit with a non-zero code if any leaks are found.
437
+ * **`verbose`**: Boolean. If `true`, more detailed output will be provided.
438
+
439
+ ## 🔒 Security Best Practices
440
+
441
+ While `api-key-guard` is a powerful tool, it's part of a broader security strategy. Always adhere to these best practices:
442
+
443
+ * **🚫 Never Hardcode Secrets:** The golden rule. Avoid placing API keys, passwords, or sensitive tokens directly in your code.
444
+ * **🌳 Use Environment Variables:** For development and deployment, load secrets from environment variables (e.g., using `.env` files locally and proper environment variable injection in production).
445
+ * **🔐 Employ Secret Management Services:** For production environments, utilize dedicated secret management services like AWS Secrets Manager, Azure Key Vault, Google Secret Manager, HashiCorp Vault, or similar.
446
+ * **🔑 Implement Least Privilege:** Grant API keys only the minimum necessary permissions required for their function.
447
+ * **🔄 Rotate Keys Regularly:** Periodically change your API keys, especially if they are long-lived.
448
+ * **📚 Educate Your Team:** Ensure all developers understand the risks of secret exposure and the proper procedures for handling sensitive information.
449
+ * **⚙️ Integrate into CI/CD:** Incorporate `api-key-guard` scans into your Continuous Integration/Continuous Deployment pipelines to catch leaks before deployment.
450
+
451
+ `api-key-guard` helps you catch mistakes, but proactive secure coding practices are paramount.
452
+
453
+ ## 🛣️ Future Roadmap
454
+
455
+ We are continuously working to enhance `api-key-guard`. Here are some planned features:
456
+
457
+ * **Advanced Entropy Analysis:** Improve detection of generic high-entropy strings that might indicate secrets without specific patterns.
458
+ * **Machine Learning-Based Detection:** Explore ML models for more intelligent and adaptive secret detection.
459
+ * **Cloud Provider Integrations:** Direct integrations with AWS, Azure, GCP for scanning cloud-specific credential formats.
460
+ * **Reporting & Alerting:** Generate detailed reports and integrate with alerting systems (e.g., Slack, email) when leaks are detected in CI/CD.
461
+ * **Support for More Secret Types:** Expand detection to include private keys, database connection strings, access tokens, etc.
462
+ * **IDE Extensions:** Develop extensions for popular IDEs (VS Code, IntelliJ) for real-time feedback.
463
+ * **Web UI for Centralized Management:** A future goal for larger teams to manage configurations and view scan results centrally.
464
+
465
+ ## 🤝 Contributing
466
+
467
+ We welcome contributions to `api-key-guard`! Whether it's bug reports, feature requests, or code contributions, your help is valuable.
468
+
469
+ 1. **Report Bugs:** If you find a bug, please open an issue on GitHub, providing detailed steps to reproduce, expected behavior, and actual behavior.
470
+ 2. **Suggest Features:** Have an idea for a new feature or improvement? Open an issue to discuss it.
471
+ 3. **Code Contributions:**
472
+ * Fork the repository.
473
+ * Create a new branch (`git checkout -b feature/your-feature-name` or `fix/bug-fix-description`).
474
+ * Make your changes.
475
+ * Write tests for your changes.
476
+ * Ensure your code adheres to the project's coding style.
477
+ * Commit your changes (`git commit -m "feat: Add new feature"`) using conventional commits.
478
+ * Push to your fork (`git push origin feature/your-feature-name`).
479
+ * Open a Pull Request to the `main` branch of the original repository.
480
+
481
+ Please adhere to our Code of Conduct.
482
+
483
+ ## 📄 License
484
+
485
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
486
+ ```
package/bin/cli.js CHANGED
@@ -5,6 +5,7 @@ const chalk = require('chalk');
5
5
  const { generateReadme } = require('../src/readmeGenerator');
6
6
  const { scanForApiKeys } = require('../src/scanner');
7
7
  const { setupGitHooks } = require('../src/gitHooks');
8
+ const { fixApiKeys } = require('../src/keyFixer');
8
9
 
9
10
  const program = new Command();
10
11
 
@@ -59,4 +60,22 @@ program
59
60
  }
60
61
  });
61
62
 
63
+ // Fix API keys command
64
+ program
65
+ .command('fix')
66
+ .description('Automatically replace hardcoded API keys with environment variables')
67
+ .option('-p, --path <path>', 'Path to scan and fix', '.')
68
+ .option('-d, --dry-run', 'Preview changes without applying them')
69
+ .option('-f, --file <file>', 'Fix specific file only')
70
+ .option('--backup', 'Create backup files before fixing', true)
71
+ .action(async (options) => {
72
+ try {
73
+ console.log(chalk.blue('🔧 Fixing hardcoded API keys...'));
74
+ await fixApiKeys(options);
75
+ } catch (error) {
76
+ console.error(chalk.red('Error fixing keys:', error.message));
77
+ process.exit(1);
78
+ }
79
+ });
80
+
62
81
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-key-guard",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "A comprehensive tool to detect, prevent, and manage API key leaks in your codebase with AI-powered README generation",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  const { scanForApiKeys } = require('./scanner');
2
2
  const { setupGitHooks } = require('./gitHooks');
3
3
  const { generateReadme } = require('./readmeGenerator');
4
+ const { fixApiKeys } = require('./keyFixer');
4
5
 
5
6
  module.exports = {
6
7
  scanForApiKeys,
7
8
  setupGitHooks,
8
- generateReadme
9
+ generateReadme,
10
+ fixApiKeys
9
11
  };
@@ -0,0 +1,406 @@
1
+ const fs = require('fs').promises;
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const readline = require('readline');
5
+
6
+ /**
7
+ * Fix hardcoded API keys by replacing them with environment variables
8
+ */
9
+ async function fixApiKeys(options = {}) {
10
+ const scanPath = options.path || '.';
11
+ const dryRun = options.dryRun || false;
12
+ const specificFile = options.file;
13
+ const createBackup = options.backup !== false;
14
+
15
+ console.log(chalk.blue(`🔍 Scanning for fixable API keys in ${scanPath}...`));
16
+
17
+ const findings = await scanForFixableKeys(scanPath, specificFile);
18
+
19
+ if (findings.length === 0) {
20
+ console.log(chalk.green('✅ No fixable API keys found!'));
21
+ return;
22
+ }
23
+
24
+ console.log(chalk.yellow(`📋 Found ${findings.length} fixable API key(s):`));
25
+ findings.forEach(finding => {
26
+ console.log(chalk.cyan(` 📄 ${finding.file}:${finding.line}`));
27
+ console.log(chalk.gray(` ${finding.originalLine.trim()}`));
28
+ console.log(chalk.green(` → ${finding.fixedLine.trim()}`));
29
+ });
30
+
31
+ if (dryRun) {
32
+ console.log(chalk.blue('\n🔍 Dry run complete. No changes were made.'));
33
+ console.log(chalk.gray('Run without --dry-run to apply fixes.'));
34
+ return;
35
+ }
36
+
37
+ const shouldProceed = await promptConfirmation(
38
+ `\n❓ Apply these ${findings.length} fixes? (y/N): `
39
+ );
40
+
41
+ if (!shouldProceed) {
42
+ console.log(chalk.yellow('Operation cancelled.'));
43
+ return;
44
+ }
45
+
46
+ console.log(chalk.blue('🔧 Applying fixes...'));
47
+
48
+ const results = await applyFixes(findings, createBackup);
49
+ await updateEnvironmentFiles(results.envVars);
50
+ await updateGitignore();
51
+
52
+ console.log(chalk.green(`✅ Successfully fixed ${results.fixedCount} API keys!`));
53
+ console.log(chalk.blue(`📝 Updated ${results.filesModified} file(s)`));
54
+ console.log(chalk.blue(`🔐 Added ${results.envVars.length} environment variable(s)`));
55
+
56
+ if (createBackup) {
57
+ console.log(chalk.gray(`💾 Backup files created with .backup extension`));
58
+ }
59
+
60
+ console.log(chalk.yellow('\n⚠️ Next steps:'));
61
+ console.log(chalk.yellow(' 1. Review the generated .env file'));
62
+ console.log(chalk.yellow(' 2. Add .env to your .gitignore (done automatically)'));
63
+ console.log(chalk.yellow(' 3. Update your deployment with the new environment variables'));
64
+ }
65
+
66
+ /**
67
+ * Scan for API keys that can be automatically fixed
68
+ */
69
+ async function scanForFixableKeys(scanPath, specificFile) {
70
+ const findings = [];
71
+
72
+ // Key patterns that can be fixed automatically
73
+ const fixablePatterns = [
74
+ {
75
+ name: 'JavaScript/TypeScript API Key Assignment',
76
+ pattern: /^(\s*)(const|let|var)\s+(\w+)\s*=\s*['"`]([A-Za-z0-9_\-]{20,})['"`]/gm,
77
+ language: 'javascript',
78
+ envVarNamer: (varName) => varName.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase()
79
+ },
80
+ {
81
+ name: 'Python API Key Assignment',
82
+ pattern: /^(\s*)(\w+)\s*=\s*['"`]([A-Za-z0-9_\-]{20,})['"`]/gm,
83
+ language: 'python',
84
+ envVarNamer: (varName) => varName.replace(/([a-z])([A-Z])/g, '$1_$2').upper()
85
+ },
86
+ {
87
+ name: 'JSON Configuration',
88
+ pattern: /"(\w*[Kk]ey\w*|token|secret)"\s*:\s*"([A-Za-z0-9_\-]{20,})"/gm,
89
+ language: 'json',
90
+ envVarNamer: (keyName) => keyName.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase()
91
+ }
92
+ ];
93
+
94
+ const files = specificFile ? [specificFile] : await getFilesRecursively(scanPath);
95
+
96
+ for (const file of files) {
97
+ try {
98
+ const content = await fs.readFile(file, 'utf8');
99
+ const lines = content.split('\n');
100
+
101
+ for (const patternConfig of fixablePatterns) {
102
+ let match;
103
+ patternConfig.pattern.lastIndex = 0; // Reset regex
104
+
105
+ while ((match = patternConfig.pattern.exec(content)) !== null) {
106
+ const lineNumber = content.substring(0, match.index).split('\n').length;
107
+ const originalLine = lines[lineNumber - 1];
108
+
109
+ let envVarName, fixedLine;
110
+
111
+ if (patternConfig.language === 'javascript') {
112
+ const [, indent, declaration, varName, keyValue] = match;
113
+ envVarName = patternConfig.envVarNamer(varName);
114
+ fixedLine = `${indent}${declaration} ${varName} = process.env.${envVarName}`;
115
+ } else if (patternConfig.language === 'python') {
116
+ const [, indent, varName, keyValue] = match;
117
+ envVarName = patternConfig.envVarNamer(varName);
118
+ fixedLine = `${indent}${varName} = os.getenv('${envVarName}')`;
119
+ } else if (patternConfig.language === 'json') {
120
+ const [fullMatch, keyName, keyValue] = match;
121
+ envVarName = patternConfig.envVarNamer(keyName);
122
+ // For JSON, we might suggest moving to a config loader
123
+ fixedLine = `"${keyName}": "${process.env.${envVarName} || 'YOUR_${envVarName}_HERE'}"`;
124
+ }
125
+
126
+ // Only include keys that look like real API keys
127
+ const keyValue = patternConfig.language === 'json' ? match[2] :
128
+ patternConfig.language === 'python' ? match[3] : match[4];
129
+
130
+ if (looksLikeApiKey(keyValue)) {
131
+ findings.push({
132
+ file: path.relative(process.cwd(), file),
133
+ line: lineNumber,
134
+ originalLine,
135
+ fixedLine,
136
+ envVarName,
137
+ keyValue,
138
+ language: patternConfig.language,
139
+ pattern: patternConfig.name
140
+ });
141
+ }
142
+ }
143
+ }
144
+ } catch (error) {
145
+ // Skip files we can't read
146
+ continue;
147
+ }
148
+ }
149
+
150
+ return findings;
151
+ }
152
+
153
+ /**
154
+ * Apply the fixes to files
155
+ */
156
+ async function applyFixes(findings, createBackup) {
157
+ const results = {
158
+ fixedCount: 0,
159
+ filesModified: 0,
160
+ envVars: []
161
+ };
162
+
163
+ const fileGroups = groupFindingsByFile(findings);
164
+
165
+ for (const [filePath, fileFindings] of Object.entries(fileGroups)) {
166
+ try {
167
+ const fullPath = path.resolve(filePath);
168
+ const content = await fs.readFile(fullPath, 'utf8');
169
+ const lines = content.split('\n');
170
+
171
+ // Create backup if requested
172
+ if (createBackup) {
173
+ await fs.writeFile(`${fullPath}.backup`, content, 'utf8');
174
+ }
175
+
176
+ // Apply fixes (in reverse order to maintain line numbers)
177
+ const sortedFindings = fileFindings.sort((a, b) => b.line - a.line);
178
+
179
+ for (const finding of sortedFindings) {
180
+ lines[finding.line - 1] = finding.fixedLine;
181
+ results.fixedCount++;
182
+
183
+ // Collect environment variables
184
+ results.envVars.push({
185
+ name: finding.envVarName,
186
+ value: finding.keyValue,
187
+ comment: `# ${finding.pattern} from ${finding.file}:${finding.line}`
188
+ });
189
+ }
190
+
191
+ // Write the fixed content
192
+ await fs.writeFile(fullPath, lines.join('\n'), 'utf8');
193
+ results.filesModified++;
194
+
195
+ } catch (error) {
196
+ console.error(chalk.red(`Error fixing ${filePath}: ${error.message}`));
197
+ }
198
+ }
199
+
200
+ return results;
201
+ }
202
+
203
+ /**
204
+ * Update or create environment files
205
+ */
206
+ async function updateEnvironmentFiles(envVars) {
207
+ const envPath = path.join(process.cwd(), '.env');
208
+ const envExamplePath = path.join(process.cwd(), '.env.example');
209
+
210
+ // Read existing .env file if it exists
211
+ let existingEnvContent = '';
212
+ try {
213
+ existingEnvContent = await fs.readFile(envPath, 'utf8');
214
+ } catch (error) {
215
+ // File doesn't exist, will create new
216
+ }
217
+
218
+ // Prepare new environment variables
219
+ const newEnvLines = [];
220
+ const exampleLines = [];
221
+
222
+ for (const envVar of envVars) {
223
+ // Only add if not already in .env file
224
+ if (!existingEnvContent.includes(`${envVar.name}=`)) {
225
+ newEnvLines.push('');
226
+ newEnvLines.push(envVar.comment);
227
+ newEnvLines.push(`${envVar.name}=${envVar.value}`);
228
+
229
+ // Add to example file (without real values)
230
+ exampleLines.push('');
231
+ exampleLines.push(envVar.comment);
232
+ exampleLines.push(`${envVar.name}=your_${envVar.name.toLowerCase()}_here`);
233
+ }
234
+ }
235
+
236
+ if (newEnvLines.length > 0) {
237
+ // Append to .env file
238
+ const updatedContent = existingEnvContent + '\n# Added by api-key-guard fix command' + newEnvLines.join('\n') + '\n';
239
+ await fs.writeFile(envPath, updatedContent, 'utf8');
240
+
241
+ // Create/update .env.example
242
+ let exampleContent = '';
243
+ try {
244
+ exampleContent = await fs.readFile(envExamplePath, 'utf8');
245
+ } catch (error) {
246
+ exampleContent = '# Environment variables template\n# Copy to .env and fill with real values\n';
247
+ }
248
+
249
+ const updatedExampleContent = exampleContent + '\n# Added by api-key-guard fix command' + exampleLines.join('\n') + '\n';
250
+ await fs.writeFile(envExamplePath, updatedExampleContent, 'utf8');
251
+ }
252
+ }
253
+
254
+ /**
255
+ * Update .gitignore to include .env
256
+ */
257
+ async function updateGitignore() {
258
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
259
+
260
+ try {
261
+ let gitignoreContent = '';
262
+ try {
263
+ gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
264
+ } catch (error) {
265
+ // File doesn't exist, create new
266
+ gitignoreContent = '';
267
+ }
268
+
269
+ // Check if .env is already ignored
270
+ if (!gitignoreContent.includes('.env') || !gitignoreContent.includes('*.env')) {
271
+ const envIgnoreRules = [
272
+ '\n# Environment variables (added by api-key-guard)',
273
+ '.env',
274
+ '.env.local',
275
+ '.env.*.local',
276
+ '*.env\n'
277
+ ];
278
+
279
+ const updatedContent = gitignoreContent + envIgnoreRules.join('\n');
280
+ await fs.writeFile(gitignorePath, updatedContent, 'utf8');
281
+ }
282
+ } catch (error) {
283
+ console.warn(chalk.yellow('Warning: Could not update .gitignore'));
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Check if a string looks like a real API key
289
+ */
290
+ function looksLikeApiKey(str) {
291
+ // Basic heuristics for API keys
292
+ const minLength = 20;
293
+ const hasLettersAndNumbers = /[a-zA-Z]/.test(str) && /[0-9]/.test(str);
294
+ const notCommonWords = !['example', 'test', 'demo', 'sample', 'placeholder', 'your'].some(word =>
295
+ str.toLowerCase().includes(word));
296
+
297
+ return str.length >= minLength && hasLettersAndNumbers && notCommonWords;
298
+ }
299
+
300
+ /**
301
+ * Group findings by file path
302
+ */
303
+ function groupFindingsByFile(findings) {
304
+ const groups = {};
305
+ for (const finding of findings) {
306
+ if (!groups[finding.file]) {
307
+ groups[finding.file] = [];
308
+ }
309
+ groups[finding.file].push(finding);
310
+ }
311
+ return groups;
312
+ }
313
+
314
+ /**
315
+ * Get all files recursively, respecting ignore patterns
316
+ */
317
+ async function getFilesRecursively(dir, ignorePatterns = []) {
318
+ let files = [];
319
+
320
+ const defaultIgnores = [
321
+ 'node_modules', '.git', 'dist', 'build', '.next', 'coverage',
322
+ '*.min.js', '*.bundle.js', 'package-lock.json', 'yarn.lock'
323
+ ];
324
+
325
+ const allIgnores = [...defaultIgnores, ...ignorePatterns];
326
+
327
+ try {
328
+ const entries = await fs.readdir(dir, { withFileTypes: true });
329
+
330
+ for (const entry of entries) {
331
+ const fullPath = path.join(dir, entry.name);
332
+
333
+ // Check if should be ignored
334
+ if (shouldIgnore(entry.name, fullPath, allIgnores)) {
335
+ continue;
336
+ }
337
+
338
+ if (entry.isDirectory()) {
339
+ files = files.concat(await getFilesRecursively(fullPath, ignorePatterns));
340
+ } else {
341
+ // Only scan text files that might contain code
342
+ if (isCodeFile(entry.name)) {
343
+ files.push(fullPath);
344
+ }
345
+ }
346
+ }
347
+ } catch (error) {
348
+ // Skip directories we can't read
349
+ }
350
+
351
+ return files;
352
+ }
353
+
354
+ /**
355
+ * Check if file should be ignored
356
+ */
357
+ function shouldIgnore(name, fullPath, ignorePatterns) {
358
+ for (const pattern of ignorePatterns) {
359
+ if (pattern.includes('*')) {
360
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
361
+ if (regex.test(name)) {
362
+ return true;
363
+ }
364
+ } else {
365
+ if (name === pattern || fullPath.includes(pattern)) {
366
+ return true;
367
+ }
368
+ }
369
+ }
370
+ return false;
371
+ }
372
+
373
+ /**
374
+ * Check if file is a code file that might contain API keys
375
+ */
376
+ function isCodeFile(filename) {
377
+ const codeExtensions = [
378
+ '.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.php', '.rb',
379
+ '.cs', '.cpp', '.c', '.h', '.rs', '.swift', '.kt', '.scala',
380
+ '.json', '.yml', '.yaml', '.xml', '.env', '.config', '.conf'
381
+ ];
382
+
383
+ const ext = path.extname(filename).toLowerCase();
384
+ return codeExtensions.includes(ext) || !ext; // Include files without extensions
385
+ }
386
+
387
+ /**
388
+ * Prompt user for confirmation
389
+ */
390
+ function promptConfirmation(question) {
391
+ return new Promise((resolve) => {
392
+ const rl = readline.createInterface({
393
+ input: process.stdin,
394
+ output: process.stdout
395
+ });
396
+
397
+ rl.question(question, (answer) => {
398
+ rl.close();
399
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
400
+ });
401
+ });
402
+ }
403
+
404
+ module.exports = {
405
+ fixApiKeys
406
+ };
@@ -108,7 +108,7 @@ async function generateWithGemini(apiKey, projectContext) {
108
108
  temperature: 0.7,
109
109
  topK: 40,
110
110
  topP: 0.95,
111
- maxOutputTokens: 2048,
111
+ maxOutputTokens: 8192,
112
112
  },
113
113
  safetySettings: [
114
114
  {