dotenv-diff 2.9.0 → 2.10.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/baseline/scanBaseline.d.ts +39 -0
  3. package/dist/src/baseline/scanBaseline.d.ts.map +1 -0
  4. package/dist/src/baseline/scanBaseline.js +175 -0
  5. package/dist/src/baseline/scanBaseline.js.map +1 -0
  6. package/dist/src/cli/program.d.ts.map +1 -1
  7. package/dist/src/cli/program.js +2 -1
  8. package/dist/src/cli/program.js.map +1 -1
  9. package/dist/src/cli/run.d.ts.map +1 -1
  10. package/dist/src/cli/run.js +2 -0
  11. package/dist/src/cli/run.js.map +1 -1
  12. package/dist/src/commands/compare.js +1 -1
  13. package/dist/src/commands/compare.js.map +1 -1
  14. package/dist/src/commands/explain.js +1 -1
  15. package/dist/src/commands/explain.js.map +1 -1
  16. package/dist/src/commands/prompts/promptNoEnvScenario.d.ts +2 -2
  17. package/dist/src/commands/prompts/promptNoEnvScenario.d.ts.map +1 -1
  18. package/dist/src/commands/prompts/promptNoEnvScenario.js +11 -7
  19. package/dist/src/commands/prompts/promptNoEnvScenario.js.map +1 -1
  20. package/dist/src/commands/scanUsage.d.ts.map +1 -1
  21. package/dist/src/commands/scanUsage.js +45 -1
  22. package/dist/src/commands/scanUsage.js.map +1 -1
  23. package/dist/src/config/options.d.ts.map +1 -1
  24. package/dist/src/config/options.js +2 -0
  25. package/dist/src/config/options.js.map +1 -1
  26. package/dist/src/config/types.d.ts +31 -0
  27. package/dist/src/config/types.d.ts.map +1 -1
  28. package/dist/src/core/compare/parseAndFilterEnv.js +1 -1
  29. package/dist/src/core/compare/parseAndFilterEnv.js.map +1 -1
  30. package/dist/src/core/helpers/filterIgnoredKeys.d.ts.map +1 -0
  31. package/dist/src/core/helpers/filterIgnoredKeys.js.map +1 -0
  32. package/dist/src/core/scan/compareScan.js +1 -1
  33. package/dist/src/core/scan/compareScan.js.map +1 -1
  34. package/dist/src/core/scan/patterns.d.ts.map +1 -1
  35. package/dist/src/core/scan/patterns.js +6 -4
  36. package/dist/src/core/scan/patterns.js.map +1 -1
  37. package/dist/src/core/scan/skipCommentedUsages.d.ts.map +1 -0
  38. package/dist/src/core/scan/skipCommentedUsages.js.map +1 -0
  39. package/dist/src/services/fixEnv.d.ts.map +1 -0
  40. package/dist/src/{core → services}/fixEnv.js +3 -5
  41. package/dist/src/services/fixEnv.js.map +1 -0
  42. package/dist/src/services/processComparisonFile.js +2 -2
  43. package/dist/src/services/processComparisonFile.js.map +1 -1
  44. package/dist/src/services/scanCodebase.js +1 -1
  45. package/dist/src/services/scanCodebase.js.map +1 -1
  46. package/dist/src/ui/scan/printBaseline.d.ts +14 -0
  47. package/dist/src/ui/scan/printBaseline.d.ts.map +1 -0
  48. package/dist/src/ui/scan/printBaseline.js +32 -0
  49. package/dist/src/ui/scan/printBaseline.js.map +1 -0
  50. package/dist/src/ui/scan/printExplain.js +3 -1
  51. package/dist/src/ui/scan/printExplain.js.map +1 -1
  52. package/dist/test/unit/baseline/scanBaseline.test.d.ts +2 -0
  53. package/dist/test/unit/baseline/scanBaseline.test.d.ts.map +1 -0
  54. package/dist/test/unit/baseline/scanBaseline.test.js +587 -0
  55. package/dist/test/unit/baseline/scanBaseline.test.js.map +1 -0
  56. package/dist/test/unit/cli/run.test.js +14 -0
  57. package/dist/test/unit/cli/run.test.js.map +1 -1
  58. package/dist/test/unit/commands/compare.test.js +4 -4
  59. package/dist/test/unit/commands/compare.test.js.map +1 -1
  60. package/dist/test/unit/commands/explain.test.js +2 -2
  61. package/dist/test/unit/commands/explain.test.js.map +1 -1
  62. package/dist/test/unit/commands/prompts/promptNoEnvScenario.test.js +59 -0
  63. package/dist/test/unit/commands/prompts/promptNoEnvScenario.test.js.map +1 -1
  64. package/dist/test/unit/commands/scanUsage.test.js +100 -0
  65. package/dist/test/unit/commands/scanUsage.test.js.map +1 -1
  66. package/dist/test/unit/core/helpers/filterIgnoredKeys.test.d.ts.map +1 -0
  67. package/dist/test/unit/core/{filterIgnoredKeys.test.js → helpers/filterIgnoredKeys.test.js} +1 -1
  68. package/dist/test/unit/core/helpers/filterIgnoredKeys.test.js.map +1 -0
  69. package/dist/test/unit/core/helpers/findConfigFile.test.d.ts +2 -0
  70. package/dist/test/unit/core/helpers/findConfigFile.test.d.ts.map +1 -0
  71. package/dist/test/unit/core/helpers/findConfigFile.test.js +63 -0
  72. package/dist/test/unit/core/helpers/findConfigFile.test.js.map +1 -0
  73. package/dist/test/unit/core/helpers/isLikelyMinified.test.d.ts +2 -0
  74. package/dist/test/unit/core/helpers/isLikelyMinified.test.d.ts.map +1 -0
  75. package/dist/test/unit/core/helpers/isLikelyMinified.test.js +35 -0
  76. package/dist/test/unit/core/helpers/isLikelyMinified.test.js.map +1 -0
  77. package/dist/test/unit/core/helpers/normalizePath.test.d.ts +2 -0
  78. package/dist/test/unit/core/helpers/normalizePath.test.d.ts.map +1 -0
  79. package/dist/test/unit/core/helpers/normalizePath.test.js +26 -0
  80. package/dist/test/unit/core/helpers/normalizePath.test.js.map +1 -0
  81. package/dist/test/unit/core/scan/patterns.test.js +24 -0
  82. package/dist/test/unit/core/scan/patterns.test.js.map +1 -1
  83. package/dist/test/unit/core/scan/skipCommentedUsages.test.d.ts +2 -0
  84. package/dist/test/unit/core/scan/skipCommentedUsages.test.d.ts.map +1 -0
  85. package/dist/test/unit/core/scan/skipCommentedUsages.test.js +131 -0
  86. package/dist/test/unit/core/scan/skipCommentedUsages.test.js.map +1 -0
  87. package/dist/test/unit/services/fixEnv.test.d.ts.map +1 -0
  88. package/dist/test/unit/{core → services}/fixEnv.test.js +11 -1
  89. package/dist/test/unit/services/fixEnv.test.js.map +1 -0
  90. package/dist/test/unit/services/parseEnvFile.test.d.ts +2 -0
  91. package/dist/test/unit/services/parseEnvFile.test.d.ts.map +1 -0
  92. package/dist/test/unit/services/parseEnvFile.test.js +47 -0
  93. package/dist/test/unit/services/parseEnvFile.test.js.map +1 -0
  94. package/dist/test/unit/services/processComparisonFile.test.js +2 -2
  95. package/dist/test/unit/services/processComparisonFile.test.js.map +1 -1
  96. package/dist/test/unit/ui/scan/printBaseline.test.d.ts +2 -0
  97. package/dist/test/unit/ui/scan/printBaseline.test.d.ts.map +1 -0
  98. package/dist/test/unit/ui/scan/printBaseline.test.js +23 -0
  99. package/dist/test/unit/ui/scan/printBaseline.test.js.map +1 -0
  100. package/dist/test/unit/ui/scan/printExplain.test.js +2 -1
  101. package/dist/test/unit/ui/scan/printExplain.test.js.map +1 -1
  102. package/package.json +1 -1
  103. package/dist/src/core/filterIgnoredKeys.d.ts.map +0 -1
  104. package/dist/src/core/filterIgnoredKeys.js.map +0 -1
  105. package/dist/src/core/fixEnv.d.ts.map +0 -1
  106. package/dist/src/core/fixEnv.js.map +0 -1
  107. package/dist/src/core/helpers/skipCommentedUsages.d.ts.map +0 -1
  108. package/dist/src/core/helpers/skipCommentedUsages.js.map +0 -1
  109. package/dist/test/unit/core/filterIgnoredKeys.test.d.ts.map +0 -1
  110. package/dist/test/unit/core/filterIgnoredKeys.test.js.map +0 -1
  111. package/dist/test/unit/core/fixEnv.test.d.ts.map +0 -1
  112. package/dist/test/unit/core/fixEnv.test.js.map +0 -1
  113. /package/dist/src/core/{filterIgnoredKeys.d.ts → helpers/filterIgnoredKeys.d.ts} +0 -0
  114. /package/dist/src/core/{filterIgnoredKeys.js → helpers/filterIgnoredKeys.js} +0 -0
  115. /package/dist/src/core/{helpers → scan}/skipCommentedUsages.d.ts +0 -0
  116. /package/dist/src/core/{helpers → scan}/skipCommentedUsages.js +0 -0
  117. /package/dist/src/{core → services}/fixEnv.d.ts +0 -0
  118. /package/dist/test/unit/core/{filterIgnoredKeys.test.d.ts → helpers/filterIgnoredKeys.test.d.ts} +0 -0
  119. /package/dist/test/unit/{core → services}/fixEnv.test.d.ts +0 -0
