preship 2.0.2 → 2.0.6
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/dist/cli.js +175 -71
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -109,8 +109,12 @@ async function unifiedScan(options) {
|
|
|
109
109
|
}
|
|
110
110
|
const mode = config.mode ?? "auto";
|
|
111
111
|
const policy = config.policy ?? "commercial-safe";
|
|
112
|
+
const progress = options?.onProgress ?? (() => {
|
|
113
|
+
});
|
|
114
|
+
progress("Detecting project...");
|
|
112
115
|
const projects = (0, import_core.detectProjects)(projectPath);
|
|
113
116
|
const project = projects[0];
|
|
117
|
+
progress(`Parsing ${project.type} lockfile...`);
|
|
114
118
|
const packageJsonPath = path.join(project.path, "package.json");
|
|
115
119
|
let parsedDeps;
|
|
116
120
|
switch (project.type) {
|
|
@@ -136,6 +140,7 @@ async function unifiedScan(options) {
|
|
|
136
140
|
if (modules.license) {
|
|
137
141
|
promises.push(
|
|
138
142
|
(async () => {
|
|
143
|
+
progress("Scanning licenses...");
|
|
139
144
|
const licenseStart = Date.now();
|
|
140
145
|
const dependencies = await (0, import_license.resolveLicenses)(parsedDeps, projectPath, {
|
|
141
146
|
mode,
|
|
@@ -169,6 +174,7 @@ async function unifiedScan(options) {
|
|
|
169
174
|
if (modules.security) {
|
|
170
175
|
promises.push(
|
|
171
176
|
(async () => {
|
|
177
|
+
progress("Checking security vulnerabilities...");
|
|
172
178
|
const securityConfig = (0, import_security.mergeSecurityConfig)(config.security);
|
|
173
179
|
securityResult = await (0, import_security.scanSecurity)(parsedDeps, projectPath, securityConfig, mode);
|
|
174
180
|
})()
|
|
@@ -177,6 +183,7 @@ async function unifiedScan(options) {
|
|
|
177
183
|
if (modules.secrets) {
|
|
178
184
|
promises.push(
|
|
179
185
|
(async () => {
|
|
186
|
+
progress("Scanning for leaked secrets...");
|
|
180
187
|
secretsResult = await (0, import_secrets.scanSecrets)(projectPath, config.secrets);
|
|
181
188
|
})()
|
|
182
189
|
);
|
|
@@ -303,12 +310,12 @@ function formatTerminalUnified(result, warnOnly = false) {
|
|
|
303
310
|
if (warnOnly) {
|
|
304
311
|
return formatWarnOnlyUnified(result);
|
|
305
312
|
}
|
|
313
|
+
const totalTime = (result.totalScanDurationMs / 1e3).toFixed(1);
|
|
306
314
|
lines.push("");
|
|
307
315
|
lines.push(import_chalk.default.bold("\u{1F50D} PreShip: Pre-ship verification"));
|
|
308
316
|
lines.push(` Project: ${import_chalk.default.cyan(getProjectName(result.projectPath))}${result.framework ? ` (${result.framework})` : ""}`);
|
|
309
317
|
lines.push(` Lock file: ${import_chalk.default.cyan(getLockFileName(result.projectType))} (${result.projectType})`);
|
|
310
|
-
lines.push(` Policy: ${import_chalk.default.cyan(result.policy)}`);
|
|
311
|
-
lines.push(` Mode: ${import_chalk.default.cyan(result.mode)}`);
|
|
318
|
+
lines.push(` Policy: ${import_chalk.default.cyan(result.policy)} ${import_chalk.default.dim("|")} Mode: ${import_chalk.default.cyan(result.mode)}`);
|
|
312
319
|
const enabledModules = [];
|
|
313
320
|
if (result.modules.license) enabledModules.push("license");
|
|
314
321
|
if (result.modules.security) enabledModules.push("security");
|
|
@@ -326,89 +333,172 @@ function formatTerminalUnified(result, warnOnly = false) {
|
|
|
326
333
|
}
|
|
327
334
|
lines.push(` Modules: ${import_chalk.default.cyan(enabledModules.join(", "))}`);
|
|
328
335
|
lines.push("");
|
|
336
|
+
lines.push(import_chalk.default.bold(`\u{1F4CA} Scan Summary`) + import_chalk.default.dim(` Total time: ${totalTime}s`));
|
|
337
|
+
const summaryTable = new import_cli_table3.default({
|
|
338
|
+
head: ["Module", "Scanned", "Passed", "Issues", "Warnings", "Status", "Time"],
|
|
339
|
+
colWidths: [12, 12, 9, 9, 10, 9, 8],
|
|
340
|
+
style: { head: ["cyan"] }
|
|
341
|
+
});
|
|
329
342
|
if (result.modules.license) {
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
343
|
+
const lic = result.modules.license;
|
|
344
|
+
const issues = lic.rejected.length;
|
|
345
|
+
const warnings = lic.warned.length + lic.unknown.length;
|
|
346
|
+
summaryTable.push([
|
|
347
|
+
"License",
|
|
348
|
+
`${lic.totalPackages} pkgs`,
|
|
349
|
+
String(lic.allowed.length),
|
|
350
|
+
issues > 0 ? import_chalk.default.red(String(issues)) : "0",
|
|
351
|
+
warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
|
|
352
|
+
lic.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
|
|
353
|
+
`${(lic.scanDurationMs / 1e3).toFixed(1)}s`
|
|
354
|
+
]);
|
|
355
|
+
}
|
|
356
|
+
if (result.modules.security) {
|
|
357
|
+
const sec = result.modules.security;
|
|
358
|
+
const issues = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high").length;
|
|
359
|
+
const warnings = sec.findings.filter((f) => f.severity === "medium" || f.severity === "low").length;
|
|
360
|
+
summaryTable.push([
|
|
361
|
+
"Security",
|
|
362
|
+
`${sec.totalPackages} pkgs`,
|
|
363
|
+
import_chalk.default.dim("--"),
|
|
364
|
+
issues > 0 ? import_chalk.default.red(String(issues)) : "0",
|
|
365
|
+
warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
|
|
366
|
+
sec.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
|
|
367
|
+
`${(sec.scanDurationMs / 1e3).toFixed(1)}s`
|
|
368
|
+
]);
|
|
369
|
+
}
|
|
370
|
+
if (result.modules.secrets) {
|
|
371
|
+
const sec = result.modules.secrets;
|
|
372
|
+
const issues = sec.stats.critical + sec.stats.high;
|
|
373
|
+
const warnings = sec.stats.medium + sec.stats.low;
|
|
374
|
+
summaryTable.push([
|
|
375
|
+
"Secrets",
|
|
376
|
+
`${sec.filesScanned} files`,
|
|
377
|
+
import_chalk.default.dim("--"),
|
|
378
|
+
issues > 0 ? import_chalk.default.red(String(issues)) : "0",
|
|
379
|
+
warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
|
|
380
|
+
sec.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
|
|
381
|
+
`${(sec.scanDurationMs / 1e3).toFixed(1)}s`
|
|
382
|
+
]);
|
|
383
|
+
}
|
|
384
|
+
lines.push(summaryTable.toString());
|
|
385
|
+
lines.push("");
|
|
386
|
+
if (result.modules.license && result.modules.license.passed) {
|
|
387
|
+
const lic = result.modules.license;
|
|
388
|
+
const warnings = lic.warned.length + lic.unknown.length;
|
|
389
|
+
if (warnings > 0) {
|
|
390
|
+
lines.push(import_chalk.default.green(`\u{1F4DC} License Compliance \u2014 \u2705 ${lic.allowed.length} passed`) + import_chalk.default.yellow(`, ${warnings} warning${warnings > 1 ? "s" : ""}`));
|
|
336
391
|
} else {
|
|
337
|
-
|
|
338
|
-
lines.push(import_chalk.default.green(` \u2705 ${license.allowed.length} packages \u2014 Allowed`));
|
|
339
|
-
}
|
|
340
|
-
if (license.warned.length > 0) {
|
|
341
|
-
lines.push(import_chalk.default.yellow(` \u26A0\uFE0F ${license.warned.length} package${license.warned.length > 1 ? "s" : ""} \u2014 Warning (weak copyleft)`));
|
|
342
|
-
formatPolicyResultsIndented(license.warned, lines, import_chalk.default.yellow);
|
|
343
|
-
}
|
|
344
|
-
if (license.rejected.length > 0) {
|
|
345
|
-
lines.push(import_chalk.default.red(` \u274C ${license.rejected.length} package${license.rejected.length > 1 ? "s" : ""} \u2014 Rejected`));
|
|
346
|
-
formatPolicyResultsIndented(license.rejected, lines, import_chalk.default.red);
|
|
347
|
-
}
|
|
348
|
-
if (license.unknown.length > 0) {
|
|
349
|
-
lines.push(import_chalk.default.yellow(` \u26A0\uFE0F ${license.unknown.length} package${license.unknown.length > 1 ? "s" : ""} \u2014 Unknown License`));
|
|
350
|
-
formatPolicyResultsIndented(license.unknown, lines, import_chalk.default.yellow);
|
|
351
|
-
}
|
|
392
|
+
lines.push(import_chalk.default.green(`\u{1F4DC} License Compliance \u2014 \u2705 All ${lic.totalPackages} packages passed`));
|
|
352
393
|
}
|
|
353
|
-
lines.push("");
|
|
354
394
|
}
|
|
355
|
-
if (result.modules.security) {
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
lines.push("");
|
|
360
|
-
if (security.findings.length === 0) {
|
|
361
|
-
lines.push(import_chalk.default.green(" \u2705 No security issues found"));
|
|
395
|
+
if (result.modules.security && result.modules.security.passed) {
|
|
396
|
+
const sec = result.modules.security;
|
|
397
|
+
if (sec.findings.length === 0) {
|
|
398
|
+
lines.push(import_chalk.default.green(`\u{1F6E1}\uFE0F Security Vulnerabilities \u2014 \u2705 No issues found`));
|
|
362
399
|
} else {
|
|
363
|
-
|
|
364
|
-
if (security.stats.critical > 0) statParts.push(import_chalk.default.red(`${security.stats.critical} critical`));
|
|
365
|
-
if (security.stats.high > 0) statParts.push(import_chalk.default.red(`${security.stats.high} high`));
|
|
366
|
-
if (security.stats.medium > 0) statParts.push(import_chalk.default.yellow(`${security.stats.medium} medium`));
|
|
367
|
-
if (security.stats.low > 0) statParts.push(import_chalk.default.dim(`${security.stats.low} low`));
|
|
368
|
-
if (security.stats.deprecated > 0) statParts.push(import_chalk.default.yellow(`${security.stats.deprecated} deprecated`));
|
|
369
|
-
if (security.stats.outdated > 0) statParts.push(import_chalk.default.yellow(`${security.stats.outdated} outdated`));
|
|
370
|
-
if (security.stats.unmaintained > 0) statParts.push(import_chalk.default.yellow(`${security.stats.unmaintained} unmaintained`));
|
|
371
|
-
lines.push(` ${statParts.join(" \u2502 ")}`);
|
|
372
|
-
lines.push("");
|
|
373
|
-
const vulnFindings = security.findings.filter((f) => f.type === "vulnerability");
|
|
374
|
-
const healthFindings = security.findings.filter((f) => f.type !== "vulnerability");
|
|
375
|
-
if (vulnFindings.length > 0) {
|
|
376
|
-
formatSecurityFindings(vulnFindings, lines, "Vulnerabilities");
|
|
377
|
-
}
|
|
378
|
-
if (healthFindings.length > 0) {
|
|
379
|
-
formatSecurityFindings(healthFindings, lines, "Health Issues");
|
|
380
|
-
}
|
|
400
|
+
lines.push(import_chalk.default.green(`\u{1F6E1}\uFE0F Security Vulnerabilities \u2014 \u2705 Passed`) + import_chalk.default.yellow(` (${sec.findings.length} low-severity finding${sec.findings.length > 1 ? "s" : ""})`));
|
|
381
401
|
}
|
|
382
|
-
lines.push("");
|
|
383
402
|
}
|
|
384
|
-
if (result.modules.secrets) {
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
lines.push("");
|
|
389
|
-
if (secrets.findings.length === 0) {
|
|
390
|
-
lines.push(import_chalk.default.green(" \u2705 No leaked secrets found"));
|
|
403
|
+
if (result.modules.secrets && result.modules.secrets.passed) {
|
|
404
|
+
const sec = result.modules.secrets;
|
|
405
|
+
if (sec.findings.length === 0) {
|
|
406
|
+
lines.push(import_chalk.default.green(`\u{1F511} Secret Detection \u2014 \u2705 No issues found`));
|
|
391
407
|
} else {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
408
|
+
lines.push(import_chalk.default.green(`\u{1F511} Secret Detection \u2014 \u2705 Passed`) + import_chalk.default.yellow(` (${sec.findings.length} low-severity finding${sec.findings.length > 1 ? "s" : ""})`));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const hasLicenseFailures = (result.modules.license?.rejected.length ?? 0) > 0;
|
|
412
|
+
const hasSecurityFailures = result.modules.security ? result.modules.security.findings.filter((f) => f.severity === "critical" || f.severity === "high").length > 0 : false;
|
|
413
|
+
const hasSecretFailures = result.modules.secrets ? result.modules.secrets.findings.filter((f) => f.severity === "critical" || f.severity === "high").length > 0 : false;
|
|
414
|
+
if (hasLicenseFailures || hasSecurityFailures || hasSecretFailures) {
|
|
415
|
+
lines.push("");
|
|
416
|
+
lines.push(import_chalk.default.red.bold("\u274C Failures"));
|
|
417
|
+
lines.push("");
|
|
418
|
+
if (hasLicenseFailures) {
|
|
419
|
+
const lic = result.modules.license;
|
|
420
|
+
lines.push(import_chalk.default.red(` \u{1F4DC} License Compliance \u2014 ${lic.rejected.length} rejected`));
|
|
421
|
+
formatPolicyResultsTruncated(lic.rejected, lines, import_chalk.default.red, 10);
|
|
422
|
+
lines.push("");
|
|
423
|
+
}
|
|
424
|
+
if (hasSecurityFailures) {
|
|
425
|
+
const sec = result.modules.security;
|
|
426
|
+
const critHighFindings = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high");
|
|
427
|
+
const parts = [];
|
|
428
|
+
const critCount = critHighFindings.filter((f) => f.severity === "critical").length;
|
|
429
|
+
const highCount = critHighFindings.filter((f) => f.severity === "high").length;
|
|
430
|
+
if (critCount > 0) parts.push(`${critCount} critical`);
|
|
431
|
+
if (highCount > 0) parts.push(`${highCount} high`);
|
|
432
|
+
lines.push(import_chalk.default.red(` \u{1F6E1}\uFE0F Security Vulnerabilities \u2014 ${parts.join(", ")}`));
|
|
433
|
+
const vulnFails = critHighFindings.filter((f) => f.type === "vulnerability");
|
|
434
|
+
const healthFails = critHighFindings.filter((f) => f.type !== "vulnerability");
|
|
435
|
+
if (vulnFails.length > 0) formatSecurityFindings(vulnFails, lines, "Vulnerabilities");
|
|
436
|
+
if (healthFails.length > 0) formatSecurityFindings(healthFails, lines, "Health Issues");
|
|
398
437
|
lines.push("");
|
|
399
|
-
formatSecretFindings(secrets.findings, lines);
|
|
400
438
|
}
|
|
439
|
+
if (hasSecretFailures) {
|
|
440
|
+
const sec = result.modules.secrets;
|
|
441
|
+
const critHighFindings = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high");
|
|
442
|
+
const parts = [];
|
|
443
|
+
const critCount = critHighFindings.filter((f) => f.severity === "critical").length;
|
|
444
|
+
const highCount = critHighFindings.filter((f) => f.severity === "high").length;
|
|
445
|
+
if (critCount > 0) parts.push(`${critCount} critical`);
|
|
446
|
+
if (highCount > 0) parts.push(`${highCount} high`);
|
|
447
|
+
lines.push(import_chalk.default.red(` \u{1F511} Secret Detection \u2014 ${parts.join(", ")}`));
|
|
448
|
+
formatSecretFindings(critHighFindings, lines);
|
|
449
|
+
lines.push("");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const licenseWarnings = result.modules.license ? [...result.modules.license.warned, ...result.modules.license.unknown] : [];
|
|
453
|
+
const securityWarnings = result.modules.security ? result.modules.security.findings.filter((f) => f.severity === "medium" || f.severity === "low") : [];
|
|
454
|
+
const secretWarnings = result.modules.secrets ? result.modules.secrets.findings.filter((f) => f.severity === "medium" || f.severity === "low") : [];
|
|
455
|
+
const hasWarnings = licenseWarnings.length > 0 || securityWarnings.length > 0 || secretWarnings.length > 0;
|
|
456
|
+
if (hasWarnings) {
|
|
457
|
+
lines.push(import_chalk.default.yellow.bold("\u26A0\uFE0F Warnings"));
|
|
401
458
|
lines.push("");
|
|
459
|
+
if (licenseWarnings.length > 0) {
|
|
460
|
+
const warnedCount = result.modules.license.warned.length;
|
|
461
|
+
const unknownCount = result.modules.license.unknown.length;
|
|
462
|
+
const parts = [];
|
|
463
|
+
if (warnedCount > 0) parts.push(`${warnedCount} weak copyleft`);
|
|
464
|
+
if (unknownCount > 0) parts.push(`${unknownCount} unknown`);
|
|
465
|
+
lines.push(import_chalk.default.yellow(` \u{1F4DC} License Compliance \u2014 ${parts.join(", ")}`));
|
|
466
|
+
formatPolicyResultsTruncated(licenseWarnings, lines, import_chalk.default.yellow, 10);
|
|
467
|
+
lines.push("");
|
|
468
|
+
}
|
|
469
|
+
if (securityWarnings.length > 0) {
|
|
470
|
+
const medCount = securityWarnings.filter((f) => f.severity === "medium").length;
|
|
471
|
+
const lowCount = securityWarnings.filter((f) => f.severity === "low").length;
|
|
472
|
+
const parts = [];
|
|
473
|
+
if (medCount > 0) parts.push(`${medCount} medium`);
|
|
474
|
+
if (lowCount > 0) parts.push(`${lowCount} low`);
|
|
475
|
+
lines.push(import_chalk.default.yellow(` \u{1F6E1}\uFE0F Security Vulnerabilities \u2014 ${parts.join(", ")}`));
|
|
476
|
+
const vulnWarns = securityWarnings.filter((f) => f.type === "vulnerability");
|
|
477
|
+
const healthWarns = securityWarnings.filter((f) => f.type !== "vulnerability");
|
|
478
|
+
if (vulnWarns.length > 0) formatSecurityFindings(vulnWarns, lines, "Vulnerabilities");
|
|
479
|
+
if (healthWarns.length > 0) formatSecurityFindings(healthWarns, lines, "Health Issues");
|
|
480
|
+
lines.push("");
|
|
481
|
+
}
|
|
482
|
+
if (secretWarnings.length > 0) {
|
|
483
|
+
const medCount = secretWarnings.filter((f) => f.severity === "medium").length;
|
|
484
|
+
const lowCount = secretWarnings.filter((f) => f.severity === "low").length;
|
|
485
|
+
const parts = [];
|
|
486
|
+
if (medCount > 0) parts.push(`${medCount} medium`);
|
|
487
|
+
if (lowCount > 0) parts.push(`${lowCount} low`);
|
|
488
|
+
lines.push(import_chalk.default.yellow(` \u{1F511} Secret Detection \u2014 ${parts.join(", ")}`));
|
|
489
|
+
formatSecretFindings(secretWarnings, lines);
|
|
490
|
+
lines.push("");
|
|
491
|
+
}
|
|
402
492
|
}
|
|
403
|
-
lines.push("\u2501".repeat(
|
|
493
|
+
lines.push("\u2501".repeat(62));
|
|
404
494
|
if (result.passed) {
|
|
405
|
-
lines.push(import_chalk.default.green.bold(`\u2705 RESULT: All checks passed
|
|
495
|
+
lines.push(import_chalk.default.green.bold(`\u2705 RESULT: All checks passed`));
|
|
406
496
|
} else {
|
|
407
497
|
const failedModules = [];
|
|
408
498
|
if (result.modules.license && !result.modules.license.passed) failedModules.push("license");
|
|
409
499
|
if (result.modules.security && !result.modules.security.passed) failedModules.push("security");
|
|
410
500
|
if (result.modules.secrets && !result.modules.secrets.passed) failedModules.push("secrets");
|
|
411
|
-
lines.push(import_chalk.default.red.bold(`\u274C RESULT:
|
|
501
|
+
lines.push(import_chalk.default.red.bold(`\u274C RESULT: ${failedModules.length} of ${enabledModules.length} check${enabledModules.length > 1 ? "s" : ""} failed`));
|
|
412
502
|
lines.push("");
|
|
413
503
|
lines.push(import_chalk.default.dim("\u{1F4A1} To fix:"));
|
|
414
504
|
if (result.modules.license && !result.modules.license.passed) {
|
|
@@ -486,15 +576,21 @@ function formatPolicyResults(results, lines, colorFn) {
|
|
|
486
576
|
lines.push(import_chalk.default.dim(`${reasonPrefix}Reason: ${getShortReason(r)}`));
|
|
487
577
|
}
|
|
488
578
|
}
|
|
489
|
-
function
|
|
490
|
-
|
|
579
|
+
function formatPolicyResultsTruncated(results, lines, colorFn, maxItems) {
|
|
580
|
+
const showCount = Math.min(results.length, maxItems);
|
|
581
|
+
for (let i = 0; i < showCount; i++) {
|
|
491
582
|
const r = results[i];
|
|
492
|
-
const isLast = i === results.length
|
|
583
|
+
const isLast = i === showCount - 1 && results.length <= maxItems;
|
|
493
584
|
const prefix = isLast ? " \u2514\u2500\u2500 " : " \u251C\u2500\u2500 ";
|
|
494
585
|
const reasonPrefix = isLast ? " " : " \u2502 ";
|
|
495
586
|
lines.push(colorFn(`${prefix}${r.dependency.name}@${r.dependency.version} \u2014 ${r.dependency.license}`));
|
|
496
587
|
lines.push(import_chalk.default.dim(`${reasonPrefix}Reason: ${getShortReason(r)}`));
|
|
497
588
|
}
|
|
589
|
+
if (results.length > maxItems) {
|
|
590
|
+
const remaining = results.length - maxItems;
|
|
591
|
+
lines.push(import_chalk.default.dim(` \u2514\u2500\u2500 ... and ${remaining} more`));
|
|
592
|
+
lines.push(import_chalk.default.dim(" Run with --format json for full details"));
|
|
593
|
+
}
|
|
498
594
|
}
|
|
499
595
|
function formatSecurityFindings(findings, lines, heading) {
|
|
500
596
|
const MAX_FINDINGS = 15;
|
|
@@ -810,8 +906,13 @@ function registerScanCommand(program2) {
|
|
|
810
906
|
}
|
|
811
907
|
return;
|
|
812
908
|
}
|
|
909
|
+
const showProgress = !options.silent && options.format === "table";
|
|
910
|
+
const onProgress = showProgress ? (msg) => {
|
|
911
|
+
process.stderr.write(`\r\x1B[K\x1B[2m \u23F3 ${msg}\x1B[0m`);
|
|
912
|
+
} : void 0;
|
|
813
913
|
const result = await unifiedScan({
|
|
814
914
|
projectPath: options.project,
|
|
915
|
+
onProgress,
|
|
815
916
|
config: {
|
|
816
917
|
scanDevDependencies: options.dev || void 0,
|
|
817
918
|
output: options.format !== "table" ? options.format : void 0,
|
|
@@ -835,6 +936,9 @@ function registerScanCommand(program2) {
|
|
|
835
936
|
}
|
|
836
937
|
}
|
|
837
938
|
});
|
|
939
|
+
if (showProgress) {
|
|
940
|
+
process.stderr.write("\r\x1B[K");
|
|
941
|
+
}
|
|
838
942
|
if (!options.silent) {
|
|
839
943
|
switch (options.format) {
|
|
840
944
|
case "json":
|
|
@@ -3914,7 +4018,7 @@ function registerAllowCommand(program2) {
|
|
|
3914
4018
|
|
|
3915
4019
|
// src/cli.ts
|
|
3916
4020
|
var program = new import_commander.Command();
|
|
3917
|
-
program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.
|
|
4021
|
+
program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.6");
|
|
3918
4022
|
registerScanCommand(program);
|
|
3919
4023
|
registerInitCommand(program);
|
|
3920
4024
|
registerListCommand(program);
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export { Dependency, DetectedProject, ExceptionEntry, LicenseSource, ModuleConfi
|
|
|
4
4
|
interface ScanOptions {
|
|
5
5
|
projectPath?: string;
|
|
6
6
|
config?: Partial<PreshipConfig>;
|
|
7
|
+
/** Optional progress callback for CLI status updates */
|
|
8
|
+
onProgress?: (message: string) => void;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Legacy scan function — license-only scan for backwards compatibility.
|
package/dist/index.js
CHANGED
|
@@ -119,8 +119,12 @@ async function unifiedScan(options) {
|
|
|
119
119
|
}
|
|
120
120
|
const mode = config.mode ?? "auto";
|
|
121
121
|
const policy = config.policy ?? "commercial-safe";
|
|
122
|
+
const progress = options?.onProgress ?? (() => {
|
|
123
|
+
});
|
|
124
|
+
progress("Detecting project...");
|
|
122
125
|
const projects = (0, import_core.detectProjects)(projectPath);
|
|
123
126
|
const project = projects[0];
|
|
127
|
+
progress(`Parsing ${project.type} lockfile...`);
|
|
124
128
|
const packageJsonPath = path.join(project.path, "package.json");
|
|
125
129
|
let parsedDeps;
|
|
126
130
|
switch (project.type) {
|
|
@@ -146,6 +150,7 @@ async function unifiedScan(options) {
|
|
|
146
150
|
if (modules.license) {
|
|
147
151
|
promises.push(
|
|
148
152
|
(async () => {
|
|
153
|
+
progress("Scanning licenses...");
|
|
149
154
|
const licenseStart = Date.now();
|
|
150
155
|
const dependencies = await (0, import_license.resolveLicenses)(parsedDeps, projectPath, {
|
|
151
156
|
mode,
|
|
@@ -179,6 +184,7 @@ async function unifiedScan(options) {
|
|
|
179
184
|
if (modules.security) {
|
|
180
185
|
promises.push(
|
|
181
186
|
(async () => {
|
|
187
|
+
progress("Checking security vulnerabilities...");
|
|
182
188
|
const securityConfig = (0, import_security.mergeSecurityConfig)(config.security);
|
|
183
189
|
securityResult = await (0, import_security.scanSecurity)(parsedDeps, projectPath, securityConfig, mode);
|
|
184
190
|
})()
|
|
@@ -187,6 +193,7 @@ async function unifiedScan(options) {
|
|
|
187
193
|
if (modules.secrets) {
|
|
188
194
|
promises.push(
|
|
189
195
|
(async () => {
|
|
196
|
+
progress("Scanning for leaked secrets...");
|
|
190
197
|
secretsResult = await (0, import_secrets.scanSecrets)(projectPath, config.secrets);
|
|
191
198
|
})()
|
|
192
199
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "preship",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Pre-ship verification for modern dev teams. License compliance, security vulnerability scanning, and secret detection — all in one CLI. Zero config. Fully offline. Free forever.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"license",
|
|
@@ -56,9 +56,9 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@preship/core": "2.0.1",
|
|
59
|
-
"@preship/license": "2.0.
|
|
60
|
-
"@preship/security": "1.0.
|
|
61
|
-
"@preship/secrets": "1.0.
|
|
59
|
+
"@preship/license": "2.0.1",
|
|
60
|
+
"@preship/security": "1.0.2",
|
|
61
|
+
"@preship/secrets": "1.0.4",
|
|
62
62
|
"chalk": "^4.1.2",
|
|
63
63
|
"cli-table3": "^0.6.5",
|
|
64
64
|
"commander": "^12.1.0"
|