diff --git a/README.md b/README.md index ae4e889..b1827ea 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Scan your codebase to detect which environment variables are used in your code. Optimized for SvelteKit and Next.js.
Also works well in modern JavaScript/TypeScript projects and frameworks like Node.js, Nuxt, and Vue — or any other setup where you want reliable .env file comparison / scanning. +![CI](https://github.com/chrilleweb/dotenv-diff/actions/workflows/ci.yml/badge.svg) [![npm version](https://img.shields.io/npm/v/dotenv-diff.svg)](https://www.npmjs.com/package/dotenv-diff) [![npm downloads](https://img.shields.io/npm/dt/dotenv-diff.svg)](https://www.npmjs.com/package/dotenv-diff) @@ -347,12 +348,19 @@ This makes it quick to set up environment files without manually copying or rety `dotenv-diff` will warn you if your `.env` file is **not** ignored by Git. This helps prevent accidentally committing sensitive environment variables. +## Exit codes + +- `0` → No errors (warnings may be present unless `--strict`) +- `1` → Errors found (or warnings when using `--strict`) + ## 🤝 Contributing -Contributions are welcome! Feel free to open an issue or a pull request. +Issues, feature requests and pull requests are welcome. + +If you plan a larger change, please open an issue first to discuss scope and approach. ## License -MIT +Licensed under the [MIT](LICENSE) license. ### Created by [chrilleweb](https://github.com/chrilleweb) \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..2981dc9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +If you discover a security vulnerability, please report it responsibly. + +Send us an email to christian.munknissen@gmail.com and **don't** open a public issue. diff --git a/package.json b/package.json index 11f0eaa..f8e36bf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "dotenv-diff", "version": "2.3.11", "type": "module", - "description": "Scan your codebase to find environment variables in use.", + "description": "Detects environment variable issues, usage, and potential security risks.", "bin": { "dotenv-diff": "dist/bin/dotenv-diff.js" }, @@ -40,11 +40,17 @@ "dotenv", "env", "dotenv-diff", + "env-check", + "env-validate", + "env-scan", "cli", - "compare", - "environment variables", - "dotenv validator", - "scan codebase" + "config", + "security", + "ci", + "monorepo", + "sveltekit", + "nextjs", + "node" ], "repository": { "type": "git", diff --git a/src/cli/run.ts b/src/cli/run.ts index ea0c23b..3119bbf 100644 --- a/src/cli/run.ts +++ b/src/cli/run.ts @@ -3,7 +3,7 @@ import fs from 'fs'; import path from 'path'; import { normalizeOptions } from '../config/options.js'; import { discoverEnvFiles } from '../services/envDiscovery.js'; -import { pairWithExample } from '../services/envPairing.js'; +import { pairWithExample } from '../core/envPairing.js'; import { ensureFilesOrPrompt } from '../services/ensureFilesOrPrompt.js'; import { compareMany } from '../commands/compare.js'; import { diff --git a/src/core/determineComparisonFile.ts b/src/core/determineComparisonFile.ts index 7518e01..5785251 100644 --- a/src/core/determineComparisonFile.ts +++ b/src/core/determineComparisonFile.ts @@ -3,14 +3,26 @@ import path from 'path'; import { type ScanUsageOptions } from '../config/types.js'; import { resolveFromCwd } from './helpers/resolveFromCwd.js'; +type ComparisonFile = { + path: string; + name: string; +}; + +const DEFAULT_ENV_FILES = [ + '.env', + '.env.example', + '.env.local', + '.env.production', +] as const; + /** * Determines which file to use for comparison based on provided options * @param {ScanUsageOptions} opts - Scan configuration options - * @returns {Object|null} - The comparison file information or undefined if not found + * @returns Comparison file info with absolute path and basename, or undefined if not found */ export function determineComparisonFile( opts: ScanUsageOptions, -): { path: string; name: string } | undefined { +): ComparisonFile | undefined { // Priority: explicit flags first, then auto-discovery if (opts.examplePath) { @@ -28,8 +40,7 @@ export function determineComparisonFile( } // Auto-discovery: look for common env files relative to cwd - const candidates = ['.env', '.env.example', '.env.local', '.env.production']; - for (const candidate of candidates) { + for (const candidate of DEFAULT_ENV_FILES) { const fullPath = path.resolve(opts.cwd, candidate); if (fs.existsSync(fullPath)) { return { path: fullPath, name: candidate }; diff --git a/src/services/envPairing.ts b/src/core/envPairing.ts similarity index 81% rename from src/services/envPairing.ts rename to src/core/envPairing.ts index 9679d28..9267d57 100644 --- a/src/services/envPairing.ts +++ b/src/core/envPairing.ts @@ -1,20 +1,15 @@ import fs from 'fs'; import path from 'path'; -import type { Discovery } from './envDiscovery.js'; +import type { Discovery } from '../services/envDiscovery.js'; +import type { FilePair } from '../config/types.js'; /** * Pairs each environment file with its corresponding example file. * @param d - The discovery object containing environment and example file information. * @returns An array of objects containing the environment name, path, and example path. */ -export function pairWithExample( - d: Discovery, -): Array<{ envName: string; envPath: string; examplePath: string }> { - const pairs: Array<{ - envName: string; - envPath: string; - examplePath: string; - }> = []; +export function pairWithExample(d: Discovery): Array { + const pairs: Array = []; const list = d.envFiles.length > 0 ? d.envFiles : [d.primaryEnv]; for (const envName of list) { diff --git a/src/services/duplicates.ts b/src/services/duplicates.ts index 4b60cd8..c52ce08 100644 --- a/src/services/duplicates.ts +++ b/src/services/duplicates.ts @@ -1,4 +1,5 @@ import fs from 'fs'; +import type { Duplicate } from '../config/types.js'; /** * Scan a .env-like file for duplicate keys. @@ -9,9 +10,7 @@ import fs from 'fs'; * @param filePath - Path to the .env file to scan * @returns An array of objects representing duplicate keys and their counts. */ -export function findDuplicateKeys( - filePath: string, -): Array<{ key: string; count: number }> { +export function findDuplicateKeys(filePath: string): Array { if (!fs.existsSync(filePath)) return []; const raw = fs.readFileSync(filePath, 'utf8'); @@ -32,7 +31,7 @@ export function findDuplicateKeys( counts.set(key, (counts.get(key) ?? 0) + 1); } - const duplicates: Array<{ key: string; count: number }> = []; + const duplicates: Array = []; for (const [key, count] of counts) { if (count > 1) duplicates.push({ key, count }); } diff --git a/src/services/fileWalker.ts b/src/services/fileWalker.ts index 1fb0ed2..1ea0c31 100644 --- a/src/services/fileWalker.ts +++ b/src/services/fileWalker.ts @@ -6,6 +6,12 @@ import { DEFAULT_EXCLUDE_PATTERNS, } from '../core/patterns.js'; +interface FindFilesOptions { + include?: string[]; + exclude?: string[]; + files?: string[]; +} + /** * Recursively finds all files in the given directory matching the include patterns, * while excluding files and directories that match the exclude patterns. @@ -15,7 +21,7 @@ import { */ export async function findFiles( rootDir: string, - opts: { include: string[]; exclude: string[]; files?: string[] }, + opts: FindFilesOptions, ): Promise { // If --files provided, keep existing replacement behavior if (opts.files && opts.files.length > 0) { @@ -24,7 +30,7 @@ export async function findFiles( const defaultPatterns = getDefaultPatterns(); const rawInclude = - opts.include.length > 0 + opts.include && opts.include.length > 0 ? [...defaultPatterns, ...opts.include] : defaultPatterns; const includePatterns = rawInclude.flatMap(expandBraceSets); @@ -69,7 +75,7 @@ export async function findFiles( if ( shouldExclude(entry.name, relativeToRoot, [ ...DEFAULT_EXCLUDE_PATTERNS, - ...opts.exclude, + ...(opts.exclude ?? []), ]) ) { continue; diff --git a/src/services/scanOutputToConsole.ts b/src/services/scanOutputToConsole.ts index e95be8a..0565602 100644 --- a/src/services/scanOutputToConsole.ts +++ b/src/services/scanOutputToConsole.ts @@ -24,6 +24,13 @@ import { printHealthScore } from '../ui/scan/printHealthScore.js'; import { printExpireWarnings } from '../ui/scan/printExpireWarnings.js'; import { printInconsistentNamingWarning } from '../ui/scan/printInconsistentNamingWarning.js'; +interface FixContext { + fixApplied: boolean; + removedDuplicates: string[]; + addedEnv: string[]; + gitignoreUpdated: boolean; +} + /** * Outputs the scan results to the console. * @param scanResult - The result of the scan. @@ -35,12 +42,7 @@ export function outputToConsole( scanResult: ScanResult, opts: ScanUsageOptions, comparedAgainst: string, - fixContext?: { - fixApplied: boolean; - removedDuplicates: string[]; - addedEnv: string[]; - gitignoreUpdated: boolean; - }, + fixContext?: FixContext, ): { exitWithError: boolean } { let exitWithError = false;