@socketsecurity/cli-with-sentry 1.9.0 → 1.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 (43) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +5 -5
  3. package/dist/cli.js +186 -57
  4. package/dist/cli.js.map +1 -1
  5. package/dist/constants.js +4 -4
  6. package/dist/constants.js.map +1 -1
  7. package/dist/manifest-scripts/maven-extension/coana-maven-extension.jar +0 -0
  8. package/dist/manifest-scripts/socket-facts.init.gradle +4 -3
  9. package/dist/manifest-scripts/socket-facts.plugin.scala +80 -49
  10. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  11. package/dist/types/commands/manifest/cmd-manifest-dynamic-sbom-inference.d.mts.map +1 -1
  12. package/dist/types/commands/manifest/convert-gradle-to-facts.d.mts +3 -1
  13. package/dist/types/commands/manifest/convert-gradle-to-facts.d.mts.map +1 -1
  14. package/dist/types/commands/manifest/convert-maven-to-facts.d.mts +3 -1
  15. package/dist/types/commands/manifest/convert-maven-to-facts.d.mts.map +1 -1
  16. package/dist/types/commands/manifest/convert-sbt-to-facts.d.mts +3 -1
  17. package/dist/types/commands/manifest/convert-sbt-to-facts.d.mts.map +1 -1
  18. package/dist/types/commands/manifest/enumerate-workspaces.d.mts.map +1 -1
  19. package/dist/types/commands/manifest/generate-recursive-manifests.d.mts +8 -1
  20. package/dist/types/commands/manifest/generate-recursive-manifests.d.mts.map +1 -1
  21. package/dist/types/commands/manifest/generate_auto_manifest.d.mts.map +1 -1
  22. package/dist/types/commands/manifest/handle-manifest-dynamic-sbom-inference.d.mts +2 -1
  23. package/dist/types/commands/manifest/handle-manifest-dynamic-sbom-inference.d.mts.map +1 -1
  24. package/dist/types/commands/manifest/run-manifest-facts.d.mts +4 -1
  25. package/dist/types/commands/manifest/run-manifest-facts.d.mts.map +1 -1
  26. package/dist/types/commands/manifest/scripts/records.d.mts +4 -4
  27. package/dist/types/commands/manifest/scripts/records.d.mts.map +1 -1
  28. package/dist/types/commands/manifest/scripts/resolution-report-maven.d.mts +3 -3
  29. package/dist/types/commands/manifest/scripts/resolution-report-maven.d.mts.map +1 -1
  30. package/dist/types/commands/manifest/scripts/resolution-report-render.d.mts +20 -4
  31. package/dist/types/commands/manifest/scripts/resolution-report-render.d.mts.map +1 -1
  32. package/dist/types/commands/manifest/scripts/resolution-report.d.mts +9 -3
  33. package/dist/types/commands/manifest/scripts/resolution-report.d.mts.map +1 -1
  34. package/dist/types/commands/manifest/scripts/run.d.mts +2 -1
  35. package/dist/types/commands/manifest/scripts/run.d.mts.map +1 -1
  36. package/dist/types/commands/scan/cmd-scan-create.d.mts.map +1 -1
  37. package/dist/types/commands/scan/cmd-scan-reach.d.mts.map +1 -1
  38. package/dist/types/commands/scan/warn-socket-json-only-flags.d.mts +2 -0
  39. package/dist/types/commands/scan/warn-socket-json-only-flags.d.mts.map +1 -0
  40. package/dist/types/constants.d.mts +1 -1
  41. package/dist/utils.js +2 -1
  42. package/dist/utils.js.map +1 -1
  43. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -2445,9 +2445,9 @@ const SBT_DIALECT = {
2445
2445
  }]
2446
2446
  };
2447
2447
 