@@ -0,0 +1,587 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import crypto from 'crypto';
6
+ import { BASELINE_FILE, loadBaselineFile, writeBaselineFile, collectBaselineEntries, applyBaselineEntries, } from '../../../src/baseline/scanBaseline.js';
7
+ // ---------------------------------------------------------------------------
8
+ // Helpers
9
+ // ---------------------------------------------------------------------------
10
+ function fp(input) {
11
+ return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12);
12
+ }
13
+ function makeSecret(file, snippet) {
14
+ return {
15
+ file,
16
+ snippet,
17
+ line: 1,
18
+ kind: 'pattern',
19
+ message: 'secret',
20
+ severity: 'high',
21
+ };
22
+ }
23
+ const emptyScanResult = {
24
+ used: [],
25
+ missing: [],
26
+ unused: [],
27
+ secrets: [],
28
+ duplicates: {},
29
+ logged: [],
30
+ stats: {
31
+ filesScanned: 0,
32
+ totalUsages: 0,
33
+ uniqueVariables: 0,
34
+ warningsCount: 0,
35
+ duration: 0,
36
+ },
37
+ };
38
+ // ---------------------------------------------------------------------------
39
+ // Setup
40
+ // ---------------------------------------------------------------------------
41
+ let tmpDir;
42
+ beforeEach(() => {
43
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'scanBaseline-test-'));
44
+ });
45
+ afterEach(() => {
46
+ fs.rmSync(tmpDir, { recursive: true, force: true });
47
+ });
48
+ // ---------------------------------------------------------------------------
49
+ // loadBaselineFile
50
+ // ---------------------------------------------------------------------------
51
+ describe('loadBaselineFile', () => {
52
+ it('returns null when baseline file does not exist', () => {
53
+ expect(loadBaselineFile(tmpDir)).toBeNull();
54
+ });
55
+ it('loads and returns a valid baseline file', async () => {
56
+ await writeBaselineFile(tmpDir, [{ rule: 'missing', key: 'FOO' }]);
57
+ const result = loadBaselineFile(tmpDir);
58
+ expect(result).not.toBeNull();
59
+ expect(result.version).toBe(1);
60
+ expect(result.entries).toEqual([{ rule: 'missing', key: 'FOO' }]);
61
+ expect(typeof result.createdAt).toBe('string');
62
+ });
63
+ it('returns null when file contains invalid JSON', () => {
64
+ fs.writeFileSync(path.join(tmpDir, BASELINE_FILE), 'not json');
65
+ expect(loadBaselineFile(tmpDir)).toBeNull();
66
+ });
67
+ it('returns null when JSON is valid but missing entries array', () => {
68
+ fs.writeFileSync(path.join(tmpDir, BASELINE_FILE), JSON.stringify({ version: 1, createdAt: '2024-01-01' }));
69
+ expect(loadBaselineFile(tmpDir)).toBeNull();
70
+ });
71
+ it('returns null when root value is not an object', () => {
72
+ fs.writeFileSync(path.join(tmpDir, BASELINE_FILE), '"just a string"');
73
+ expect(loadBaselineFile(tmpDir)).toBeNull();
74
+ });
75
+ });
76
+ // ---------------------------------------------------------------------------
77
+ // writeBaselineFile
78
+ // ---------------------------------------------------------------------------
79
+ describe('writeBaselineFile', () => {
80
+ it('writes baseline file and returns its absolute path', async () => {
81
+ const entries = [{ rule: 'unused', key: 'BAR' }];
82
+ const written = await writeBaselineFile(tmpDir, entries);
83
+ expect(written).toBe(path.join(tmpDir, BASELINE_FILE));
84
+ expect(fs.existsSync(written)).toBe(true);
85
+ });
86
+ it('writes valid JSON with version, createdAt, and entries', async () => {
87
+ const entries = [{ rule: 'missing', key: 'API_KEY' }];
88
+ await writeBaselineFile(tmpDir, entries);
89
+ const raw = fs.readFileSync(path.join(tmpDir, BASELINE_FILE), 'utf8');
90
+ const parsed = JSON.parse(raw);
91
+ expect(parsed.version).toBe(1);
92
+ expect(parsed.entries).toEqual(entries);
93
+ expect(typeof parsed.createdAt).toBe('string');
94
+ });
95
+ it('file ends with a newline', async () => {
96
+ await writeBaselineFile(tmpDir, []);
97
+ const raw = fs.readFileSync(path.join(tmpDir, BASELINE_FILE), 'utf8');
98
+ expect(raw.endsWith('\n')).toBe(true);
99
+ });
100
+ it('overwrites an existing baseline file', async () => {
101
+ await writeBaselineFile(tmpDir, [{ rule: 'missing', key: 'OLD' }]);
102
+ await writeBaselineFile(tmpDir, [{ rule: 'unused', key: 'NEW' }]);
103
+ const loaded = loadBaselineFile(tmpDir);
104
+ expect(loaded.entries).toEqual([{ rule: 'unused', key: 'NEW' }]);
105
+ });
106
+ });
107
+ // ---------------------------------------------------------------------------
108
+ // collectBaselineEntries
109
+ // ---------------------------------------------------------------------------
110
+ describe('collectBaselineEntries', () => {
111
+ it('returns empty array for a clean scan result', () => {
112
+ expect(collectBaselineEntries(emptyScanResult)).toEqual([]);
113
+ });
114
+ it('collects missing keys', () => {
115
+ const result = collectBaselineEntries({
116
+ ...emptyScanResult,
117
+ missing: ['A', 'B'],
118
+ });
119
+ expect(result).toContainEqual({ rule: 'missing', key: 'A' });
120
+ expect(result).toContainEqual({ rule: 'missing', key: 'B' });
121
+ });
122
+ it('collects unused keys', () => {
123
+ const result = collectBaselineEntries({
124
+ ...emptyScanResult,
125
+ unused: ['X'],
126
+ });
127
+ expect(result).toContainEqual({ rule: 'unused', key: 'X' });
128
+ });
129
+ it('collects logged warnings by variable + file', () => {
130
+ const result = collectBaselineEntries({
131
+ ...emptyScanResult,
132
+ logged: [
133
+ {
134
+ variable: 'API_KEY',
135
+ file: 'src/index.ts',
136
+ line: 10,
137
+ column: 0,
138
+ pattern: 'process.env',
139
+ context: 'console.log(process.env.API_KEY)',
140
+ isLogged: true,
141
+ },
142
+ ],
143
+ });
144
+ expect(result).toContainEqual({
145
+ rule: 'logged',
146
+ key: 'API_KEY',
147
+ file: 'src/index.ts',
148
+ });
149
+ });
150
+ it('collects secrets as fingerprints (no raw value)', () => {
151
+ const secret = makeSecret('src/app.ts', 'TOKEN=abc123');
152
+ const result = collectBaselineEntries({
153
+ ...emptyScanResult,
154
+ secrets: [secret],
155
+ });
156
+ const expected = fp('src/app.ts:TOKEN=abc123');
157
+ expect(result).toContainEqual({
158
+ rule: 'secret',
159
+ key: expected,
160
+ file: 'src/app.ts',
161
+ });
162
+ // raw snippet must not appear in any key
163
+ result.forEach((e) => expect(e.key).not.toContain('TOKEN=abc123'));
164
+ });
165
+ it('collects example-secret warnings', () => {
166
+ const result = collectBaselineEntries({
167
+ ...emptyScanResult,
168
+ exampleWarnings: [
169
+ {
170
+ key: 'DB_PASS',
171
+ value: 'secret',
172
+ reason: 'pattern',
173
+ severity: 'high',
174
+ },
175
+ ],
176
+ });
177
+ expect(result).toContainEqual({ rule: 'example-secret', key: 'DB_PASS' });
178
+ });
179
+ it('collects env duplicate keys', () => {
180
+ const result = collectBaselineEntries({
181
+ ...emptyScanResult,
182
+ duplicates: { env: [{ key: 'DUP', count: 2 }] },
183
+ });
184
+ expect(result).toContainEqual({ rule: 'duplicate-env', key: 'DUP' });
185
+ });
186
+ it('collects example duplicate keys', () => {
187
+ const result = collectBaselineEntries({
188
+ ...emptyScanResult,
189
+ duplicates: { example: [{ key: 'EX_DUP', count: 2 }] },
190
+ });
191
+ expect(result).toContainEqual({ rule: 'duplicate-example', key: 'EX_DUP' });
192
+ });
193
+ it('collects framework warnings with file', () => {
194
+ const result = collectBaselineEntries({
195
+ ...emptyScanResult,
196
+ frameworkWarnings: [
197
+ {
198
+ variable: 'NEXT_VAR',
199
+ file: 'pages/index.ts',
200
+ line: 5,
201
+ reason: 'bad',
202
+ framework: 'nextjs',
203
+ },
204
+ ],
205
+ });
206
+ expect(result).toContainEqual({
207
+ rule: 'framework',
208
+ key: 'NEXT_VAR',
209
+ file: 'pages/index.ts',
210
+ });
211
+ });
212
+ it('collects uppercase warnings', () => {
213
+ const result = collectBaselineEntries({
214
+ ...emptyScanResult,
215
+ uppercaseWarnings: [{ key: 'myKey', suggestion: 'MYKEY' }],
216
+ });
217
+ expect(result).toContainEqual({ rule: 'uppercase', key: 'myKey' });
218
+ });
219
+ it('collects expire warnings', () => {
220
+ const result = collectBaselineEntries({
221
+ ...emptyScanResult,
222
+ expireWarnings: [{ key: 'OLD_KEY', date: '2024-01-01', daysLeft: -5 }],
223
+ });
224
+ expect(result).toContainEqual({ rule: 'expire', key: 'OLD_KEY' });
225
+ });
226
+ it('collects inconsistent-naming warnings as sorted key pair', () => {
227
+ const result = collectBaselineEntries({
228
+ ...emptyScanResult,
229
+ inconsistentNamingWarnings: [
230
+ { key1: 'SECRETKEY', key2: 'SECRET_KEY', suggestion: '' },
231
+ ],
232
+ });
233
+ // sorted: SECRETKEY|SECRET_KEY ('K' < '_' in ASCII so SECRETKEY < SECRET_KEY)
234
+ expect(result).toContainEqual({
235
+ rule: 'inconsistent-naming',
236
+ key: 'SECRETKEY|SECRET_KEY',
237
+ });
238
+ });
239
+ it('key pair is identical regardless of key1/key2 order', () => {
240
+ const a = collectBaselineEntries({
241
+ ...emptyScanResult,
242
+ inconsistentNamingWarnings: [
243
+ { key1: 'B_KEY', key2: 'BKEY', suggestion: '' },
244
+ ],
245
+ });
246
+ const b = collectBaselineEntries({
247
+ ...emptyScanResult,
248
+ inconsistentNamingWarnings: [
249
+ { key1: 'BKEY', key2: 'B_KEY', suggestion: '' },
250
+ ],
251
+ });
252
+ expect(a).toEqual(b);
253
+ });
254
+ it('returns entries sorted by rule, then file, then key', () => {
255
+ const result = collectBaselineEntries({
256
+ ...emptyScanResult,
257
+ missing: ['Z', 'A'],
258
+ unused: ['M'],
259
+ });
260
+ const rules = result.map((e) => e.rule);
261
+ // missing < unused alphabetically
262
+ expect(rules.indexOf('missing')).toBeLessThan(rules.indexOf('unused'));
263
+ // A before Z within missing
264
+ const missingKeys = result
265
+ .filter((e) => e.rule === 'missing')
266
+ .map((e) => e.key);
267
+ expect(missingKeys).toEqual(['A', 'Z']);
268
+ });
269
+ it('sorts entries with same rule by file before key', () => {
270
+ // Two framework warnings with same rule but different files
271
+ const result = collectBaselineEntries({
272
+ ...emptyScanResult,
273
+ frameworkWarnings: [
274
+ {
275
+ variable: 'VAR',
276
+ file: 'z-page.ts',
277
+ line: 1,
278
+ reason: 'r',
279
+ framework: 'nextjs',
280
+ },
281
+ {
282
+ variable: 'VAR',
283
+ file: 'a-page.ts',
284
+ line: 2,
285
+ reason: 'r',
286
+ framework: 'nextjs',
287
+ },
288
+ ],
289
+ });
290
+ const files = result.map((e) => e.file);
291
+ expect(files).toEqual(['a-page.ts', 'z-page.ts']);
292
+ });
293
+ it('two secrets with the same content produce the same fingerprint', () => {
294
+ const s1 = makeSecret('file.ts', 'SNIPPET=x');
295
+ const s2 = makeSecret('file.ts', 'SNIPPET=x');
296
+ const r1 = collectBaselineEntries({ ...emptyScanResult, secrets: [s1] });
297
+ const r2 = collectBaselineEntries({ ...emptyScanResult, secrets: [s2] });
298
+ expect(r1[0].key).toBe(r2[0].key);
299
+ });
300
+ });
301
+ // ---------------------------------------------------------------------------
302
+ // applyBaselineEntries
303
+ // ---------------------------------------------------------------------------
304
+ describe('applyBaselineEntries', () => {
305
+ it('returns scan result unchanged when entries list is empty', () => {
306
+ const result = {
307
+ ...emptyScanResult,
308
+ missing: ['A'],
309
+ unused: ['B'],
310
+ };
311
+ const after = applyBaselineEntries(result, []);
312
+ expect(after.missing).toEqual(['A']);
313
+ expect(after.unused).toEqual(['B']);
314
+ });
315
+ it('suppresses matching missing key', () => {
316
+ const result = { ...emptyScanResult, missing: ['FOO', 'BAR'] };
317
+ const entries = [{ rule: 'missing', key: 'FOO' }];
318
+ const after = applyBaselineEntries(result, entries);
319
+ expect(after.missing).toEqual(['BAR']);
320
+ });
321
+ it('suppresses matching unused key', () => {
322
+ const result = { ...emptyScanResult, unused: ['OLD', 'KEEP'] };
323
+ const entries = [{ rule: 'unused', key: 'OLD' }];
324
+ const after = applyBaselineEntries(result, entries);
325
+ expect(after.unused).toEqual(['KEEP']);
326
+ });
327
+ it('suppresses logged warning by variable + file', () => {
328
+ const result = {
329
+ ...emptyScanResult,
330
+ logged: [
331
+ {
332
+ variable: 'API_KEY',
333
+ file: 'src/index.ts',
334
+ line: 11,
335
+ column: 0,
336
+ pattern: 'process.env',
337
+ context: 'console.log(process.env.API_KEY)',
338
+ isLogged: true,
339
+ },
340
+ ],
341
+ };
342
+ const entries = [
343
+ { rule: 'logged', key: 'API_KEY', file: 'src/index.ts' },
344
+ ];
345
+ const after = applyBaselineEntries(result, entries);
346
+ expect(after.logged).toHaveLength(0);
347
+ });
348
+ it('keeps logged warning when file does not match', () => {
349
+ const result = {
350
+ ...emptyScanResult,
351
+ logged: [
352
+ {
353
+ variable: 'API_KEY',
354
+ file: 'src/index.ts',
355
+ line: 11,
356
+ column: 0,
357
+ pattern: 'process.env',
358
+ context: 'console.log(process.env.API_KEY)',
359
+ isLogged: true,
360
+ },
361
+ ],
362
+ };
363
+ const entries = [
364
+ { rule: 'logged', key: 'API_KEY', file: 'src/other.ts' },
365
+ ];
366
+ const after = applyBaselineEntries(result, entries);
367
+ expect(after.logged).toHaveLength(1);
368
+ });
369
+ it('suppresses secret by fingerprint', () => {
370
+ const secret = makeSecret('src/index.ts', 'TOKEN=secret');
371
+ const result = { ...emptyScanResult, secrets: [secret] };
372
+ const entries = collectBaselineEntries(result); // derive matching entries
373
+ const after = applyBaselineEntries(result, entries);
374
+ expect(after.secrets).toHaveLength(0);
375
+ });
376
+ it('keeps secret that does not match baseline fingerprint', () => {
377
+ const secret = makeSecret('src/index.ts', 'TOKEN=secret');
378
+ const otherEntries = [
379
+ { rule: 'secret', key: fp('other.ts:OTHER=val'), file: 'other.ts' },
380
+ ];
381
+ const result = { ...emptyScanResult, secrets: [secret] };
382
+ const after = applyBaselineEntries(result, otherEntries);
383
+ expect(after.secrets).toHaveLength(1);
384
+ });
385
+ it('suppresses duplicate-env key', () => {
386
+ const result = {
387
+ ...emptyScanResult,
388
+ duplicates: { env: [{ key: 'DUP', count: 2 }] },
389
+ };
390
+ const entries = [{ rule: 'duplicate-env', key: 'DUP' }];
391
+ const after = applyBaselineEntries(result, entries);
392
+ expect(after.duplicates.env).toHaveLength(0);
393
+ });
394
+ it('suppresses duplicate-example key', () => {
395
+ const result = {
396
+ ...emptyScanResult,
397
+ duplicates: { example: [{ key: 'EX', count: 2 }] },
398
+ };
399
+ const entries = [{ rule: 'duplicate-example', key: 'EX' }];
400
+ const after = applyBaselineEntries(result, entries);
401
+ expect(after.duplicates.example).toHaveLength(0);
402
+ });
403
+ it('leaves duplicates undefined when scanResult has no duplicates', () => {
404
+ const result = { ...emptyScanResult, duplicates: {} };
405
+ const after = applyBaselineEntries(result, []);
406
+ expect(after.duplicates.env).toBeUndefined();
407
+ expect(after.duplicates.example).toBeUndefined();
408
+ });
409
+ it('suppresses example-secret warning', () => {
410
+ const result = {
411
+ ...emptyScanResult,
412
+ exampleWarnings: [
413
+ { key: 'DB_PASS', value: 'x', reason: 'pattern', severity: 'high' },
414
+ ],
415
+ };
416
+ const entries = [
417
+ { rule: 'example-secret', key: 'DB_PASS' },
418
+ ];
419
+ const after = applyBaselineEntries(result, entries);
420
+ expect(after.exampleWarnings).toHaveLength(0);
421
+ });
422
+ it('does not touch exampleWarnings when field is absent', () => {
423
+ const result = { ...emptyScanResult };
424
+ const after = applyBaselineEntries(result, [
425
+ { rule: 'example-secret', key: 'X' },
426
+ ]);
427
+ expect(after.exampleWarnings).toBeUndefined();
428
+ });
429
+ it('suppresses framework warning by variable + file', () => {
430
+ const result = {
431
+ ...emptyScanResult,
432
+ frameworkWarnings: [
433
+ {
434
+ variable: 'NEXT_VAR',
435
+ file: 'pages/i.ts',
436
+ line: 1,
437
+ reason: 'bad',
438
+ framework: 'nextjs',
439
+ },
440
+ ],
441
+ };
442
+ const entries = [
443
+ { rule: 'framework', key: 'NEXT_VAR', file: 'pages/i.ts' },
444
+ ];
445
+ const after = applyBaselineEntries(result, entries);
446
+ expect(after.frameworkWarnings).toHaveLength(0);
447
+ });
448
+ it('keeps framework warning when file does not match', () => {
449
+ const result = {
450
+ ...emptyScanResult,
451
+ frameworkWarnings: [
452
+ {
453
+ variable: 'NEXT_VAR',
454
+ file: 'pages/other.ts',
455
+ line: 1,
456
+ reason: 'bad',
457
+ framework: 'nextjs',
458
+ },
459
+ ],
460
+ };
461
+ const entries = [
462
+ { rule: 'framework', key: 'NEXT_VAR', file: 'pages/i.ts' },
463
+ ];
464
+ const after = applyBaselineEntries(result, entries);
465
+ expect(after.frameworkWarnings).toHaveLength(1);
466
+ });
467
+ it('does not touch frameworkWarnings when field is absent', () => {
468
+ const result = { ...emptyScanResult };
469
+ const after = applyBaselineEntries(result, [
470
+ { rule: 'framework', key: 'X', file: 'f.ts' },
471
+ ]);
472
+ expect(after.frameworkWarnings).toBeUndefined();
473
+ });
474
+ it('suppresses uppercase warning', () => {
475
+ const result = {
476
+ ...emptyScanResult,
477
+ uppercaseWarnings: [{ key: 'myKey', suggestion: 'MYKEY' }],
478
+ };
479
+ const entries = [{ rule: 'uppercase', key: 'myKey' }];
480
+ const after = applyBaselineEntries(result, entries);
481
+ expect(after.uppercaseWarnings).toHaveLength(0);
482
+ });
483
+ it('does not touch uppercaseWarnings when field is absent', () => {
484
+ const result = { ...emptyScanResult };
485
+ const after = applyBaselineEntries(result, [
486
+ { rule: 'uppercase', key: 'x' },
487
+ ]);
488
+ expect(after.uppercaseWarnings).toBeUndefined();
489
+ });
490
+ it('suppresses expire warning', () => {
491
+ const result = {
492
+ ...emptyScanResult,
493
+ expireWarnings: [{ key: 'OLD_KEY', date: '2020-01-01', daysLeft: -100 }],
494
+ };
495
+ const entries = [{ rule: 'expire', key: 'OLD_KEY' }];
496
+ const after = applyBaselineEntries(result, entries);
497
+ expect(after.expireWarnings).toHaveLength(0);
498
+ });
499
+ it('does not touch expireWarnings when field is absent', () => {
500
+ const result = { ...emptyScanResult };
501
+ const after = applyBaselineEntries(result, [{ rule: 'expire', key: 'x' }]);
502
+ expect(after.expireWarnings).toBeUndefined();
503
+ });
504
+ it('suppresses inconsistent-naming warning (sorted pair)', () => {
505
+ const result = {
506
+ ...emptyScanResult,
507
+ inconsistentNamingWarnings: [
508
+ { key1: 'SECRETKEY', key2: 'SECRET_KEY', suggestion: '' },
509
+ ],
510
+ };
511
+ const entries = [
512
+ { rule: 'inconsistent-naming', key: 'SECRETKEY|SECRET_KEY' },
513
+ ];
514
+ const after = applyBaselineEntries(result, entries);
515
+ expect(after.inconsistentNamingWarnings).toHaveLength(0);
516
+ });
517
+ it('does not touch inconsistentNamingWarnings when field is absent', () => {
518
+ const result = { ...emptyScanResult };
519
+ const after = applyBaselineEntries(result, [
520
+ { rule: 'inconsistent-naming', key: 'A|B' },
521
+ ]);
522
+ expect(after.inconsistentNamingWarnings).toBeUndefined();
523
+ });
524
+ it('only suppresses matched entries, keeps unmatched ones', () => {
525
+ const result = {
526
+ ...emptyScanResult,
527
+ missing: ['KEEP', 'SUPPRESS'],
528
+ };
529
+ const entries = [{ rule: 'missing', key: 'SUPPRESS' }];
530
+ const after = applyBaselineEntries(result, entries);
531
+ expect(after.missing).toEqual(['KEEP']);
532
+ });
533
+ it('round-trips: collect then apply removes all warnings', () => {
534
+ const result = {
535
+ ...emptyScanResult,
536
+ missing: ['A'],
537
+ unused: ['B'],
538
+ logged: [
539
+ {
540
+ variable: 'LOG_KEY',
541
+ file: 'f.ts',
542
+ line: 1,
543
+ column: 0,
544
+ pattern: 'process.env',
545
+ context: 'console.log(process.env.LOG_KEY)',
546
+ isLogged: true,
547
+ },
548
+ ],
549
+ secrets: [makeSecret('f.ts', 'S=x')],
550
+ exampleWarnings: [
551
+ { key: 'K', value: 'v', reason: 'r', severity: 'medium' },
552
+ ],
553
+ duplicates: {
554
+ env: [{ key: 'D', count: 2 }],
555
+ example: [{ key: 'E', count: 2 }],
556
+ },
557
+ frameworkWarnings: [
558
+ {
559
+ variable: 'V',
560
+ file: 'f.ts',
561
+ line: 1,
562
+ reason: 'r',
563
+ framework: 'nextjs',
564
+ },
565
+ ],
566
+ uppercaseWarnings: [{ key: 'u', suggestion: 'U' }],
567
+ expireWarnings: [{ key: 'OLD', date: '2020-01-01', daysLeft: -1 }],
568
+ inconsistentNamingWarnings: [
569
+ { key1: 'X_KEY', key2: 'XKEY', suggestion: '' },
570
+ ],
571
+ };
572
+ const entries = collectBaselineEntries(result);
573
+ const after = applyBaselineEntries(result, entries);
574
+ expect(after.missing).toHaveLength(0);
575
+ expect(after.unused).toHaveLength(0);
576
+ expect(after.logged).toHaveLength(0);
577
+ expect(after.secrets).toHaveLength(0);
578
+ expect(after.exampleWarnings).toHaveLength(0);
579
+ expect(after.duplicates.env).toHaveLength(0);
580
+ expect(after.duplicates.example).toHaveLength(0);
581
+ expect(after.frameworkWarnings).toHaveLength(0);
582
+ expect(after.uppercaseWarnings).toHaveLength(0);
583
+ expect(after.expireWarnings).toHaveLength(0);
584
+ expect(after.inconsistentNamingWarnings).toHaveLength(0);
585
+ });
586
+ });
587
+ //# sourceMappingURL=scanBaseline.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanBaseline.test.js","sourceRoot":"","sources":["../../../../test/unit/baseline/scanBaseline.test.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,7 @@ import { setupGlobalConfig } from '../../../src/ui/shared/setupGlobalConfig.js';
44
44
  import { loadConfig } from '../../../src/config/loadConfig.js';
