safelaunch 1.0.18 → 1.0.19
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/package.json +1 -1
- package/safelaunch/src/scan.js +20 -68
package/package.json
CHANGED
package/safelaunch/src/scan.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { track, shutdown } = require('./telemetry');
|
|
3
4
|
|
|
4
|
-
// ─── Impact messages
|
|
5
|
+
// ─── Impact messages ──────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
function impactBlock(lines) {
|
|
8
|
+
return ' Impact:\n' + lines.map(l => ' ' + l).join('\n');
|
|
9
|
+
}
|
|
5
10
|
|
|
6
11
|
const IMPACT = {
|
|
7
12
|
missing: (key) => impactBlock([
|
|
@@ -38,12 +43,6 @@ const IMPACT = {
|
|
|
38
43
|
]),
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
function impactBlock(lines) {
|
|
42
|
-
return ' Impact:\n' + lines.map(l => ' ' + l).join('\n');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ─── Divider ──────────────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
46
|
const DIVIDER = '────────────────────────────';
|
|
48
47
|
|
|
49
48
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -119,39 +118,26 @@ function checkDependencies(cwd) {
|
|
|
119
118
|
return { notInstalled: false, missing };
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
function renderIssue(number, title, impactLines) {
|
|
121
|
+
function renderIssue(number, title, impact) {
|
|
125
122
|
return (
|
|
126
123
|
number + '. ' + title + '\n' +
|
|
127
124
|
'\n' +
|
|
128
|
-
|
|
125
|
+
impact + '\n'
|
|
129
126
|
);
|
|
130
127
|
}
|
|
131
128
|
|
|
132
129
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
133
130
|
|
|
134
131
|
async function scan() {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
let shutdown = async () => {};
|
|
138
|
-
try {
|
|
139
|
-
const telemetry = require('./safelaunch/src/telemetry');
|
|
140
|
-
track = telemetry.track;
|
|
141
|
-
shutdown = telemetry.shutdown;
|
|
142
|
-
} catch (_) {}
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log('Scanning your project...');
|
|
143
134
|
|
|
144
135
|
const cwd = process.cwd();
|
|
145
136
|
const projectType = detectProjectType(cwd);
|
|
146
137
|
const typeLabels = { vite: 'Vite', next: 'Next.js', cra: 'Create React App', node: 'Node.js' };
|
|
147
|
-
|
|
148
|
-
console.log('');
|
|
149
|
-
console.log('Scanning your project...');
|
|
150
138
|
console.log('Detected: ' + typeLabels[projectType]);
|
|
151
139
|
console.log('');
|
|
152
140
|
|
|
153
|
-
// ── Collect env vars used in codebase ──
|
|
154
|
-
|
|
155
141
|
const extensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte'];
|
|
156
142
|
let pattern;
|
|
157
143
|
if (projectType === 'vite') {
|
|
@@ -164,8 +150,6 @@ async function scan() {
|
|
|
164
150
|
|
|
165
151
|
const found = scanFiles(cwd, extensions, pattern);
|
|
166
152
|
|
|
167
|
-
// ── No env vars in codebase at all ──
|
|
168
|
-
|
|
169
153
|
if (found.size === 0) {
|
|
170
154
|
console.log('🛡️ Safelaunch Scan Report');
|
|
171
155
|
console.log('');
|
|
@@ -182,8 +166,6 @@ async function scan() {
|
|
|
182
166
|
return;
|
|
183
167
|
}
|
|
184
168
|
|
|
185
|
-
// ── No .env file found ──
|
|
186
|
-
|
|
187
169
|
const result = readEnvDetailed(cwd);
|
|
188
170
|
|
|
189
171
|
if (!result) {
|
|
@@ -191,12 +173,7 @@ async function scan() {
|
|
|
191
173
|
const criticals = [];
|
|
192
174
|
let issueNum = 1;
|
|
193
175
|
|
|
194
|
-
criticals.push(renderIssue(
|
|
195
|
-
issueNum++,
|
|
196
|
-
'.env file is missing',
|
|
197
|
-
IMPACT.noEnvFile()
|
|
198
|
-
));
|
|
199
|
-
|
|
176
|
+
criticals.push(renderIssue(issueNum++, '.env file is missing', IMPACT.noEnvFile()));
|
|
200
177
|
for (const key of varList) {
|
|
201
178
|
criticals.push(renderIssue(issueNum++, key + ' is missing', IMPACT.missing(key)));
|
|
202
179
|
}
|
|
@@ -233,8 +210,6 @@ async function scan() {
|
|
|
233
210
|
return;
|
|
234
211
|
}
|
|
235
212
|
|
|
236
|
-
// ── Full scan ──
|
|
237
|
-
|
|
238
213
|
const { envVars, duplicates } = result;
|
|
239
214
|
const missing = [];
|
|
240
215
|
const empty = [];
|
|
@@ -252,7 +227,6 @@ async function scan() {
|
|
|
252
227
|
|
|
253
228
|
const drift = checkDependencies(cwd);
|
|
254
229
|
|
|
255
|
-
// Prefix issues (warnings only)
|
|
256
230
|
const prefixWarnings = [];
|
|
257
231
|
for (const key of found) {
|
|
258
232
|
if (key === 'NODE_ENV') continue;
|
|
@@ -264,40 +238,27 @@ async function scan() {
|
|
|
264
238
|
}
|
|
265
239
|
}
|
|
266
240
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
const warningIssues = []; // { title, impact }
|
|
271
|
-
const passingChecks = []; // string[]
|
|
241
|
+
const criticalIssues = [];
|
|
242
|
+
const warningIssues = [];
|
|
243
|
+
const passingChecks = [];
|
|
272
244
|
|
|
273
|
-
// Criticals: missing vars
|
|
274
245
|
for (const key of missing) {
|
|
275
246
|
criticalIssues.push({ title: key + ' is missing', impact: IMPACT.missing(key) });
|
|
276
247
|
}
|
|
277
|
-
|
|
278
|
-
// Criticals: empty vars
|
|
279
248
|
for (const key of empty) {
|
|
280
249
|
criticalIssues.push({ title: key + ' is empty', impact: IMPACT.empty(key) });
|
|
281
250
|
}
|
|
282
|
-
|
|
283
|
-
// Criticals: deps not installed at all
|
|
284
251
|
if (drift && drift.notInstalled) {
|
|
285
252
|
criticalIssues.push({ title: 'Dependencies are not installed', impact: IMPACT.depsNotInstalled() });
|
|
286
253
|
}
|
|
287
|
-
|
|
288
|
-
// Warnings: dependency drift
|
|
289
254
|
if (drift && !drift.notInstalled && drift.missing.length > 0) {
|
|
290
255
|
for (const dep of drift.missing) {
|
|
291
256
|
warningIssues.push({ title: dep + ' is not installed', impact: IMPACT.depsDrift(dep) });
|
|
292
257
|
}
|
|
293
258
|
}
|
|
294
|
-
|
|
295
|
-
// Warnings: duplicate vars
|
|
296
259
|
for (const key of duplicates) {
|
|
297
260
|
warningIssues.push({ title: key + ' is defined more than once', impact: IMPACT.duplicate(key) });
|
|
298
261
|
}
|
|
299
|
-
|
|
300
|
-
// Warnings: prefix issues
|
|
301
262
|
for (const { key, type } of prefixWarnings) {
|
|
302
263
|
if (type === 'vite') {
|
|
303
264
|
warningIssues.push({ title: key + ' is missing VITE_ prefix', impact: IMPACT.prefixVite(key) });
|
|
@@ -306,7 +267,6 @@ async function scan() {
|
|
|
306
267
|
}
|
|
307
268
|
}
|
|
308
269
|
|
|
309
|
-
// Passing checks
|
|
310
270
|
if (result) passingChecks.push('Environment file detected');
|
|
311
271
|
if (!drift || (!drift.notInstalled && drift.missing.length === 0)) passingChecks.push('Dependencies installed');
|
|
312
272
|
if (duplicates.length === 0) passingChecks.push('No duplicate variables');
|
|
@@ -317,23 +277,17 @@ async function scan() {
|
|
|
317
277
|
const totalIssues = criticalIssues.length + warningIssues.length;
|
|
318
278
|
const hasFailed = totalIssues > 0;
|
|
319
279
|
|
|
320
|
-
// ─── Render ───────────────────────────────────────────────────────────────
|
|
321
|
-
|
|
322
280
|
if (hasFailed) {
|
|
323
|
-
const critCount = criticalIssues.length;
|
|
324
|
-
const warnCount = warningIssues.length;
|
|
325
|
-
|
|
326
|
-
let summary = totalIssues + ' issue' + (totalIssues !== 1 ? 's' : '') + ' found';
|
|
327
281
|
const parts = [];
|
|
328
|
-
if (
|
|
329
|
-
if (
|
|
330
|
-
summary += '\n' + parts.join(' · ');
|
|
282
|
+
if (criticalIssues.length > 0) parts.push(criticalIssues.length + ' critical');
|
|
283
|
+
if (warningIssues.length > 0) parts.push(warningIssues.length + ' warning' + (warningIssues.length !== 1 ? 's' : ''));
|
|
331
284
|
|
|
332
285
|
console.log('🚨 Safelaunch Scan Report');
|
|
333
286
|
console.log('');
|
|
334
287
|
console.log('This project is NOT safe to deploy');
|
|
335
288
|
console.log('');
|
|
336
|
-
console.log(
|
|
289
|
+
console.log(totalIssues + ' issue' + (totalIssues !== 1 ? 's' : '') + ' found');
|
|
290
|
+
console.log(parts.join(' · '));
|
|
337
291
|
console.log('');
|
|
338
292
|
console.log(DIVIDER);
|
|
339
293
|
console.log('');
|
|
@@ -370,7 +324,7 @@ async function scan() {
|
|
|
370
324
|
}
|
|
371
325
|
|
|
372
326
|
if (passingChecks.length > 0) {
|
|
373
|
-
console.log(
|
|
327
|
+
console.log("✅ What's working (" + passingChecks.length + ' checks passed)');
|
|
374
328
|
console.log('');
|
|
375
329
|
for (const check of passingChecks) {
|
|
376
330
|
console.log('- ' + check);
|
|
@@ -389,8 +343,6 @@ async function scan() {
|
|
|
389
343
|
console.log('');
|
|
390
344
|
|
|
391
345
|
} else {
|
|
392
|
-
// ── All clean ──
|
|
393
|
-
|
|
394
346
|
console.log('🛡️ Safelaunch Scan Report');
|
|
395
347
|
console.log('');
|
|
396
348
|
console.log('Your project is safe to deploy');
|
|
@@ -407,7 +359,7 @@ async function scan() {
|
|
|
407
359
|
console.log('');
|
|
408
360
|
console.log(DIVIDER);
|
|
409
361
|
console.log('');
|
|
410
|
-
console.log(
|
|
362
|
+
console.log("🎉 You're good to go");
|
|
411
363
|
console.log('');
|
|
412
364
|
console.log(' Deploy with confidence');
|
|
413
365
|
console.log('');
|