2448
- // Maven's resolver (Aether/maven-resolver): no attribute-based variants. Two
2449
- // failure shapes (artifact-resolution miss with config = scope, dependency-graph
2450
- // build failure with config = "graph") both classify off the root-cause message.
2448
+ // Maven's resolver (Aether/maven-resolver): no attribute-based variants. Both
2449
+ // failure shapes (artifact-resolution miss, dependency-graph build failure)
2450
+ // classify off the root-cause message.
2451
2451
  function classifyMavenFailure(detail) {
2452
2452
  const t = (detail || '').toLowerCase();
2453
2453
  if (t.includes('could not transfer') || t.includes('connection refused') || t.includes('connect timed out') || t.includes('connection timed out') || t.includes('read timed out') || t.includes('status code: 401') || t.includes('status code: 403') || t.includes('unauthorized') || t.includes('forbidden') || t.includes('peer not authenticated') || t.includes('certpathbuilderexception')) {
@@ -2493,6 +2493,17 @@ const MAVEN_DIALECT = {
2493
2493
 
2494
2494
  // Per-resolver classify + render/score policy.
2495
2495
 
2496
+ // Where the invoking command lets the user set each build option, so a remedy
2497
+ // names something they can actually set.
2498
+
2499
+ const DSI_SETUP_COMMAND = 'socket manifest setup --dynamic-sbom-inference';
2500
+
2501
+ // The single-build manifest commands take every option as a flag.
2502
+ const FLAG_HINTS = {
2503
+ flags: new Set(['excludeConfigs', 'ignoreUnresolved', 'verbose']),
2504
+ setupCommand: 'socket manifest setup',
2505
+ socketJson: constants.default.SOCKET_JSON
2506
+ };
2496
2507
  const RESOLUTION_REPORT_ARTIFACT_LIMIT = 15;
2497
2508
  const RESOLUTION_REPORT_CONFIG_LIMIT = 20;
2498
2509
 
@@ -2509,26 +2520,57 @@ function dedupCoords(coords) {
2509
2520
  }
2510
2521
  return [...set].filter(c => c.split(':').length >= 3 || !versioned.has(c)).sort();
2511
2522
  }
2523
+ function firstLine(s) {
2524
+ return (s || '').split('\n').map(l => l.trim()).find(Boolean) ?? '';
2525
+ }
2512
2526
  function fmtList(list, limit) {
2513
2527
  const shown = list.slice(0, limit).join(', ');
2514
2528
  return list.length > limit ? `${shown} (+${list.length - limit} more)` : shown;
2515
2529
  }
2516
- function firstLine(s) {
2517
- return (s || '').split('\n').map(l => l.trim()).find(Boolean) ?? '';
2530
+ function flagText(option, value) {
2531
+ const flag = `--${utils.camelToKebab(option)}`;
2532
+ return value === true ? flag : `${flag} '${value}'`;
2533
+ }
2534
+
2535
+ // Where a failure happened, for builds with several subprojects.
2536
+ function inProjects(projects) {
2537
+ const list = [...(typeof projects === 'string' ? [projects] : projects)].filter(Boolean).sort().map(p => `\`${p}\``);
2538
+ return list.length ? ` (in ${fmtList(list, 3)})` : '';
2539
+ }
2540
+
2541
+ // `excludableConfigs` is empty when excluding configurations cannot clear
2542
+ // every blocking failure.
2543
+ function proceedHint(hints, tool, excludableConfigs) {
2544
+ const options = [['ignoreUnresolved', true]];
2545
+ if (excludableConfigs.length) {
2546
+ options.push(['excludeConfigs', excludableConfigs.join(',')]);
2547
+ }
2548
+ const asFlags = options.filter(o => hints.flags.has(o[0]));
2549
+ const inSocketJson = options.filter(o => !hints.flags.has(o[0]));
2550
+ const setup = `\`${hints.setupCommand}\``;
2551
+ if (!inSocketJson.length) {
2552
+ return asFlags.length === 1 ? [`To proceed, re-run with ${flagText(...asFlags[0])}.`] : ['To proceed, re-run with either:', ...asFlags.map(o => ` ${flagText(...o)}`)];
2553
+ }
2554
+ if (!asFlags.length) {
2555
+ return [`To proceed, set ${options.length > 1 ? 'either of these' : 'this'} under defaults.manifest.${tool} in ${hints.socketJson} (${setup} walks you through it):`, ...options.map(([option, value]) => ` "${option}": ${JSON.stringify(value)}`)];
2556
+ }
2557
+ return ['To proceed, either:', ...asFlags.map(o => ` re-run with ${flagText(...o)}`), ...inSocketJson.map(([option, value]) => ` set defaults.manifest.${tool}.${option} to ${JSON.stringify(value)} in ${hints.socketJson} (${setup})`)];
2518
2558
  }
2519
2559
 
2520
2560
  // Severity is per-kind; the exit-code decision lives in the caller. We do NOT
2521
2561
  // cross-reference what resolved elsewhere: the failed selector carries no
2522
2562
  // classifier/type, so relating a failed and a succeeded dep is unsound.
2523
- function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2563
+ function renderResolutionReport(failures, scannedConfigs, tool, opts = {}) {
2564
+ const dialect = dialectFor(tool);
2524
2565
  const name = dialect.label;
2566
+ const hints = opts.hints ?? FLAG_HINTS;
2525
2567
  const unscannable = opts.unscannable ?? [];
2526
- const unscannableConfigs = new Set(unscannable.map(u => u.config));
2568
+ const unscannableConfigs = new Set(unscannable.filter(u => u.config).map(u => u.config));
2527
2569
  const specOf = new Map(dialect.categories.map(c => [c.key, c]));
2528
2570
  const isBlocking = cat => specOf.get(cat)?.blocking ?? true;
2529
2571
 
2530
2572
  // Aggregate by (coord, category): one module can fail with different causes
2531
- // across configs. Keep first-seen detail, union the configs.
2573
+ // across configs. Keep first-seen detail, union the configs and projects.
2532
2574
 
2533
2575
  const byKey = new Map();
2534
2576
  const keyOf = (coord, category) => `${coord} ${category}`;
@@ -2541,12 +2583,19 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2541
2583
  coord: f.coord,
2542
2584
  category,
2543
2585
  detail: f.detail,
2544
- configs: new Set()
2586
+ configs: new Set(),
2587
+ projects: new Set(),
2588
+ configless: false
2545
2589
  };
2546
2590
  byKey.set(key, info);
2547
2591
  }
2548
2592
  if (f.config) {
2549
2593
  info.configs.add(f.config);
2594
+ } else {
2595
+ info.configless = true;
2596
+ }
2597
+ if (f.project) {
2598
+ info.projects.add(f.project);
2550
2599
  }
2551
2600
  }
2552
2601
  const allInfos = [...byKey.values()];
@@ -2563,6 +2612,8 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2563
2612
  });
2564
2613
  const blockingUnscannable = unscannableInfos.filter(u => u.blocking);
2565
2614
  const nonBlockingUnscannable = unscannableInfos.filter(u => !u.blocking);
2615
+ const blockingUnscannableConfigs = blockingUnscannable.filter(u => u.config);
2616
+ const blockingUnscannableProjects = blockingUnscannable.filter(u => !u.config);
2566
2617
  const perDepBlockingConfigs = new Set();