45
45
  import { runInit } from '../../../src/commands/init.js';
46
46
  import { explainKey } from '../../../src/commands/explain.js';
47
+ import { DEFAULT_ENV_FILE } from '../../../src/config/constants.js';
47
48
  function createBaseOptions(overrides = {}) {
48
49
  return {
49
50
  checkValues: false,
@@ -74,6 +75,7 @@ function createBaseOptions(overrides = {}) {
74
75
  inconsistentNamingWarnings: true,
75
76
  listAll: false,
76
77
  explain: undefined,
78
+ baseline: false,
77
79
  ...overrides,
78
80
  };
79
81
  }
@@ -292,6 +294,18 @@ describe('run', () => {
292
294
  expect(mockScanUsage).toHaveBeenCalledWith(expect.objectContaining({ envPath: undefined }));
293
295
  existsSpy.mockRestore();
294
296
  });
297
+ it('uses DEFAULT_ENV_FILE envPath when no env flag and default env file exists', async () => {
298
+ const program = {
299
+ parse: vi.fn(),
300
+ opts: vi.fn(() => ({ compare: false })),
301
+ };
302
+ mockNormalizeOptions.mockReturnValue(createBaseOptions({ compare: false }));
303
+ const existsSpy = vi.spyOn(fs, 'existsSync').mockReturnValue(true);
304
+ mockScanUsage.mockResolvedValue({ exitWithError: false });
305
+ await run(program);
306
+ expect(mockScanUsage).toHaveBeenCalledWith(expect.objectContaining({ envPath: DEFAULT_ENV_FILE }));
307
+ existsSpy.mockRestore();
308
+ });
295
309
  it('prints JSON report output and uses collect callback in compare mode', async () => {
296
310
  const program = {
297
311
  parse: vi.fn(),