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.
Files changed (2) hide show
  1. package/dist/cli.js +61 -11
  2. 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
- for (let i = 0; i < findings.length; i++) {
502
- const f = findings[i];
503
- const isLast = i === findings.length - 1;
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
- for (const [file, fileFindings] of byFile) {
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
- for (let i = 0; i < fileFindings.length; i++) {
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 - 1;
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: 3 # Major versions behind to flag
915
- # unmaintainedYears: 2 # Years without publish to flag
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.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.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.0",
58
+ "@preship/core": "2.0.1",
59
59
  "@preship/license": "2.0.0",
60
- "@preship/security": "1.0.0",
61
- "@preship/secrets": "1.0.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"