2567
2618
  for (const info of allInfos) {
2568
2619
  if (isBlocking(info.category)) {
@@ -2571,10 +2622,13 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2571
2622
  }
2572
2623
  }
2573
2624
  }
2574
- const blockingConfigs = new Set([...perDepBlockingConfigs, ...blockingUnscannable.map(u => u.config)]);
2625
+ const blockingConfigs = new Set([...perDepBlockingConfigs, ...blockingUnscannableConfigs.map(u => u.config)]);
2575
2626
  const blockingFailed = [...blockingConfigs].sort();
2627
+ // A blocking failure outside any configuration leaves every configuration of
2628
+ // its project incomplete, so none can be reported as succeeded.
2629
+ const hasBlockingConfiglessFailure = blockingUnscannableProjects.length > 0 || allInfos.some(i => i.configless && isBlocking(i.category));
2576
2630
  // An un-scannable config was attempted but resolved nothing, so it didn't succeed.
2577
- const succeeded = scannedConfigs.filter(c => !blockingConfigs.has(c) && !unscannableConfigs.has(c)).sort();
2631
+ const succeeded = hasBlockingConfiglessFailure ? [] : scannedConfigs.filter(c => !blockingConfigs.has(c) && !unscannableConfigs.has(c)).sort();
2578
2632
  const groups = dialect.categories.map(spec => ({
2579
2633
  spec,
2580
2634
  infos: dedupCoords(allInfos.filter(i => i.category === spec.key).map(i => i.coord)).map(c => byKey.get(keyOf(c, spec.key)))
@@ -2587,7 +2641,8 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2587
2641
  const out = [];
2588
2642
  if (hasBlockingFailures) {
2589
2643
  if (blockingCount > 0) {
2590
- out.push(opts.ignoreUnresolved ? `Ignored ${blockingCount} unresolved dependency(ies) in ${perDepBlockingConfigs.size} configuration(s):` : `Could not resolve ${blockingCount} dependency(ies) in ${perDepBlockingConfigs.size} configuration(s):`);
2644
+ const inConfigs = perDepBlockingConfigs.size ? ` in ${perDepBlockingConfigs.size} configuration(s)` : '';
2645
+ out.push(opts.ignoreUnresolved ? `Ignored ${blockingCount} unresolved dependency(ies)${inConfigs}:` : `Could not resolve ${blockingCount} dependency(ies)${inConfigs}:`);
2591
2646
  for (const {
2592
2647
  infos,
2593
2648
  spec
@@ -2597,29 +2652,36 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2597
2652
  for (const info of infos.slice(0, RESOLUTION_REPORT_ARTIFACT_LIMIT)) {
2598
2653
  const fl = firstLine(info.detail);
2599
2654
  const reasonSuffix = spec.showReason && fl ? ` [${fl}]` : '';
2600
- out.push(` - ${info.coord}${reasonSuffix}`);
2655
+ out.push(` - ${info.coord}${inProjects(info.projects)}${reasonSuffix}`);
2601
2656
  }
2602
2657
  if (infos.length > RESOLUTION_REPORT_ARTIFACT_LIMIT) {
2603
2658
  out.push(` … and ${infos.length - RESOLUTION_REPORT_ARTIFACT_LIMIT} more`);
2604
2659
  }
2605
2660
  }
2606
2661
  }
2607
- if (blockingUnscannable.length) {
2608
- // Separate from the per-dep block above, but only if there is one — otherwise
2609
- // the summary would lead with a blank line (a dangling ✗ under logger.fail).
2662
+ const pushUnscannable = (items, header, label) => {
2663
+ if (!items.length) {
2664
+ return;
2665
+ }
2666
+ // Separate from the block above, but only if there is one — otherwise the
2667
+ // summary would lead with a blank line (a dangling ✗ under logger.fail).
2610
2668
  if (out.length) {
2611
2669
  out.push('');
2612
2670
  }
2613
- out.push(opts.ignoreUnresolved ? `Ignored ${blockingUnscannable.length} configuration(s) that could not be scanned:` : `Could not scan ${blockingUnscannable.length} configuration(s) (reason from ${name}):`);
2614
- for (const u of blockingUnscannable.slice(0, RESOLUTION_REPORT_CONFIG_LIMIT)) {
2671
+ out.push(header);
2672
+ for (const u of items.slice(0, RESOLUTION_REPORT_CONFIG_LIMIT)) {
2615
2673
  const fl = firstLine(u.detail);
2616
- out.push(` - ${u.config}${fl ? ` [${fl}]` : ''}`);
2674
+ out.push(` - ${label(u)}${fl ? ` [${fl}]` : ''}`);
2617
2675
  }
2618
- if (blockingUnscannable.length > RESOLUTION_REPORT_CONFIG_LIMIT) {
2619
- out.push(` … and ${blockingUnscannable.length - RESOLUTION_REPORT_CONFIG_LIMIT} more`);
2676
+ if (items.length > RESOLUTION_REPORT_CONFIG_LIMIT) {
2677
+ out.push(` … and ${items.length - RESOLUTION_REPORT_CONFIG_LIMIT} more`);
2620
2678
  }
2679
+ };
2680
+ pushUnscannable(blockingUnscannableConfigs, opts.ignoreUnresolved ? `Ignored ${blockingUnscannableConfigs.length} configuration(s) that could not be scanned:` : `Could not scan ${blockingUnscannableConfigs.length} configuration(s) (reason from ${name}):`, u => `${u.config}${inProjects(u.project)}`);
2681
+ pushUnscannable(blockingUnscannableProjects, opts.ignoreUnresolved ? `Ignored ${blockingUnscannableProjects.length} project(s) whose dependencies could not be resolved:` : `Could not resolve the dependencies of ${blockingUnscannableProjects.length} project(s) (reason from ${name}):`, u => `\`${u.project}\``);
2682
+ if (succeeded.length || blockingFailed.length) {
2683
+ out.push('');
2621
2684
  }
2622
- out.push('');
2623
2685
  if (succeeded.length) {
2624
2686
  out.push(`Resolution succeeded in: ${fmtList(succeeded, RESOLUTION_REPORT_CONFIG_LIMIT)}`);
2625
2687
  }
@@ -2628,14 +2690,10 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2628
2690
  }
2629
2691
  if (willFail) {
2630
2692
  out.push('');
2631
- out.push(`To proceed, re-run with either:`);
2632
- out.push(` --ignore-unresolved`);
2633
- if (blockingFailed.length) {
2634
- out.push(` --exclude-configs '${blockingFailed.join(',')}'`);
2635
- }
2693
+ out.push(...proceedHint(hints, tool, hasBlockingConfiglessFailure ? [] : blockingFailed));
2636
2694
  }
2637
2695
  out.push('');
2638
- out.push(`Re-run with --verbose for ${name}'s full messages.`);
2696
+ out.push(hints.flags.has('verbose') ? `Re-run with --verbose for ${name}'s full messages.` : `For ${name}'s full messages, ${verboseHint(hints, tool)}.`);
2639
2697
  }
2640
2698
  const notices = [];
2641
2699
  for (const {
@@ -2652,7 +2710,7 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2652
2710
  // matching the deliberately-lenient per-dep variant-ambiguity policy.
2653
2711
  if (nonBlockingUnscannable.length) {
2654
2712
  const n = new Set(nonBlockingUnscannable.map(u => u.config)).size;
2655
- notices.push(`Could not scan ${n} configuration(s) — re-run with --verbose for ${name}'s messages.`);
2713
+ notices.push(hints.flags.has('verbose') ? `Could not scan ${n} configuration(s) — re-run with --verbose for ${name}'s messages.` : `Could not scan ${n} configuration(s); for ${name}'s messages, ${verboseHint(hints, tool)}.`);
2656
2714
  }
2657
2715
  const detailLines = [`${name}'s full message for each unresolved dependency:`];
2658
2716
  for (const info of allInfos) {
@@ -2664,10 +2722,10 @@ function renderResolutionReport(failures, scannedConfigs, dialect, opts = {}) {
2664
2722
  }
2665
2723
  if (unscannable.length) {
2666
2724
  detailLines.push('');
2667
- detailLines.push(`${name} configurations that could not be scanned:`);
2725
+ detailLines.push(`${name} resolutions that could not be scanned:`);
2668
2726
  for (const u of unscannable) {
2669
2727
  detailLines.push('');
2670
- detailLines.push(` ${u.config}:`);
2728
+ detailLines.push(` ${u.config || 'all dependencies'}${inProjects(u.project)}:`);
2671
2729
  for (const line of (u.detail || '(no message)').split('\n')) {
2672
2730
  detailLines.push(` ${line}`);
2673
2731
  }
@@ -2691,7 +2749,10 @@ function dialectFor(tool) {
2691
2749
  }
2692
2750
  }
2693
2751
  function renderResolutionErrorReport(failures, scannedConfigs = [], tool = 'gradle', opts = {}) {
2694
- return renderResolutionReport(failures, scannedConfigs, dialectFor(tool), opts);
2752
+ return renderResolutionReport(failures, scannedConfigs, tool, opts);
2753
+ }
2754
+ function verboseHint(hints, tool) {
2755
+ return hints.flags.has('verbose') ? 'pass --verbose' : `set defaults.manifest.${tool}.verbose to true in ${hints.socketJson}`;
2695
2756
  }
2696
2757
 
2697
2758
  const PURL_TYPE_MAVEN = 'maven';
@@ -3056,7 +3117,7 @@ function buildArtifactPaths(finalNodes, projects, graphs, fileExists) {
3056
3117
  function buildReport(parsed) {
3057
3118
  const seen = new Set();
3058
3119
  const failures = parsed.failures.filter(f => {
3059
- const key = `${f.coord}|${f.detail}|${f.config}`;
3120
+ const key = `${f.coord}|${f.detail}|${f.config}|${f.project}`;
3060
3121
  if (seen.has(key)) {
3061
3122
  return false;
3062
3123
  }
@@ -3065,7 +3126,7 @@ function buildReport(parsed) {
3065
3126
  });
3066
3127
  const seenUnscannable = new Set();
3067
3128
  const unscannable = parsed.unscannable.filter(u => {
3068
- const key = `${u.config}|${u.detail}`;
3129
+ const key = `${u.config}|${u.detail}|${u.project}`;
3069
3130
  if (seenUnscannable.has(key)) {
3070
3131
  return false;
3071
3132
  }
@@ -3232,8 +3293,8 @@ function serializeExcludePathPatterns(paths) {
3232
3293
  // edge rootId parentCoordId childCoordId
3233
3294
  // file rootId coordId path (--with-files only)
3234
3295
  // scanned config
3235
- // failure coord detail config
3236
- // unscannable config detail
3296
+ // failure coord detail config projectKey (config empty: no configuration)
3297
+ // unscannable config detail projectKey (config empty: whole project)
3237
3298
  //
3238
3299
  // `projectKey` is the tool's unique project identity (Maven: GAV; Gradle:
3239
3300
  // project path; sbt: project id), emitted as the project id; a `node` whose
@@ -3402,15 +3463,17 @@ function parseRecords(text) {
3402
3463
  result.failures.push({
3403
3464
  coord: f[1],
3404
3465
  detail: f[2] ?? '',
3405
- config: f[3] ?? ''
3466
+ config: f[3] ?? '',
3467
+ project: f[4] ?? ''
3406
3468
  });
3407
3469
  }
3408
3470
  break;
3409
3471
  case 'unscannable':
3410
- if (f[1]) {
3472
+ if (f[1] || f[3]) {
3411
3473
  result.unscannable.push({
3412
- config: f[1],
3413
- detail: f[2] ?? ''
3474
+ config: f[1] ?? '',
3475
+ detail: f[2] ?? '',
3476
+ project: f[3] ?? ''
3414
3477
  });
3415
3478
  }
3416
3479
  break;
@@ -3431,6 +3494,10 @@ function manifestScriptsPath(...parts) {
3431
3494
  return path.join(constants.default.distPath, 'manifest-scripts', ...parts);
3432
3495
  }
3433
3496
 
3497
+ // Streamed build output is a diagnostic: it goes to stderr so the command's own
3498
+ // stdout (e.g. --json) stays machine-readable.
3499
+ const STREAM_TO_STDERR = ['inherit', 2, 'inherit'];
3500
+
3434
3501
  // Don't throw on a non-zero exit: the script emits failure records, so a usable
3435
3502
  // records file still exists. A non-exit spawn error (e.g. missing executable)
3436
3503
  // propagates.
@@ -3438,7 +3505,7 @@ async function runNeverThrow(bin, args, opts) {
3438
3505
  try {
3439
3506
  const result = await spawn.spawn(bin, args, {
3440
3507
  cwd: opts.projectDir,
3441
- stdio: opts.stdio ?? 'inherit',
3508
+ stdio: opts.stdio === 'pipe' ? 'pipe' : [...STREAM_TO_STDERR],
3442
3509
  ...(opts.env ? {
3443
3510
  env: opts.env
3444
3511
  } : {}),
@@ -3654,6 +3721,7 @@ async function runManifestFacts({
3654
3721
  ecosystem,
3655
3722
  excludeConfigs,
3656
3723
  excludePaths,
3724
+ hints = FLAG_HINTS,
3657
3725
  ignoreUnresolved,
3658
3726
  includeConfigs,
3659
3727
  javaHome,
@@ -3705,7 +3773,7 @@ async function runManifestFacts({
3705
3773
  logger.logger.info(`(Running ${ecosystem} with output streaming; this can take a while.)`);
3706
3774
  result = await runManifestScript(ecosystem, scriptOpts);
3707
3775
  } else {
3708
- logger.logger.info(`(No live output; pass --verbose to stream the ${ecosystem} build output.)`);
3776
+ logger.logger.info(`(No live output; to stream the ${ecosystem} build output, ${verboseHint(hints, ecosystem)}.)`);
3709
3777
  spinner.start(`Resolving ${ecosystem} dependencies ...`);
3710
3778
  result = await runManifestScript(ecosystem, scriptOpts);
3711
3779
  if (result.code === 0) {
@@ -3721,7 +3789,7 @@ async function runManifestFacts({
3721
3789
  spinner.failAndStop(`Failed to run ${ecosystem}.`);
3722
3790
  }
3723
3791
  process.exitCode = 1;
3724
- logger.logger.fail(`Could not run the ${ecosystem} build tool` + (verbose ? `: ${utils.getErrorMessageOr(e, String(e))}` : ' (run with --verbose for details).'));
3792
+ logger.logger.fail(`Could not run the ${ecosystem} build tool: ${utils.getErrorMessageOr(e, String(e))}`);
3725
3793
  return null;
3726
3794
  }
3727
3795
  const {
@@ -3735,6 +3803,7 @@ async function runManifestFacts({
3735
3803
  stdout
3736
3804
  } = result;
3737
3805
  const rendered = renderResolutionErrorReport(report.failures, report.scannedConfigs, ecosystem, {
3806
+ hints,
3738
3807
  ignoreUnresolved,
3739
3808
  unscannable: report.unscannable
3740
3809
  });
@@ -3821,16 +3890,22 @@ async function runManifestFacts({
3821
3890
  };
3822
3891
  }
3823
3892
 
3893
+ // Relative to the user's shell when inside it, else absolute.
3894
+ function displayPath(file) {
3895
+ const rel = path.relative(process.cwd(), file);
3896
+ return rel.startsWith('..') || path.isAbsolute(rel) ? file : rel;
3897
+ }
3898
+
3824
3899
  // A cascaded (not just root-level) disabled additionally skips this one build
3825
3900
  // root here, on top of its existing root-only ecosystem-wide meaning for
3826
3901
  // auto/gradle/etc. facts:false has no pom-mode equivalent here (facts-only),
3827
3902
  // so it skips too.
3828
- function getSkipReason(disabled, facts) {
3903
+ function getSkipReason(ecosystem, disabled, facts) {
3829
3904
  if (disabled) {
3830
- return 'defaults.manifest.<ecosystem>.disabled is true';
3905
+ return `defaults.manifest.${ecosystem}.disabled is true`;
3831
3906
  }
3832
3907
  if (facts === false) {
3833
- return 'defaults.manifest.<ecosystem>.facts is false (pom mode)';
3908
+ return `defaults.manifest.${ecosystem}.facts is false (pom mode)`;
3834
3909
  }
3835
3910
  return undefined;
3836
3911
  }
@@ -3849,6 +3924,8 @@ function nearestDisabledRoot(dir, disabledRoots) {
3849
3924
  async function runEcosystemCandidates({
3850
3925
  candidatesByTool,
3851
3926
  excludePaths,
3927
+ ignoreUnresolved: ignoreUnresolvedOverride,
3928
+ optionFlags,
3852
3929
  realCwd,
3853
3930
  rootSockJson,
3854
3931
  sbtTmpDir,
@@ -3879,7 +3956,8 @@ async function runEcosystemCandidates({
3879
3956
  ignoreUnresolved,
3880
3957
  includeConfigs,
3881
3958
  javaHome,
3882
- skipReason
3959
+ skipReason,
3960
+ verbose: configVerbose
3883
3961
  } = resolveEcosystemConfig(ecosystem, dir, sockJson);
3884
3962
  if (skipReason) {
3885
3963
  // Only warn for a genuinely new disabled root, not one already
@@ -3914,12 +3992,17 @@ async function runEcosystemCandidates({
3914
3992
  ecosystem,
3915
3993
  excludeConfigs,
3916
3994
  excludePaths: excludePathsForRoot,
3917
- ignoreUnresolved,
3995
+ hints: {
3996
+ flags: optionFlags,
3997
+ setupCommand: DSI_SETUP_COMMAND,
3998
+ socketJson: displayPath(path.join(dir, constants.SOCKET_JSON))
3999
+ },
4000
+ ignoreUnresolved: ignoreUnresolvedOverride ?? ignoreUnresolved,
3918
4001
  includeConfigs,
3919
4002
  javaHome,
3920
4003
  sidecarAcc,
3921
4004
  tmpDir: ecosystem === 'sbt' ? sbtTmpDir : undefined,
3922
- verbose,
4005
+ verbose: verbose || configVerbose,
3923
4006
  withFiles
3924
4007
  });
3925
4008
  if (result === null) {
@@ -3928,8 +4011,11 @@ async function runEcosystemCandidates({
3928
4011
  ecosystem,
3929
4012
  status: 'failed'
3930
4013
  });
3931
- logger.logger.warn(`Aborting ${ecosystem} discovery: ${dir}'s workspace layout could not be determined, so its remaining build roots cannot be safely classified as covered or independent.`);
3932
- for (const abortedDir of dirs.slice(dirIndex + 1)) {
4014
+ const abortedDirs = dirs.slice(dirIndex + 1);
4015
+ if (abortedDirs.length) {
4016
+ logger.logger.warn(`Aborting ${ecosystem} discovery: ${dir} failed to generate Socket facts, and without them the remaining build roots cannot be safely classified as covered or independent.`);
4017
+ }
4018
+ for (const abortedDir of abortedDirs) {
3933
4019
  outcomes.push({
3934
4020
  dir: abortedDir,
3935
4021
  ecosystem,
@@ -3966,6 +4052,8 @@ async function runEcosystemCandidates({
3966
4052
  async function generateRecursiveManifests({
3967
4053
  cwd,
3968
4054
  excludePaths,
4055
+ ignoreUnresolved,
4056
+ optionFlags = new Set(),
3969
4057
  sbtTmpDir,
3970
4058
  sidecarAcc,
3971
4059
  verbose,
@@ -3987,6 +4075,8 @@ async function generateRecursiveManifests({
3987
4075
  const runAll = resolvedSbtTmpDir => runEcosystemCandidates({
3988
4076
  candidatesByTool,
3989
4077
  excludePaths,
4078
+ ignoreUnresolved,
4079
+ optionFlags,
3990
4080
  realCwd,
3991
4081
  rootSockJson,
3992
4082
  sbtTmpDir: resolvedSbtTmpDir,
@@ -4023,7 +4113,8 @@ function resolveEcosystemConfig(ecosystem, dir, sockJson) {
4023
4113
  ignoreUnresolved: Boolean(config?.ignoreUnresolved),
4024
4114
  includeConfigs: config?.includeConfigs ?? '',
4025
4115
  javaHome: config?.javaHome ?? undefined,
4026
- skipReason: getSkipReason(config?.disabled, config?.facts)
4116
+ skipReason: getSkipReason(ecosystem, config?.disabled, config?.facts),
4117
+ verbose: Boolean(config?.verbose)
4027
4118
  };
4028
4119
  }
4029
4120
  if (ecosystem === 'gradle') {
@@ -4036,7 +4127,8 @@ function resolveEcosystemConfig(ecosystem, dir, sockJson) {
4036
4127
  ignoreUnresolved: Boolean(config?.ignoreUnresolved),
4037
4128
  includeConfigs: config?.includeConfigs ?? '',
4038
4129
  javaHome: config?.javaHome ?? undefined,
4039
- skipReason: getSkipReason(config?.disabled, config?.facts)
4130
+ skipReason: getSkipReason(ecosystem, config?.disabled, config?.facts),
4131
+ verbose: Boolean(config?.verbose)
4040
4132
  };
4041
4133
  }
4042
4134
  const config = sockJson.defaults?.manifest?.maven;
@@ -4048,7 +4140,8 @@ function resolveEcosystemConfig(ecosystem, dir, sockJson) {
4048
4140
  ignoreUnresolved: Boolean(config?.ignoreUnresolved),
4049
4141
  includeConfigs: config?.includeConfigs ?? '',
4050
4142
  javaHome: config?.javaHome ?? undefined,
4051
- skipReason: getSkipReason(config?.disabled)
4143
+ skipReason: getSkipReason(ecosystem, config?.disabled),
4144
+ verbose: Boolean(config?.verbose)
4052
4145
  };
4053
4146
  }
4054
4147
 
@@ -6463,6 +6556,7 @@ async function convertGradleToFacts({
6463
6556
  excludeConfigs,
6464
6557
  excludePaths,
6465
6558
  gradleOpts,
6559
+ hints,
6466
6560
  ignoreUnresolved,
6467
6561
  includeConfigs,
6468
6562
  javaHome,
@@ -6477,6 +6571,7 @@ async function convertGradleToFacts({
6477
6571
  ecosystem: 'gradle',
6478
6572
  excludeConfigs,
6479
6573
  excludePaths,
6574
+ hints,
6480
6575
  ignoreUnresolved,
6481
6576
  includeConfigs,
6482
6577
  javaHome,
@@ -6493,6 +6588,7 @@ async function convertMavenToFacts({
6493
6588
  cwd,
6494
6589
  excludeConfigs,
6495
6590
  excludePaths,
6591
+ hints,
6496
6592
  ignoreUnresolved,
6497
6593
  includeConfigs,
6498
6594
  javaHome,
@@ -6508,6 +6604,7 @@ async function convertMavenToFacts({
6508
6604
  ecosystem: 'maven',
6509
6605
  excludeConfigs,
6510
6606
  excludePaths,
6607
+ hints,
6511
6608
  ignoreUnresolved,
6512
6609
  includeConfigs,
6513
6610
  javaHome,
@@ -6525,6 +6622,7 @@ async function convertSbtToFacts({
6525
6622
  cwd,
6526
6623
  excludeConfigs,
6527
6624
  excludePaths,
6625
+ hints,
6528
6626
  ignoreUnresolved,
6529
6627
  includeConfigs,
6530
6628
  javaHome,
@@ -6541,6 +6639,7 @@ async function convertSbtToFacts({
6541
6639
  ecosystem: 'sbt',
6542
6640
  excludeConfigs,
6543
6641
  excludePaths,
6642
+ hints,
6544
6643
  ignoreUnresolved,
6545
6644
  includeConfigs,
6546
6645
  javaHome,
@@ -7004,6 +7103,12 @@ async function handleManifestConda({
7004
7103
  await outputRequirements(data, outputKind, out === '-' ? out : path.resolve(cwd, out));
7005
7104
  }
7006
7105
 
7106
+ // Auto-manifest reads every build option from the root socket.json.
7107
+ const AUTO_MANIFEST_HINTS = {
7108
+ flags: new Set(),
7109
+ setupCommand: 'socket manifest setup',
7110
+ socketJson: constants.SOCKET_JSON
7111
+ };
7007
7112
  // Under --auto-manifest, a manifest generator that failed — raising the exit
7008
7113
  // code above the value captured before it ran — aborts the whole run: a partial
7009
7114
  // or empty SBOM silently under-reports dependencies. The generator has already
@@ -7055,6 +7160,7 @@ async function generateAutoManifest({
7055
7160
  ignoreUnresolved: Boolean(sockJson.defaults?.manifest?.sbt?.ignoreUnresolved),
7056
7161
  includeConfigs: sockJson.defaults?.manifest?.sbt?.includeConfigs ?? '',
7057
7162
  javaHome: sockJson.defaults?.manifest?.sbt?.javaHome ?? undefined,
7163
+ hints: AUTO_MANIFEST_HINTS,
7058
7164
  sidecarAcc,
7059
7165
  tmpDir,
7060
7166
  withFiles: computeArtifactsSidecar
@@ -7090,6 +7196,7 @@ async function generateAutoManifest({
7090
7196
  ignoreUnresolved: Boolean(sockJson.defaults?.manifest?.gradle?.ignoreUnresolved),
7091
7197
  includeConfigs: sockJson.defaults?.manifest?.gradle?.includeConfigs ?? '',
7092
7198
  javaHome: sockJson.defaults?.manifest?.gradle?.javaHome ?? undefined,
7199
+ hints: AUTO_MANIFEST_HINTS,
7093
7200
  sidecarAcc,
7094
7201
  withFiles: computeArtifactsSidecar
7095
7202
  });
@@ -7114,6 +7221,7 @@ async function generateAutoManifest({
7114
7221
  includeConfigs: sockJson.defaults?.manifest?.maven?.includeConfigs ?? '',
7115
7222
  javaHome: sockJson.defaults?.manifest?.maven?.javaHome ?? undefined,
7116
7223
  mavenOpts: parseBuildToolOpts(sockJson.defaults?.manifest?.maven?.mavenOpts ?? undefined),
7224
+ hints: AUTO_MANIFEST_HINTS,
7117
7225
  sidecarAcc,
7118
7226
  verbose: Boolean(sockJson.defaults?.manifest?.maven?.verbose),
7119
7227
  withFiles: computeArtifactsSidecar
@@ -10006,7 +10114,7 @@ const generalFlags$2 = {
10006
10114
  allowOverrides: {
10007
10115
  type: 'boolean',
10008
10116
  default: false,
10009
- description: "When the only fix for a vulnerability is blocked by a parent package's declared version range, write an override or resolution that forces the fixed version under that parent. This can install a version outside the range the parent declares, so test the parent afterwards. Works for npm, pnpm, Yarn Berry and Rush projects."
10117
+ description: "When the only fix for a vulnerability is blocked by a parent package's declared version range, write an override or resolution that forces the fixed version under that parent. This can install a version outside the range the parent declares, so test the parent afterwards. Works for npm, pnpm, Yarn and Rush projects."
10010
10118
  },
10011
10119
  autopilot: {
10012
10120
  type: 'boolean',
@@ -12935,12 +13043,15 @@ async function outputManifestDynamicSbomInference(result, outputKind) {
12935
13043
  async function handleManifestDynamicSbomInference({
12936
13044
  cwd,
12937
13045
  excludePaths,
13046
+ ignoreUnresolved,
12938
13047
  outputKind,
12939
13048
  verbose
12940
13049
  }) {
12941
13050
  const outcomes = await generateRecursiveManifests({
12942
13051
  cwd,
12943
13052
  excludePaths,
13053
+ ignoreUnresolved,
13054
+ optionFlags: new Set(['ignoreUnresolved', 'verbose']),
12944
13055
  verbose
12945
13056
  });
12946
13057
  const result = !outcomes.length ? {
@@ -12968,6 +13079,10 @@ const config$d = {
12968
13079
  ...flags.commonFlags,
12969
13080
  ...flags.outputFlags,
12970
13081
  ...excludePathsFlag,
13082
+ ignoreUnresolved: {
13083
+ type: 'boolean',
13084
+ description: "Warn on unresolved dependencies instead of failing the run (unresolved deps are not emitted to the facts files); overrides each build's socket.json setting"
13085
+ },
12971
13086
  verbose: {
12972
13087
  type: 'boolean',
12973
13088
  default: false,
@@ -13012,6 +13127,7 @@ async function run$E(argv, importMeta, {
13012
13127
  });
13013
13128
  const {
13014
13129
  dryRun,
13130
+ ignoreUnresolved,
13015
13131
  json,
13016
13132
  markdown,
13017
13133
  verbose: verboseFlag
@@ -13055,6 +13171,7 @@ async function run$E(argv, importMeta, {
13055
13171
  await handleManifestDynamicSbomInference({
13056
13172
  cwd,
13057
13173
  excludePaths,
13174
+ ignoreUnresolved,
13058
13175
  outputKind,
13059
13176
  verbose
13060
13177
  });
@@ -14731,7 +14848,7 @@ async function enumerateWorkspaces({
14731
14848
  result = await enumerateWorkspaces$1(ecosystem, scriptOpts);
14732
14849
  } catch (e) {
14733
14850
  process.exitCode = 1;
14734
- logger.logger.fail(`Could not run the ${ecosystem} build tool` + (' (run with --verbose for details).'));
14851
+ logger.logger.fail(`Could not run the ${ecosystem} build tool: ${utils.getErrorMessageOr(e, String(e))}`);
14735
14852
  return;
14736
14853
  }
14737
14854
  if (!result.projects.length) {
@@ -19871,6 +19988,16 @@ async function validateReachabilityTarget(targets, cwd) {
19871
19988
  return result;
19872
19989
  }
19873
19990
 
19991
+ // Build options that `socket manifest <tool>` takes as flags but the scan
19992
+ // commands read from each build's socket.json, so passing them does nothing.
19993
+ const SOCKET_JSON_ONLY_FLAGS = ['excludeConfigs', 'ignoreUnresolved', 'includeConfigs', 'verbose'];
19994
+ function warnSocketJsonOnlyFlags(flags, command) {
19995
+ const ignored = SOCKET_JSON_ONLY_FLAGS.filter(name => flags[name] !== undefined).map(name => `--${utils.camelToKebab(name)}`);
19996
+ if (ignored.length) {
19997
+ logger.logger.warn(`Ignoring ${ignored.join(', ')}: \`${command}\` reads build options from each build's socket.json. Set them there, for example with \`${DSI_SETUP_COMMAND}\`.`);
19998
+ }
19999
+ }
20000
+
19874
20001
  const CMD_NAME$a = 'create';
19875
20002
 
19876
20003
  // Accepted for backwards compatibility but forwarded nowhere, so passing one
@@ -20110,6 +20237,7 @@ async function run$d(argv, importMeta, {
20110
20237
 
20111
20238
  // Validate ecosystem values against the reachability-supported set.
20112
20239
  const reachEcosystems = utils.parseReachEcosystems(utils.cmdFlagValueToArray(cli.flags['reachEcosystems']));
20240
+ warnSocketJsonOnlyFlags(cli.flags, `${parentName} ${CMD_NAME$a}`);
20113
20241
  const dryRun = !!cli.flags['dryRun'];
20114
20242
  const uvMembers = !!cli.flags['uvMembers'];
20115
20243
  let {
@@ -22463,6 +22591,7 @@ async function run$7(argv, importMeta, {
22463
22591
  importMeta,
22464
22592
  parentName
22465
22593
  });
22594
+ warnSocketJsonOnlyFlags(cli.flags, `${parentName} ${CMD_NAME$4}`);
22466
22595
  const {
22467
22596
  cwd: cwdOverride,
22468
22597
  dynamicSbomInference,
@@ -24539,5 +24668,5 @@ process.on('unhandledRejection', async (reason, promise) => {
24539
24668
  // eslint-disable-next-line n/no-process-exit
24540
24669
  process.exit(1);
24541
24670
  });
24542
- //# debugId=c715fb1e-bcb7-40c4-b394-2bc4db5e64a
24671
+ //# debugId=ccb7632d-f5e4-4589-8d85-1814c416c744
24543
24672
  //# sourceMappingURL=cli.js.map