preship 2.0.0 → 2.0.2
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 +61 -11
- package/package.json +4 -4
package/dist/cli.js
CHANGED
|
@@ -497,35 +497,82 @@ function formatPolicyResultsIndented(results, lines, colorFn) {
|
|
|
497
497
|
}
|
|
498
498
|
}
|
|
499
499
|
function formatSecurityFindings(findings, lines, heading) {
|
|
500
|
+
const MAX_FINDINGS = 15;
|
|
501
|
+
const sorted = [...findings].sort((a, b) => severityRank(a.severity) - severityRank(b.severity));
|
|
500
502
|
lines.push(import_chalk.default.dim(` ${heading}:`));
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const
|
|
503
|
+
const showCount = Math.min(sorted.length, MAX_FINDINGS);
|
|
504
|
+
for (let i = 0; i < showCount; i++) {
|
|
505
|
+
const f = sorted[i];
|
|
506
|
+
const isLast = i === showCount - 1 && sorted.length <= MAX_FINDINGS;
|
|
504
507
|
const prefix = isLast ? " \u2514\u2500\u2500 " : " \u251C\u2500\u2500 ";
|
|
505
508
|
const severityColor = getSeverityColor(f.severity);
|
|
506
509
|
const severityBadge = severityColor(`[${f.severity.toUpperCase()}]`);
|
|
507
510
|
lines.push(`${prefix}${severityBadge} ${f.package}@${f.version}`);
|
|
508
511
|
lines.push(import_chalk.default.dim(`${isLast ? " " : " \u2502 "}${f.message}`));
|
|
509
512
|
}
|
|
513
|
+
if (sorted.length > MAX_FINDINGS) {
|
|
514
|
+
const remaining = sorted.length - MAX_FINDINGS;
|
|
515
|
+
lines.push(import_chalk.default.dim(` \u2514\u2500\u2500 ... and ${remaining} more ${heading.toLowerCase()}`));
|
|
516
|
+
lines.push(import_chalk.default.dim(" Run with --format json for full details"));
|
|
517
|
+
}
|
|
510
518
|
}
|
|
511
519
|
function formatSecretFindings(findings, lines) {
|
|
520
|
+
const MAX_FINDINGS_PER_FILE = 5;
|
|
521
|
+
const MAX_FILES = 10;
|
|
512
522
|
const byFile = /* @__PURE__ */ new Map();
|
|
513
523
|
for (const f of findings) {
|
|
514
524
|
const existing = byFile.get(f.file) || [];
|
|
515
525
|
existing.push(f);
|
|
516
526
|
byFile.set(f.file, existing);
|
|
517
527
|
}
|
|
518
|
-
|
|
528
|
+
const sortedFiles = [...byFile.entries()].sort((a, b) => {
|
|
529
|
+
const aSeverity = Math.min(...a[1].map((f) => severityRank(f.severity)));
|
|
530
|
+
const bSeverity = Math.min(...b[1].map((f) => severityRank(f.severity)));
|
|
531
|
+
return aSeverity - bSeverity;
|
|
532
|
+
});
|
|
533
|
+
let filesShown = 0;
|
|
534
|
+
let totalHidden = 0;
|
|
535
|
+
for (const [file, fileFindings] of sortedFiles) {
|
|
536
|
+
if (filesShown >= MAX_FILES) {
|
|
537
|
+
totalHidden += fileFindings.length;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
filesShown++;
|
|
519
541
|
lines.push(import_chalk.default.dim(` ${file}:`));
|
|
520
|
-
|
|
542
|
+
const showCount = Math.min(fileFindings.length, MAX_FINDINGS_PER_FILE);
|
|
543
|
+
for (let i = 0; i < showCount; i++) {
|
|
521
544
|
const f = fileFindings[i];
|
|
522
|
-
const isLast = i === fileFindings.length
|
|
545
|
+
const isLast = i === showCount - 1 && fileFindings.length <= MAX_FINDINGS_PER_FILE;
|
|
523
546
|
const prefix = isLast ? " \u2514\u2500\u2500 " : " \u251C\u2500\u2500 ";
|
|
524
547
|
const severityColor = getSeverityColor(f.severity);
|
|
525
548
|
const severityBadge = severityColor(`[${f.severity.toUpperCase()}]`);
|
|
526
549
|
lines.push(`${prefix}${severityBadge} Line ${f.line}: ${f.description}`);
|
|
527
550
|
lines.push(import_chalk.default.dim(`${isLast ? " " : " \u2502 "}Match: ${f.match}`));
|
|
528
551
|
}
|
|
552
|
+
if (fileFindings.length > MAX_FINDINGS_PER_FILE) {
|
|
553
|
+
const remaining = fileFindings.length - MAX_FINDINGS_PER_FILE;
|
|
554
|
+
lines.push(import_chalk.default.dim(` \u2514\u2500\u2500 ... and ${remaining} more finding${remaining > 1 ? "s" : ""} in this file`));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (totalHidden > 0) {
|
|
558
|
+
const hiddenFiles = sortedFiles.length - MAX_FILES;
|
|
559
|
+
lines.push("");
|
|
560
|
+
lines.push(import_chalk.default.dim(` ... and ${totalHidden} more finding${totalHidden > 1 ? "s" : ""} in ${hiddenFiles} more file${hiddenFiles > 1 ? "s" : ""}`));
|
|
561
|
+
lines.push(import_chalk.default.dim(" Run with --format json for full details"));
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function severityRank(severity) {
|
|
565
|
+
switch (severity) {
|
|
566
|
+
case "critical":
|
|
567
|
+
return 0;
|
|
568
|
+
case "high":
|
|
569
|
+
return 1;
|
|
570
|
+
case "medium":
|
|
571
|
+
return 2;
|
|
572
|
+
case "low":
|
|
573
|
+
return 3;
|
|
574
|
+
default:
|
|
575
|
+
return 4;
|
|
529
576
|
}
|
|
530
577
|
}
|
|
531
578
|
function getSeverityColor(severity) {
|
|
@@ -723,7 +770,7 @@ function escapeCsv(value) {
|
|
|
723
770
|
|
|
724
771
|
// src/commands/scan.ts
|
|
725
772
|
function registerScanCommand(program2) {
|
|
726
|
-
program2.command("scan").description("Scan the current project for license, security, and secret issues").option("--format <type>", "Output format: table, json, csv", "table").option("--strict", "Exit code 1 on warnings too (not just rejections)").option("--dev", "Include devDependencies in scan").option("--project <path>", "Path to project root", process.cwd()).option("--config <path>", "Path to config file").option("--warn-only", "Never exit with error (for postinstall hook usage)").option("--silent", "No output, only exit code").option("--mode <type>", "Resolution mode: auto (online+local fallback), online (registry only), local (offline only)", "auto").option("--no-cache", "Disable license cache (.preship-cache.json)").option("--cache-ttl <seconds>", "Cache TTL in seconds (default: 604800 = 7 days)", parseInt).option("--scan-timeout <ms>", "Total scan timeout in milliseconds (default: 60000, 0 = disabled)", parseInt).option("--license-only", "Run license scan only (legacy mode)").option("--no-license", "Disable license scanning").option("--no-security", "Disable security vulnerability scanning").option("--no-secrets", "Disable secret detection scanning").option("--security-severity <level>", "Security policy level: default, strict, lenient").option("--security-fail-on <severity>", "Minimum severity to fail: critical, high, medium, low").action(async (options) => {
|
|
773
|
+
program2.command("scan").description("Scan the current project for license, security, and secret issues").option("--format <type>", "Output format: table, json, csv", "table").option("--strict", "Exit code 1 on warnings too (not just rejections)").option("--dev", "Include devDependencies in scan").option("--project <path>", "Path to project root", process.cwd()).option("--config <path>", "Path to config file").option("--warn-only", "Never exit with error (for postinstall hook usage)").option("--silent", "No output, only exit code").option("--mode <type>", "Resolution mode: auto (online+local fallback), online (registry only), local (offline only)", "auto").option("--no-cache", "Disable license cache (.preship-cache.json)").option("--cache-ttl <seconds>", "Cache TTL in seconds (default: 604800 = 7 days)", parseInt).option("--scan-timeout <ms>", "Total scan timeout in milliseconds (default: 60000, 0 = disabled)", parseInt).option("--license-only", "Run license scan only (legacy mode)").option("--no-license", "Disable license scanning").option("--no-security", "Disable security vulnerability scanning").option("--no-secrets", "Disable secret detection scanning").option("--security-severity <level>", "Security policy level: default, strict, lenient").option("--security-fail-on <severity>", "Minimum severity to fail: critical, high, medium, low").option("--no-outdated", "Disable outdated package checks").option("--no-deprecated", "Disable deprecated package checks").option("--no-unmaintained", "Disable unmaintained package checks").action(async (options) => {
|
|
727
774
|
try {
|
|
728
775
|
if (options.licenseOnly) {
|
|
729
776
|
const result2 = await scan({
|
|
@@ -781,7 +828,10 @@ function registerScanCommand(program2) {
|
|
|
781
828
|
// Security config from CLI flags
|
|
782
829
|
security: {
|
|
783
830
|
severity: options.securitySeverity || void 0,
|
|
784
|
-
failOn: options.securityFailOn || void 0
|
|
831
|
+
failOn: options.securityFailOn || void 0,
|
|
832
|
+
checkOutdated: options.outdated !== void 0 ? options.outdated : void 0,
|
|
833
|
+
checkDeprecated: options.deprecated !== void 0 ? options.deprecated : void 0,
|
|
834
|
+
checkUnmaintained: options.unmaintained !== void 0 ? options.unmaintained : void 0
|
|
785
835
|
}
|
|
786
836
|
}
|
|
787
837
|
});
|
|
@@ -911,8 +961,8 @@ policy: ${policy}
|
|
|
911
961
|
# checkOutdated: true # Flag outdated packages
|
|
912
962
|
# checkDeprecated: true # Flag deprecated packages
|
|
913
963
|
# checkUnmaintained: true # Flag unmaintained packages
|
|
914
|
-
# outdatedMajorThreshold:
|
|
915
|
-
# unmaintainedYears:
|
|
964
|
+
# outdatedMajorThreshold: 5 # Major versions behind to flag (direct deps only)
|
|
965
|
+
# unmaintainedYears: 4 # Years without publish to flag
|
|
916
966
|
|
|
917
967
|
# ===== Secret Detection =====
|
|
918
968
|
# secrets:
|
|
@@ -3864,7 +3914,7 @@ function registerAllowCommand(program2) {
|
|
|
3864
3914
|
|
|
3865
3915
|
// src/cli.ts
|
|
3866
3916
|
var program = new import_commander.Command();
|
|
3867
|
-
program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.
|
|
3917
|
+
program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.2");
|
|
3868
3918
|
registerScanCommand(program);
|
|
3869
3919
|
registerInitCommand(program);
|
|
3870
3920
|
registerListCommand(program);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "preship",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
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",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"lint": "tsc --noEmit"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@preship/core": "2.0.
|
|
58
|
+
"@preship/core": "2.0.1",
|
|
59
59
|
"@preship/license": "2.0.0",
|
|
60
|
-
"@preship/security": "1.0.
|
|
61
|
-
"@preship/secrets": "1.0.
|
|
60
|
+
"@preship/security": "1.0.1",
|
|
61
|
+
"@preship/secrets": "1.0.2",
|
|
62
62
|
"chalk": "^4.1.2",
|
|
63
63
|
"cli-table3": "^0.6.5",
|
|
64
64
|
"commander": "^12.1.0"
|