@socketsecurity/cli-with-sentry 0.14.57 → 0.14.59

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.
@@ -26,6 +26,7 @@ var ndjson = _socketInterop(require('ndjson'));
26
26
  var shadowNpmInject = require('./shadow-npm-inject.js');
27
27
  var constants = require('./constants.js');
28
28
  var objects = require('@socketsecurity/registry/lib/objects');
29
+ var path$1 = require('@socketsecurity/registry/lib/path');
29
30
  var regexps = require('@socketsecurity/registry/lib/regexps');
30
31
  var commonTags = _socketInterop(require('common-tags'));
31
32
  var fs$1 = require('node:fs/promises');
@@ -40,26 +41,29 @@ var require$$0$1 = require('node:util');
40
41
  var registry = require('@socketsecurity/registry');
41
42
  var npm = require('@socketsecurity/registry/lib/npm');
42
43
  var packages = require('@socketsecurity/registry/lib/packages');
43
- var registryConstants = require('@socketsecurity/registry/lib/constants');
44
- var isInteractive = require('@socketregistry/is-interactive/index.cjs');
45
- var terminalLink = _socketInterop(require('terminal-link'));
44
+ var lockfileFile = _socketInterop(require('@pnpm/lockfile-file'));
45
+ var lockfile_detectDepTypes = _socketInterop(require('@pnpm/lockfile.detect-dep-types'));
46
+ var debug = require('@socketsecurity/registry/lib/debug');
46
47
  var spawn = require('@socketsecurity/registry/lib/spawn');
47
- var npa = _socketInterop(require('npm-package-arg'));
48
- var semver = _socketInterop(require('semver'));
49
- var tinyglobby = _socketInterop(require('tinyglobby'));
50
- var promises = require('@socketsecurity/registry/lib/promises');
48
+ var shadowNpmPaths = require('./shadow-npm-paths.js');
51
49
  var browserslist = _socketInterop(require('browserslist'));
50
+ var semver = _socketInterop(require('semver'));
52
51
  var which = _socketInterop(require('which'));
53
52
  var index_cjs = require('@socketregistry/hyrious__bun.lockb/index.cjs');
54
53
  var sorts = require('@socketsecurity/registry/lib/sorts');
55
54
  var strings = require('@socketsecurity/registry/lib/strings');
55
+ var registryConstants = require('@socketsecurity/registry/lib/constants');
56
+ var isInteractive = require('@socketregistry/is-interactive/index.cjs');
57
+ var terminalLink = _socketInterop(require('terminal-link'));
58
+ var npa = _socketInterop(require('npm-package-arg'));
59
+ var tinyglobby = _socketInterop(require('tinyglobby'));
60
+ var promises = require('@socketsecurity/registry/lib/promises');
56
61
  var yaml = _socketInterop(require('yaml'));
57
- var debug = require('@socketsecurity/registry/lib/debug');
58
- var shadowNpmPaths = require('./shadow-npm-paths.js');
59
62
  var betterAjvErrors = _socketInterop(require('@apideck/better-ajv-errors'));
60
63
  var config$A = require('@socketsecurity/config');
61
64
  var assert = require('node:assert');
62
65
  var readline = require('node:readline/promises');
66
+ var BoxWidget = _socketInterop(require('blessed/lib/widgets/box'));
63
67
  var TableWidget = _socketInterop(require('blessed-contrib/lib/widget/table'));
64
68
  var readline$1 = require('node:readline');
65
69
 
@@ -321,7 +325,7 @@ class Core {
321
325
  }) {
322
326
  const introducedBy = [];
323
327
  if (pkg.direct) {
324
- let manifests = pkg.manifestFiles.map(({
328
+ const manifests = pkg.manifestFiles.map(({
325
329
  file
326
330
  }) => file).join(';');
327
331
  introducedBy.push(['direct', manifests]);
@@ -332,7 +336,7 @@ class Core {
332
336
  continue;
333
337
  }
334
338
  const topPurl = `${topPackage.type}/${topPackage.name}@${topPackage.version}`;
335
- let manifests = topPackage.manifestFiles.map(({
339
+ const manifests = topPackage.manifestFiles.map(({
336
340
  file
337
341
  }) => file).join(';');
338
342
  introducedBy.push([topPurl, manifests]);
@@ -764,7 +768,7 @@ function processSecurityComment({
764
768
  const result = [];
765
769
  let start = false;
766
770
  let ignoreAll = false;
767
- let ignoredPackages = [];
771
+ const ignoredPackages = [];
768
772
  for (const ignoreComment of ignoreComments) {
769
773
  const parsed = parseIgnoreCommand(ignoreComment.body?.split('\n').at(0) ?? '');
770
774
  if (parsed.ignoreAll) {
@@ -788,7 +792,7 @@ function processSecurityComment({
788
792
  const [_, _title, packageLink, _introducedBy, _manifest, _ci] = line.split('|');
789
793
 
790
794
  // Parsing package link [npm/pkg](url)
791
- let [_ecosystem, pkg] = packageLink.slice(1, packageLink.indexOf(']')).split('/', 2);
795
+ const [_ecosystem, pkg] = packageLink.slice(1, packageLink.indexOf(']')).split('/', 2);
792
796
  const [pkgName, pkgVersion] = pkg.split('@');
793
797
 
794
798
  // Checking if this package should be ignored
@@ -1111,8 +1115,8 @@ function createSources(alert) {
1111
1115
  manifests.push(addStr);
1112
1116
  }
1113
1117
  }
1114
- let manifestList = manifests.join('');
1115
- let sourceList = sources.join('');
1118
+ const manifestList = manifests.join('');
1119
+ const sourceList = sources.join('');
1116
1120
  const manifestStr = `<ul>${manifestList}</ul>`;
1117
1121
  const sourcesStr = `<ul>${sourceList}</ul>`;
1118
1122
  return [manifestStr, sourcesStr];
@@ -1257,8 +1261,8 @@ async function runAction(githubEventBefore, githubEventAfter) {
1257
1261
  const securityComment = securityCommentTemplate(diff);
1258
1262
  let newSecurityComment = true;
1259
1263
  let newOverviewComment = true;
1260
- let updateOldSecurityComment = comments.security !== undefined;
1261
- let updateOldOverviewComment = comments.overview !== undefined;
1264
+ const updateOldSecurityComment = comments.security !== undefined;
1265
+ const updateOldOverviewComment = comments.overview !== undefined;
1262
1266
  if (diff.newAlerts.length === 0) {
1263
1267
  if (!updateOldSecurityComment) {
1264
1268
  newSecurityComment = false;
@@ -1400,8 +1404,7 @@ const validationFlags = {
1400
1404
 
1401
1405
  const {
1402
1406
  DRY_RUN_LABEL: DRY_RUN_LABEL$1,
1403
- REDACTED,
1404
- SOCKET_CLI_SHOW_BANNER
1407
+ REDACTED
1405
1408
  } = constants;
1406
1409
  async function meowWithSubcommands(subcommands, options) {
1407
1410
  const {
@@ -1435,11 +1438,7 @@ async function meowWithSubcommands(subcommands, options) {
1435
1438
  };
1436
1439
  // ...else we provide basic instructions and help.
1437
1440
 
1438
- // Temp disable until we clear the --json and --markdown usage
1439
- // Lazily access constants.ENV[SOCKET_CLI_SHOW_BANNER].
1440
- if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1441
- logger.logger.log(getAsciiHeader(name));
1442
- }
1441
+ emitBanner(name);
1443
1442
  const cli = vendor.meow(`
1444
1443
  Usage
1445
1444
  $ ${name} <command>
@@ -1493,11 +1492,7 @@ function meowOrExit({
1493
1492
  parentName
1494
1493
  }) {
1495
1494
  const command = `${parentName} ${config.commandName}`;
1496
- // Temp disable until we clear the --json and --markdown usage.
1497
- // Lazily access constants.ENV[SOCKET_CLI_SHOW_BANNER].
1498
- if (constants.ENV[SOCKET_CLI_SHOW_BANNER]) {
1499
- logger.logger.log(getAsciiHeader(command));
1500
- }
1495
+ emitBanner(command);
1501
1496
 
1502
1497
  // This exits if .printHelp() is called either by meow itself or by us.
1503
1498
  const cli = vendor.meow({
@@ -1514,13 +1509,24 @@ function meowOrExit({
1514
1509
  }
1515
1510
  return cli;
1516
1511
  }
1512
+ function emitBanner(name) {
1513
+ // Print a banner at the top of each command.
1514
+ // This helps with brand recognition and marketing.
1515
+ // It also helps with debugging since it contains version and command details.
1516
+ // Note: print over stderr to preserve stdout for flags like --json and
1517
+ // --markdown. If we don't do this, you can't use --json in particular
1518
+ // and pipe the result to other tools. By emiting the banner over stderr
1519
+ // you can do something like `socket scan view xyz | jq | process`.
1520
+ // The spinner also emits over stderr for example.
1521
+ logger.logger.error(getAsciiHeader(name));
1522
+ }
1517
1523
  function getAsciiHeader(command) {
1518
1524
  const cliVersion = // The '@rollup/plugin-replace' will replace "process.env['SOCKET_CLI_VERSION_HASH']".
1519
- "0.14.57:6783de7:236c7308:pub";
1525
+ "0.14.59:e40b009:5200cfd8:pub";
1520
1526
  const nodeVersion = process.version;
1521
1527
  const apiToken = shadowNpmInject.getSetting('apiToken');
1522
1528
  const shownToken = apiToken ? getLastFiveOfApiToken(apiToken) : 'no';
1523
- const relCwd = process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}`, 'i'), '~/');
1529
+ const relCwd = path$1.normalizePath(process.cwd().replace(new RegExp(`^${regexps.escapeRegExp(constants.homePath)}(?:${path.sep}|$)`, 'i'), '~/'));
1524
1530
  const body = `
1525
1531
  _____ _ _ /---------------
1526
1532
  | __|___ ___| |_ ___| |_ | Socket.dev CLI ver ${cliVersion}
@@ -1719,7 +1725,7 @@ async function outputAnalyticsWithToken({
1719
1725
  // A message should already have been printed if we have no data here
1720
1726
  if (!data) return;
1721
1727
  if (outputKind === 'json') {
1722
- let serialized = renderJson(data);
1728
+ const serialized = renderJson(data);
1723
1729
  if (!serialized) return;
1724
1730
  if (filePath && filePath !== '-') {
1725
1731
  try {
@@ -2191,6 +2197,9 @@ const config$x = {
2191
2197
  Usage
2192
2198
  $ ${command} <org slug>
2193
2199
 
2200
+ This feature requires an Enterprise Plan. To learn more about getting access
2201
+ to this feature and many more, please visit https://socket.dev/pricing
2202
+
2194
2203
  Options
2195
2204
  ${getFlagListOutput(config.flags, 6)}
2196
2205
 
@@ -2246,22 +2255,22 @@ async function run$x(argv, importMeta, {
2246
2255
  }
2247
2256
 
2248
2257
  const {
2249
- NPM: NPM$e,
2258
+ NPM: NPM$f,
2250
2259
  NPX: NPX$3,
2251
- PNPM: PNPM$8
2260
+ PNPM: PNPM$a
2252
2261
  } = constants;
2253
- const nodejsPlatformTypes = new Set(['javascript', 'js', 'nodejs', NPM$e, PNPM$8, 'ts', 'tsx', 'typescript']);
2262
+ const nodejsPlatformTypes = new Set(['javascript', 'js', 'nodejs', NPM$f, PNPM$a, 'ts', 'tsx', 'typescript']);
2254
2263
  async function runCycloneDX(yargv) {
2255
2264
  let cleanupPackageLock = false;
2256
2265
  if (yargv.type !== 'yarn' && nodejsPlatformTypes.has(yargv.type) && fs.existsSync('./yarn.lock')) {
2257
2266
  if (fs.existsSync('./package-lock.json')) {
2258
- yargv.type = NPM$e;
2267
+ yargv.type = NPM$f;
2259
2268
  } else {
2260
2269
  // Use synp to create a package-lock.json from the yarn.lock,
2261
2270
  // based on the node_modules folder, for a more accurate SBOM.
2262
2271
  try {
2263
2272
  await shadowBin(NPX$3, ['synp@1.9.14', '--', '--source-file', './yarn.lock'], 2);
2264
- yargv.type = NPM$e;
2273
+ yargv.type = NPM$f;
2265
2274
  cleanupPackageLock = true;
2266
2275
  } catch {}
2267
2276
  }
@@ -2781,99 +2790,105 @@ const cmdDiffScan = {
2781
2790
  }
2782
2791
  };
2783
2792
 
2784
- // import { detect } from '../../utils/package-environment-detector'
2785
-
2786
2793
  const {
2787
- NPM: NPM$d
2794
+ NPM: NPM$e
2788
2795
  } = constants;
2789
2796
  function isTopLevel(tree, node) {
2790
2797
  return tree.children.get(node.name) === node;
2791
2798
  }
2792
- async function runFix() {
2793
- // Lazily access constants.spinner.
2799
+ async function npmFix(_pkgEnvDetails, cwd, options) {
2794
2800
  const {
2795
2801
  spinner
2796
- } = constants;
2797
- spinner.start();
2798
- const cwd = process.cwd();
2799
- const editablePkgJson = await packages.readPackageJson(cwd, {
2800
- editable: true
2801
- });
2802
- // const agentDetails = await detect()
2803
-
2802
+ } = {
2803
+ __proto__: null,
2804
+ ...options
2805
+ };
2806
+ spinner?.start();
2804
2807
  const arb = new shadowNpmInject.SafeArborist({
2805
2808
  path: cwd,
2806
2809
  ...shadowNpmInject.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
2807
2810
  });
2808
2811
  await arb.reify();
2809
- const alerts = await shadowNpmInject.getPackagesAlerts(arb, {
2812
+ const alertsMap = await shadowNpmInject.getAlertsMapFromArborist(arb, {
2810
2813
  consolidate: true,
2811
- includeExisting: true,
2812
- includeUnfixable: false
2814
+ include: {
2815
+ existing: true,
2816
+ unfixable: false,
2817
+ upgrade: false
2818
+ }
2813
2819
  });
2814
- const infoByPkg = shadowNpmInject.getCveInfoByPackage(alerts);
2820
+ const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap);
2821
+ if (!infoByPkg) {
2822
+ spinner?.stop();
2823
+ return;
2824
+ }
2815
2825
  await arb.buildIdealTree();
2816
- if (infoByPkg) {
2817
- for (const {
2818
- 0: name,
2819
- 1: infos
2820
- } of infoByPkg) {
2821
- let revertToIdealTree = arb.idealTree;
2822
- arb.idealTree = null;
2823
- // eslint-disable-next-line no-await-in-loop
2824
- await arb.buildIdealTree();
2825
- const tree = arb.idealTree;
2826
- const hasUpgrade = !!registry.getManifestData(NPM$d, name);
2827
- if (hasUpgrade) {
2828
- spinner.info(`Skipping ${name}. Socket Optimize package exists.`);
2829
- continue;
2830
- }
2831
- const nodes = shadowNpmInject.findPackageNodes(tree, name);
2832
- const packument = nodes.length && infos.length ?
2833
- // eslint-disable-next-line no-await-in-loop
2834
- await packages.fetchPackagePackument(name) : null;
2835
- if (packument) {
2836
- for (let i = 0, {
2837
- length: nodesLength
2838
- } = nodes; i < nodesLength; i += 1) {
2839
- const node = nodes[i];
2840
- for (let j = 0, {
2841
- length: infosLength
2842
- } = infos; j < infosLength; j += 1) {
2843
- const {
2844
- firstPatchedVersionIdentifier,
2845
- vulnerableVersionRange
2846
- } = infos[j];
2847
- const {
2848
- version: oldVersion
2849
- } = node;
2850
- if (shadowNpmInject.updateNode(node, packument, vulnerableVersionRange)) {
2851
- try {
2852
- // eslint-disable-next-line no-await-in-loop
2853
- await npm.runScript('test', [], {
2854
- spinner,
2855
- stdio: 'ignore'
2856
- });
2857
- spinner.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
2858
- if (isTopLevel(tree, node)) {
2859
- for (const depField of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
2860
- const oldVersion = editablePkgJson.content[depField]?.[name];
2861
- if (oldVersion) {
2862
- const decorator = /^[~^]/.exec(oldVersion)?.[0] ?? '';
2863
- editablePkgJson.content[depField][name] = `${decorator}${node.version}`;
2864
- }
2865
- }
2826
+ const editablePkgJson = await packages.readPackageJson(cwd, {
2827
+ editable: true
2828
+ });
2829
+ for (const {
2830
+ 0: name,
2831
+ 1: infos
2832
+ } of infoByPkg) {
2833
+ const revertToIdealTree = arb.idealTree;
2834
+ arb.idealTree = null;
2835
+ // eslint-disable-next-line no-await-in-loop
2836
+ await arb.buildIdealTree();
2837
+ const tree = arb.idealTree;
2838
+ const hasUpgrade = !!registry.getManifestData(NPM$e, name);
2839
+ if (hasUpgrade) {
2840
+ spinner?.info(`Skipping ${name}. Socket Optimize package exists.`);
2841
+ continue;
2842
+ }
2843
+ const nodes = shadowNpmInject.findPackageNodes(tree, name);
2844
+ const packument = nodes.length && infos.length ?
2845
+ // eslint-disable-next-line no-await-in-loop
2846
+ await packages.fetchPackagePackument(name) : null;
2847
+ if (!packument) {
2848
+ continue;
2849
+ }
2850
+ for (let i = 0, {
2851
+ length: nodesLength
2852
+ } = nodes; i < nodesLength; i += 1) {
2853
+ const node = nodes[i];
2854
+ for (let j = 0, {
2855
+ length: infosLength
2856
+ } = infos; j < infosLength; j += 1) {
2857
+ const {
2858
+ firstPatchedVersionIdentifier,
2859
+ vulnerableVersionRange
2860
+ } = infos[j];
2861
+ const {
2862
+ version: oldVersion
2863
+ } = node;
2864
+ if (shadowNpmInject.updateNode(node, packument, vulnerableVersionRange)) {
2865
+ try {
2866
+ // eslint-disable-next-line no-await-in-loop
2867
+ await npm.runScript('test', [], {
2868
+ spinner,
2869
+ stdio: 'ignore'
2870
+ });
2871
+ spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
2872
+ if (isTopLevel(tree, node)) {
2873
+ for (const depField of ['dependencies', 'optionalDependencies', 'peerDependencies']) {
2874
+ const {
2875
+ content: pkgJson
2876
+ } = editablePkgJson;
2877
+ const oldVersion = pkgJson[depField]?.[name];
2878
+ if (oldVersion) {
2879
+ const decorator = /^[~^]/.exec(oldVersion)?.[0] ?? '';
2880
+ pkgJson[depField][name] = `${decorator}${node.version}`;
2866
2881
  }
2867
- // eslint-disable-next-line no-await-in-loop
2868
- await editablePkgJson.save();
2869
- } catch {
2870
- spinner.error(`Reverting ${name} to ${oldVersion}`);
2871
- arb.idealTree = revertToIdealTree;
2872
2882
  }
2873
- } else {
2874
- spinner.error(`Could not patch ${name} ${oldVersion}`);
2875
2883
  }
2884
+ // eslint-disable-next-line no-await-in-loop
2885
+ await editablePkgJson.save();
2886
+ } catch {
2887
+ spinner?.error(`Reverting ${name} to ${oldVersion}`);
2888
+ arb.idealTree = revertToIdealTree;
2876
2889
  }
2890
+ } else {
2891
+ spinner?.error(`Could not patch ${name} ${oldVersion}`);
2877
2892
  }
2878
2893
  }
2879
2894
  }
@@ -2883,161 +2898,687 @@ async function runFix() {
2883
2898
  });
2884
2899
  arb2.idealTree = arb.idealTree;
2885
2900
  await arb2.reify();
2886
- spinner.stop();
2901
+ spinner?.stop();
2887
2902
  }
2888
2903
 
2889
- const {
2890
- DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s
2891
- } = constants;
2892
- const config$t = {
2893
- commandName: 'fix',
2894
- description: 'Fix "fixable" Socket alerts',
2895
- hidden: true,
2896
- flags: {
2897
- ...commonFlags
2898
- },
2899
- help: (command, config) => `
2900
- Usage
2901
- $ ${command}
2902
-
2903
- Options
2904
- ${getFlagListOutput(config.flags, 6)}
2905
- `
2906
- };
2907
- const cmdFix = {
2908
- description: config$t.description,
2909
- hidden: config$t.hidden,
2910
- run: run$t
2911
- };
2912
- async function run$t(argv, importMeta, {
2913
- parentName
2914
- }) {
2915
- const cli = meowOrExit({
2916
- argv,
2917
- config: config$t,
2918
- importMeta,
2919
- parentName
2920
- });
2921
- if (cli.flags['dryRun']) {
2922
- logger.logger.log(DRY_RUN_BAIL_TEXT$s);
2923
- return;
2904
+ async function getAlertsMapFromPnpmLockfile(lockfile, options) {
2905
+ const {
2906
+ spinner
2907
+ } = {
2908
+ __proto__: null,
2909
+ ...options
2910
+ };
2911
+ const depTypes = lockfile_detectDepTypes.detectDepTypes(lockfile);
2912
+ const pkgIds = Object.keys(depTypes);
2913
+ let {
2914
+ length: remaining
2915
+ } = pkgIds;
2916
+ const alertsByPkgId = new Map();
2917
+ if (!remaining) {
2918
+ return alertsByPkgId;
2919
+ }
2920
+ const getText = () => `Looking up data for ${remaining} packages`;
2921
+ spinner?.start(getText());
2922
+ const toAlertsMapOptions = {
2923
+ overrides: lockfile.overrides,
2924
+ ...options
2925
+ };
2926
+ for await (const artifact of shadowNpmInject.batchScan(pkgIds)) {
2927
+ await shadowNpmInject.addArtifactToAlertsMap(artifact, alertsByPkgId, toAlertsMapOptions);
2928
+ remaining -= 1;
2929
+ if (spinner && remaining > 0) {
2930
+ spinner.start();
2931
+ spinner.setText(getText());
2932
+ }
2924
2933
  }
2925
- await runFix();
2934
+ spinner?.stop();
2935
+ return alertsByPkgId;
2926
2936
  }
2927
2937
 
2928
- function objectSome(obj) {
2929
- for (const key in obj) {
2930
- if (obj[key]) {
2931
- return true;
2938
+ function cmdFlagsToString(args) {
2939
+ const result = [];
2940
+ for (let i = 0, {
2941
+ length
2942
+ } = args; i < length; i += 1) {
2943
+ if (args[i].startsWith('--')) {
2944
+ // Check if the next item exists and is NOT another flag.
2945
+ if (i + 1 < length && !args[i + 1].startsWith('--')) {
2946
+ result.push(`${args[i]}=${args[i + 1]}`);
2947
+ i += 1;
2948
+ } else {
2949
+ result.push(args[i]);
2950
+ }
2932
2951
  }
2933
2952
  }
2934
- return false;
2953
+ return result.join(' ');
2935
2954
  }
2936
- function pick(input, keys) {
2937
- const result = {};
2938
- for (const key of keys) {
2939
- result[key] = input[key];
2940
- }
2941
- return result;
2955
+ function cmdPrefixMessage(cmdName, text) {
2956
+ const cmdPrefix = cmdName ? `${cmdName}: ` : '';
2957
+ return `${cmdPrefix}${text}`;
2942
2958
  }
2943
2959
 
2944
- function stringJoinWithSeparateFinalSeparator(list, separator = ' and ') {
2945
- const values = list.filter(Boolean);
2960
+ const {
2961
+ SOCKET_CLI_SENTRY_BUILD,
2962
+ SOCKET_IPC_HANDSHAKE
2963
+ } = constants;
2964
+ function safeNpmInstall(options) {
2946
2965
  const {
2947
- length
2948
- } = values;
2949
- if (!length) {
2950
- return '';
2951
- }
2952
- if (length === 1) {
2953
- return values[0];
2966
+ agentExecPath = shadowNpmPaths.getNpmBinPath(),
2967
+ args = [],
2968
+ ipc,
2969
+ spinner,
2970
+ ...spawnOptions
2971
+ } = {
2972
+ __proto__: null,
2973
+ ...options
2974
+ };
2975
+ const useIpc = objects.isObject(ipc);
2976
+ const useDebug = debug.isDebug();
2977
+ const terminatorPos = args.indexOf('--');
2978
+ const npmArgs = (terminatorPos === -1 ? args : args.slice(0, terminatorPos)).filter(a => !npm.isAuditFlag(a) && !npm.isFundFlag(a) && !npm.isProgressFlag(a));
2979
+ const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
2980
+ const isSilent = !useDebug && !npmArgs.some(npm.isLoglevelFlag);
2981
+ const logLevelArgs = isSilent ? ['--loglevel', 'error'] : [];
2982
+ const spawnPromise = spawn.spawn(
2983
+ // Lazily access constants.execPath.
2984
+ constants.execPath, [
2985
+ // Lazily access constants.nodeHardenFlags.
2986
+ ...constants.nodeHardenFlags,
2987
+ // Lazily access constants.nodeNoWarningsFlags.
2988
+ ...constants.nodeNoWarningsFlags,
2989
+ // Lazily access constants.ENV[SOCKET_CLI_SENTRY_BUILD].
2990
+ ...(constants.ENV[SOCKET_CLI_SENTRY_BUILD] ? ['--require',
2991
+ // Lazily access constants.distInstrumentWithSentryPath.
2992
+ constants.distInstrumentWithSentryPath] : []), '--require',
2993
+ // Lazily access constants.distShadowNpmInjectPath.
2994
+ constants.distShadowNpmInjectPath, agentExecPath, 'install',
2995
+ // Avoid code paths for 'audit' and 'fund'.
2996
+ '--no-audit', '--no-fund',
2997
+ // Add `--no-progress` flag to fix input being swallowed by the spinner
2998
+ // when running the command with recent versions of npm.
2999
+ '--no-progress',
3000
+ // Add '--loglevel=error' if a loglevel flag is not provided and the
3001
+ // SOCKET_CLI_DEBUG environment variable is not truthy.
3002
+ ...logLevelArgs, ...npmArgs, ...otherArgs], {
3003
+ spinner,
3004
+ // Set stdio to include 'ipc'.
3005
+ // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166
3006
+ // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.
3007
+ stdio: useIpc ? [0, 1, 2, 'ipc'] : 'inherit',
3008
+ ...spawnOptions,
3009
+ env: {
3010
+ ...process$1.env,
3011
+ ...spawnOptions.env
3012
+ }
3013
+ });
3014
+ if (useIpc) {
3015
+ spawnPromise.process.send({
3016
+ [SOCKET_IPC_HANDSHAKE]: ipc
3017
+ });
2954
3018
  }
2955
- const finalValue = values.pop();
2956
- return `${values.join(', ')}${separator}${finalValue}`;
3019
+ return spawnPromise;
2957
3020
  }
2958
3021
 
2959
- // Ordered from most severe to least.
2960
- const SEVERITIES_BY_ORDER = ['critical', 'high', 'middle', 'low'];
2961
- function getDesiredSeverities(lowestToInclude) {
2962
- const result = [];
2963
- for (const severity of SEVERITIES_BY_ORDER) {
2964
- result.push(severity);
2965
- if (severity === lowestToInclude) {
2966
- break;
2967
- }
3022
+ const {
3023
+ NPM: NPM$d
3024
+ } = constants;
3025
+ function runAgentInstall(pkgEnvDetails, options) {
3026
+ const {
3027
+ agent,
3028
+ agentExecPath
3029
+ } = pkgEnvDetails;
3030
+ // All package managers support the "install" command.
3031
+ if (agent === NPM$d) {
3032
+ return safeNpmInstall({
3033
+ agentExecPath,
3034
+ ...options
3035
+ });
2968
3036
  }
2969
- return result;
3037
+ const {
3038
+ args = [],
3039
+ spinner,
3040
+ ...spawnOptions
3041
+ } = {
3042
+ __proto__: null,
3043
+ ...options
3044
+ };
3045
+ return spawn.spawn(agentExecPath, ['install', ...args], {
3046
+ spinner,
3047
+ stdio: debug.isDebug() ? 'inherit' : 'ignore',
3048
+ ...spawnOptions,
3049
+ env: {
3050
+ ...process.env,
3051
+ NODE_OPTIONS: cmdFlagsToString([
3052
+ // Lazily access constants.nodeHardenFlags.
3053
+ ...constants.nodeHardenFlags,
3054
+ // Lazily access constants.nodeNoWarningsFlags.
3055
+ ...constants.nodeNoWarningsFlags]),
3056
+ ...spawnOptions.env
3057
+ }
3058
+ });
2970
3059
  }
2971
- function formatSeverityCount(severityCount) {
2972
- const summary = [];
2973
- for (const severity of SEVERITIES_BY_ORDER) {
2974
- if (severityCount[severity]) {
2975
- summary.push(`${severityCount[severity]} ${severity}`);
3060
+
3061
+ const {
3062
+ NPM: NPM$c,
3063
+ OVERRIDES: OVERRIDES$2,
3064
+ PNPM: PNPM$9
3065
+ } = constants;
3066
+ async function pnpmFix(pkgEnvDetails, cwd, options) {
3067
+ const {
3068
+ spinner
3069
+ } = {
3070
+ __proto__: null,
3071
+ ...options
3072
+ };
3073
+ spinner?.start();
3074
+ const lockfile = await lockfileFile.readWantedLockfile(cwd, {
3075
+ ignoreIncompatible: false
3076
+ });
3077
+ if (!lockfile) {
3078
+ spinner?.stop();
3079
+ return;
3080
+ }
3081
+ const alertsMap = await getAlertsMapFromPnpmLockfile(lockfile, {
3082
+ consolidate: true,
3083
+ include: {
3084
+ existing: true,
3085
+ unfixable: false,
3086
+ upgrade: false
2976
3087
  }
3088
+ });
3089
+ const infoByPkg = shadowNpmInject.getCveInfoByAlertsMap(alertsMap);
3090
+ if (!infoByPkg) {
3091
+ spinner?.stop();
3092
+ return;
2977
3093
  }
2978
- return stringJoinWithSeparateFinalSeparator(summary);
2979
- }
2980
- function getSeverityCount(issues, lowestToInclude) {
2981
- const severityCount = pick({
2982
- low: 0,
2983
- middle: 0,
2984
- high: 0,
2985
- critical: 0
2986
- }, getDesiredSeverities(lowestToInclude));
2987
- for (const issue of issues) {
2988
- const {
2989
- value
2990
- } = issue;
2991
- if (!value) {
3094
+ const arb = new shadowNpmInject.SafeArborist({
3095
+ path: cwd,
3096
+ ...shadowNpmInject.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
3097
+ });
3098
+ await arb.loadActual();
3099
+ const editablePkgJson = await packages.readPackageJson(cwd, {
3100
+ editable: true
3101
+ });
3102
+ const {
3103
+ content: pkgJson
3104
+ } = editablePkgJson;
3105
+ for (const {
3106
+ 0: name,
3107
+ 1: infos
3108
+ } of infoByPkg) {
3109
+ const tree = arb.actualTree;
3110
+ const hasUpgrade = !!registry.getManifestData(NPM$c, name);
3111
+ if (hasUpgrade) {
3112
+ spinner?.info(`Skipping ${name}. Socket Optimize package exists.`);
2992
3113
  continue;
2993
3114
  }
2994
- if (severityCount[value.severity] !== undefined) {
2995
- severityCount[value.severity] += 1;
3115
+ const nodes = shadowNpmInject.findPackageNodes(tree, name);
3116
+ const packument = nodes.length && infos.length ?
3117
+ // eslint-disable-next-line no-await-in-loop
3118
+ await packages.fetchPackagePackument(name) : null;
3119
+ if (!packument) {
3120
+ continue;
2996
3121
  }
2997
- }
2998
- return severityCount;
2999
- }
3122
+ for (let i = 0, {
3123
+ length: nodesLength
3124
+ } = nodes; i < nodesLength; i += 1) {
3125
+ const node = nodes[i];
3126
+ for (let j = 0, {
3127
+ length: infosLength
3128
+ } = infos; j < infosLength; j += 1) {
3129
+ const {
3130
+ firstPatchedVersionIdentifier,
3131
+ vulnerableVersionRange
3132
+ } = infos[j];
3133
+ const {
3134
+ version: oldVersion
3135
+ } = node;
3136
+ const availableVersions = Object.keys(packument.versions);
3137
+ // Find the highest non-vulnerable version within the same major range
3138
+ const targetVersion = shadowNpmInject.findBestPatchVersion(node, availableVersions, vulnerableVersionRange);
3139
+ const targetPackument = targetVersion ? packument.versions[targetVersion] : undefined;
3140
+ if (targetPackument) {
3141
+ const oldPnpm = pkgJson[PNPM$9];
3142
+ const oldOverrides = oldPnpm?.[OVERRIDES$2];
3143
+ try {
3144
+ editablePkgJson.update({
3145
+ [PNPM$9]: {
3146
+ ...oldPnpm,
3147
+ [OVERRIDES$2]: {
3148
+ [`${node.name}@${vulnerableVersionRange}`]: `^${targetVersion}`,
3149
+ ...oldOverrides
3150
+ }
3151
+ }
3152
+ });
3153
+ spinner?.info(`Patched ${name} ${oldVersion} -> ${node.version}`);
3000
3154
 
3001
- async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
3002
- const socketSdk = await shadowNpmInject.setupSdk(shadowNpmInject.getPublicToken());
3003
- const result = await handleApiCall(socketSdk.getIssuesByNPMPackage(pkgName, pkgVersion), 'looking up package');
3004
- const scoreResult = await handleApiCall(socketSdk.getScoreByNPMPackage(pkgName, pkgVersion), 'looking up package score');
3005
- if (result.success === false) {
3006
- return handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result);
3007
- }
3008
- if (scoreResult.success === false) {
3009
- return handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult);
3155
+ // eslint-disable-next-line no-await-in-loop
3156
+ await editablePkgJson.save();
3157
+ // eslint-disable-next-line no-await-in-loop
3158
+ await runAgentInstall(pkgEnvDetails, {
3159
+ spinner
3160
+ });
3161
+ } catch {
3162
+ spinner?.error(`Reverting ${name} to ${oldVersion}`);
3163
+ }
3164
+ } else {
3165
+ spinner?.error(`Could not patch ${name} ${oldVersion}`);
3166
+ }
3167
+ }
3168
+ }
3010
3169
  }
3011
- const severityCount = getSeverityCount(result.data, includeAllIssues ? undefined : 'high');
3012
- return {
3013
- data: result.data,
3014
- severityCount,
3015
- score: scoreResult.data
3016
- };
3170
+ spinner?.stop();
3017
3171
  }
3018
3172
 
3019
3173
  const {
3020
- NPM: NPM$c
3021
- } = registryConstants;
3022
- function formatPackageInfo({
3023
- data,
3024
- score,
3025
- severityCount
3026
- }, {
3027
- name,
3028
- outputKind,
3029
- pkgName,
3030
- pkgVersion
3031
- }) {
3032
- if (outputKind === 'json') {
3174
+ BINARY_LOCK_EXT,
3175
+ BUN: BUN$5,
3176
+ LOCK_EXT: LOCK_EXT$1,
3177
+ NPM: NPM$b,
3178
+ NPM_BUGGY_OVERRIDES_PATCHED_VERSION: NPM_BUGGY_OVERRIDES_PATCHED_VERSION$1,
3179
+ PNPM: PNPM$8,
3180
+ VLT: VLT$5,
3181
+ YARN,
3182
+ YARN_BERRY: YARN_BERRY$5,
3183
+ YARN_CLASSIC: YARN_CLASSIC$6
3184
+ } = constants;
3185
+ const AGENTS = [BUN$5, NPM$b, PNPM$8, YARN_BERRY$5, YARN_CLASSIC$6, VLT$5];
3186
+ const binByAgent = {
3187
+ __proto__: null,
3188
+ [BUN$5]: BUN$5,
3189
+ [NPM$b]: NPM$b,
3190
+ [PNPM$8]: PNPM$8,
3191
+ [YARN_BERRY$5]: YARN,
3192
+ [YARN_CLASSIC$6]: YARN,
3193
+ [VLT$5]: VLT$5
3194
+ };
3195
+ async function getAgentExecPath(agent) {
3196
+ const binName = binByAgent[agent];
3197
+ return (await which(binName, {
3198
+ nothrow: true
3199
+ })) ?? binName;
3200
+ }
3201
+ async function getAgentVersion(agentExecPath, cwd) {
3202
+ let result;
3203
+ try {
3204
+ result = semver.coerce(
3205
+ // All package managers support the "--version" flag.
3206
+ (await spawn.spawn(agentExecPath, ['--version'], {
3207
+ cwd
3208
+ })).stdout) ?? undefined;
3209
+ } catch {}
3210
+ return result;
3211
+ }
3212
+
3213
+ // The order of LOCKS properties IS significant as it affects iteration order.
3214
+ const LOCKS = {
3215
+ [`bun${LOCK_EXT$1}`]: BUN$5,
3216
+ [`bun${BINARY_LOCK_EXT}`]: BUN$5,
3217
+ // If both package-lock.json and npm-shrinkwrap.json are present in the root
3218
+ // of a project, npm-shrinkwrap.json will take precedence and package-lock.json
3219
+ // will be ignored.
3220
+ // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson
3221
+ 'npm-shrinkwrap.json': NPM$b,
3222
+ 'package-lock.json': NPM$b,
3223
+ 'pnpm-lock.yaml': PNPM$8,
3224
+ 'pnpm-lock.yml': PNPM$8,
3225
+ [`yarn${LOCK_EXT$1}`]: YARN_CLASSIC$6,
3226
+ 'vlt-lock.json': VLT$5,
3227
+ // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:
3228
+ // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles
3229
+ //
3230
+ // Unlike the other LOCKS keys this key contains a directory AND filename so
3231
+ // it has to be handled differently.
3232
+ 'node_modules/.package-lock.json': NPM$b
3233
+ };
3234
+ const readLockFileByAgent = (() => {
3235
+ function wrapReader(reader) {
3236
+ return async (...args) => {
3237
+ try {
3238
+ return await reader(...args);
3239
+ } catch {}
3240
+ return undefined;
3241
+ };
3242
+ }
3243
+ const binaryReader = wrapReader(shadowNpmInject.readFileBinary);
3244
+ const defaultReader = wrapReader(async lockPath => await shadowNpmInject.readFileUtf8(lockPath));
3245
+ return {
3246
+ [BUN$5]: wrapReader(async (lockPath, agentExecPath) => {
3247
+ const ext = path.extname(lockPath);
3248
+ if (ext === LOCK_EXT$1) {
3249
+ return await defaultReader(lockPath);
3250
+ }
3251
+ if (ext === BINARY_LOCK_EXT) {
3252
+ const lockBuffer = await binaryReader(lockPath);
3253
+ if (lockBuffer) {
3254
+ try {
3255
+ return index_cjs.parse(lockBuffer);
3256
+ } catch {}
3257
+ }
3258
+ // To print a Yarn lockfile to your console without writing it to disk
3259
+ // use `bun bun.lockb`.
3260
+ // https://bun.sh/guides/install/yarnlock
3261
+ return (await spawn.spawn(agentExecPath, [lockPath])).stdout.trim();
3262
+ }
3263
+ return undefined;
3264
+ }),
3265
+ [NPM$b]: defaultReader,
3266
+ [PNPM$8]: defaultReader,
3267
+ [VLT$5]: defaultReader,
3268
+ [YARN_BERRY$5]: defaultReader,
3269
+ [YARN_CLASSIC$6]: defaultReader
3270
+ };
3271
+ })();
3272
+ async function detectPackageEnvironment({
3273
+ cwd = process$1.cwd(),
3274
+ onUnknown
3275
+ } = {}) {
3276
+ let lockPath = await shadowNpmInject.findUp(Object.keys(LOCKS), {
3277
+ cwd
3278
+ });
3279
+ let lockName = lockPath ? path.basename(lockPath) : undefined;
3280
+ const isHiddenLockFile = lockName === '.package-lock.json';
3281
+ const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await shadowNpmInject.findUp('package.json', {
3282
+ cwd
3283
+ });
3284
+ const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
3285
+ const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
3286
+ editable: true
3287
+ }) : undefined;
3288
+ const pkgJson = editablePkgJson?.content;
3289
+ // Read Corepack `packageManager` field in package.json:
3290
+ // https://nodejs.org/api/packages.html#packagemanager
3291
+ const pkgManager = strings.isNonEmptyString(pkgJson?.packageManager) ? pkgJson.packageManager : undefined;
3292
+ let agent;
3293
+ let agentVersion;
3294
+ if (pkgManager) {
3295
+ const atSignIndex = pkgManager.lastIndexOf('@');
3296
+ if (atSignIndex !== -1) {
3297
+ const name = pkgManager.slice(0, atSignIndex);
3298
+ const version = pkgManager.slice(atSignIndex + 1);
3299
+ if (version && AGENTS.includes(name)) {
3300
+ agent = name;
3301
+ agentVersion = semver.coerce(version) ?? undefined;
3302
+ }
3303
+ }
3304
+ }
3305
+ if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
3306
+ agent = LOCKS[lockName];
3307
+ }
3308
+ if (agent === undefined) {
3309
+ agent = NPM$b;
3310
+ onUnknown?.(pkgManager);
3311
+ }
3312
+ const agentExecPath = await getAgentExecPath(agent);
3313
+ const npmExecPath = agent === NPM$b ? agentExecPath : await getAgentExecPath(NPM$b);
3314
+ if (agentVersion === undefined) {
3315
+ agentVersion = await getAgentVersion(agentExecPath, cwd);
3316
+ }
3317
+ if (agent === YARN_CLASSIC$6 && (agentVersion?.major ?? 0) > 1) {
3318
+ agent = YARN_BERRY$5;
3319
+ }
3320
+ const targets = {
3321
+ browser: false,
3322
+ node: true
3323
+ };
3324
+ let lockSrc;
3325
+ // Lazily access constants.maintainedNodeVersions.
3326
+ let minimumNodeVersion = constants.maintainedNodeVersions.last;
3327
+ if (pkgJson) {
3328
+ const browserField = pkgJson.browser;
3329
+ if (strings.isNonEmptyString(browserField) || objects.isObjectObject(browserField)) {
3330
+ targets.browser = true;
3331
+ }
3332
+ const nodeRange = pkgJson.engines?.['node'];
3333
+ if (strings.isNonEmptyString(nodeRange)) {
3334
+ const coerced = semver.coerce(nodeRange);
3335
+ if (coerced && semver.lt(coerced, minimumNodeVersion)) {
3336
+ minimumNodeVersion = coerced.version;
3337
+ }
3338
+ }
3339
+ const browserslistQuery = pkgJson['browserslist'];
3340
+ if (Array.isArray(browserslistQuery)) {
3341
+ const browserslistTargets = browserslist(browserslistQuery).map(s => s.toLowerCase()).sort(sorts.naturalCompare);
3342
+ const browserslistNodeTargets = browserslistTargets.filter(v => v.startsWith('node ')).map(v => v.slice(5 /*'node '.length*/));
3343
+ if (!targets.browser && browserslistTargets.length) {
3344
+ targets.browser = browserslistTargets.length !== browserslistNodeTargets.length;
3345
+ }
3346
+ if (browserslistNodeTargets.length) {
3347
+ const coerced = semver.coerce(browserslistNodeTargets[0]);
3348
+ if (coerced && semver.lt(coerced, minimumNodeVersion)) {
3349
+ minimumNodeVersion = coerced.version;
3350
+ }
3351
+ }
3352
+ }
3353
+ // Lazily access constants.maintainedNodeVersions.
3354
+ targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
3355
+ lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
3356
+ } else {
3357
+ lockName = undefined;
3358
+ lockPath = undefined;
3359
+ }
3360
+ const pkgSupported = targets.browser || targets.node;
3361
+ const npmBuggyOverrides = agent === NPM$b && !!agentVersion && semver.lt(agentVersion, NPM_BUGGY_OVERRIDES_PATCHED_VERSION$1);
3362
+ return {
3363
+ agent,
3364
+ agentExecPath,
3365
+ agentVersion,
3366
+ lockName,
3367
+ lockPath,
3368
+ lockSrc,
3369
+ minimumNodeVersion,
3370
+ npmExecPath,
3371
+ pkgJson: editablePkgJson,
3372
+ pkgPath,
3373
+ pkgSupported,
3374
+ features: {
3375
+ npmBuggyOverrides
3376
+ },
3377
+ targets
3378
+ };
3379
+ }
3380
+ async function detectAndValidatePackageEnvironment(cwd, options) {
3381
+ const {
3382
+ cmdName = '',
3383
+ logger,
3384
+ prod
3385
+ } = {
3386
+ __proto__: null,
3387
+ ...options
3388
+ };
3389
+ const details = await detectPackageEnvironment({
3390
+ cwd,
3391
+ onUnknown(pkgManager) {
3392
+ logger?.warn(cmdPrefixMessage(cmdName, `Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`));
3393
+ }
3394
+ });
3395
+ if (!details.pkgSupported) {
3396
+ logger?.fail(cmdPrefixMessage(cmdName, 'No supported Node or browser range detected'));
3397
+ return;
3398
+ }
3399
+ if (details.agent === VLT$5) {
3400
+ logger?.fail(cmdPrefixMessage(cmdName, `${details.agent} does not support overrides. Soon, though ⚡`));
3401
+ return;
3402
+ }
3403
+ const lockName = details.lockName ?? 'lock file';
3404
+ if (details.lockName === undefined || details.lockSrc === undefined) {
3405
+ logger?.fail(cmdPrefixMessage(cmdName, `No ${lockName} found`));
3406
+ return;
3407
+ }
3408
+ if (details.lockSrc.trim() === '') {
3409
+ logger?.fail(cmdPrefixMessage(cmdName, `${lockName} is empty`));
3410
+ return;
3411
+ }
3412
+ if (details.pkgPath === undefined) {
3413
+ logger?.fail(cmdPrefixMessage(cmdName, 'No package.json found'));
3414
+ return;
3415
+ }
3416
+ if (prod && (details.agent === BUN$5 || details.agent === YARN_BERRY$5)) {
3417
+ logger?.fail(cmdPrefixMessage(cmdName, `--prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.version}` : ''}`));
3418
+ return;
3419
+ }
3420
+ if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
3421
+ logger?.warn(cmdPrefixMessage(cmdName, `Package ${lockName} found at ${details.lockPath}`));
3422
+ }
3423
+ return details;
3424
+ }
3425
+
3426
+ const {
3427
+ NPM: NPM$a,
3428
+ PNPM: PNPM$7
3429
+ } = constants;
3430
+ const CMD_NAME$1 = 'socket fix';
3431
+ async function runFix() {
3432
+ // Lazily access constants.spinner.
3433
+ const {
3434
+ spinner
3435
+ } = constants;
3436
+ spinner.start();
3437
+ const cwd = process.cwd();
3438
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
3439
+ cmdName: CMD_NAME$1,
3440
+ logger: logger.logger
3441
+ });
3442
+ if (!pkgEnvDetails) {
3443
+ spinner.stop();
3444
+ return;
3445
+ }
3446
+ switch (pkgEnvDetails.agent) {
3447
+ case NPM$a:
3448
+ {
3449
+ await npmFix(pkgEnvDetails, cwd);
3450
+ break;
3451
+ }
3452
+ case PNPM$7:
3453
+ {
3454
+ await pnpmFix(pkgEnvDetails, cwd);
3455
+ break;
3456
+ }
3457
+ }
3458
+ spinner.successAndStop('Socket.dev fix successful');
3459
+ }
3460
+
3461
+ const {
3462
+ DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$s
3463
+ } = constants;
3464
+ const config$t = {
3465
+ commandName: 'fix',
3466
+ description: 'Fix "fixable" Socket alerts',
3467
+ hidden: true,
3468
+ flags: {
3469
+ ...commonFlags
3470
+ },
3471
+ help: (command, config) => `
3472
+ Usage
3473
+ $ ${command}
3474
+
3475
+ Options
3476
+ ${getFlagListOutput(config.flags, 6)}
3477
+ `
3478
+ };
3479
+ const cmdFix = {
3480
+ description: config$t.description,
3481
+ hidden: config$t.hidden,
3482
+ run: run$t
3483
+ };
3484
+ async function run$t(argv, importMeta, {
3485
+ parentName
3486
+ }) {
3487
+ const cli = meowOrExit({
3488
+ argv,
3489
+ config: config$t,
3490
+ importMeta,
3491
+ parentName
3492
+ });
3493
+ if (cli.flags['dryRun']) {
3494
+ logger.logger.log(DRY_RUN_BAIL_TEXT$s);
3495
+ return;
3496
+ }
3497
+ await runFix();
3498
+ }
3499
+
3500
+ async function fetchPackageInfo(pkgName, pkgVersion, includeAllIssues) {
3501
+ const socketSdk = await shadowNpmInject.setupSdk(shadowNpmInject.getPublicToken());
3502
+ const result = await handleApiCall(socketSdk.getIssuesByNPMPackage(pkgName, pkgVersion), 'looking up package');
3503
+ const scoreResult = await handleApiCall(socketSdk.getScoreByNPMPackage(pkgName, pkgVersion), 'looking up package score');
3504
+ if (result.success === false) {
3505
+ return handleUnsuccessfulApiResponse('getIssuesByNPMPackage', result);
3506
+ }
3507
+ if (scoreResult.success === false) {
3508
+ return handleUnsuccessfulApiResponse('getScoreByNPMPackage', scoreResult);
3509
+ }
3510
+ const severityCount = shadowNpmInject.getSeverityCount(result.data, includeAllIssues ? undefined : 'high');
3511
+ return {
3512
+ data: result.data,
3513
+ severityCount,
3514
+ score: scoreResult.data
3515
+ };
3516
+ }
3517
+
3518
+ const {
3519
+ NPM: NPM$9
3520
+ } = registryConstants;
3521
+ function formatScore(score) {
3522
+ if (score > 80) {
3523
+ return colors.green(`${score}`);
3524
+ } else if (score < 80 && score > 60) {
3525
+ return colors.yellow(`${score}`);
3526
+ }
3527
+ return colors.red(`${score}`);
3528
+ }
3529
+ function logPackageIssuesDetails(packageData, outputMarkdown) {
3530
+ const issueDetails = packageData.filter(d => d.value?.severity === shadowNpmInject.SEVERITY.critical || d.value?.severity === shadowNpmInject.SEVERITY.high);
3531
+ const uniqueIssueDetails = issueDetails.reduce((acc, issue) => {
3532
+ const {
3533
+ type
3534
+ } = issue;
3535
+ if (type) {
3536
+ const details = acc.get(type);
3537
+ if (details) {
3538
+ details.count += 1;
3539
+ } else {
3540
+ acc.set(type, {
3541
+ label: issue.value?.label ?? '',
3542
+ count: 1
3543
+ });
3544
+ }
3545
+ }
3546
+ return acc;
3547
+ }, new Map());
3548
+ const format = new shadowNpmInject.ColorOrMarkdown(outputMarkdown);
3549
+ for (const [type, details] of uniqueIssueDetails.entries()) {
3550
+ const issueWithLink = format.hyperlink(details.label, shadowNpmInject.getSocketDevAlertUrl(type), {
3551
+ fallbackToUrl: true
3552
+ });
3553
+ if (details.count === 1) {
3554
+ logger.logger.log(`- ${issueWithLink}`);
3555
+ } else {
3556
+ logger.logger.log(`- ${issueWithLink}: ${details.count}`);
3557
+ }
3558
+ }
3559
+ }
3560
+ function logPackageInfo({
3561
+ data,
3562
+ score,
3563
+ severityCount
3564
+ }, {
3565
+ name,
3566
+ outputKind,
3567
+ pkgName,
3568
+ pkgVersion
3569
+ }) {
3570
+ if (outputKind === 'json') {
3033
3571
  logger.logger.log(JSON.stringify(data, undefined, 2));
3034
3572
  return;
3035
3573
  }
3036
3574
  if (outputKind === 'markdown') {
3037
- logger.logger.log(`\n# Package report for ${pkgName}\n`);
3038
- logger.logger.log('Package report card:\n');
3575
+ logger.logger.log(commonTags.stripIndents`
3576
+ # Package report for ${pkgName}
3577
+
3578
+ Package report card:
3579
+ `);
3039
3580
  } else {
3040
- logger.logger.log(`\nPackage report card for ${pkgName}:\n`);
3581
+ logger.logger.log(`Package report card for ${pkgName}:`);
3041
3582
  }
3042
3583
  const scoreResult = {
3043
3584
  'Supply Chain Risk': Math.floor(score.supplyChainRisk.score * 100),
@@ -3046,72 +3587,35 @@ function formatPackageInfo({
3046
3587
  Vulnerabilities: Math.floor(score.vulnerability.score * 100),
3047
3588
  License: Math.floor(score.license.score * 100)
3048
3589
  };
3590
+ logger.logger.log('\n');
3049
3591
  Object.entries(scoreResult).map(score => logger.logger.log(`- ${score[0]}: ${formatScore(score[1])}`));
3050
3592
  logger.logger.log('\n');
3051
- if (objectSome(severityCount)) {
3593
+ if (objects.hasKeys(severityCount)) {
3052
3594
  if (outputKind === 'markdown') {
3053
3595
  logger.logger.log('# Issues\n');
3054
3596
  }
3055
- logger.logger.log(`Package has these issues: ${formatSeverityCount(severityCount)}\n`);
3056
- formatPackageIssuesDetails(data, outputKind === 'markdown');
3597
+ logger.logger.log(`Package has these issues: ${shadowNpmInject.formatSeverityCount(severityCount)}\n`);
3598
+ logPackageIssuesDetails(data, outputKind === 'markdown');
3057
3599
  } else {
3058
3600
  logger.logger.log('Package has no issues');
3059
3601
  }
3060
3602
  const format = new shadowNpmInject.ColorOrMarkdown(outputKind === 'markdown');
3061
- const url = shadowNpmInject.getSocketDevPackageOverviewUrl(NPM$c, pkgName, pkgVersion);
3062
- logger.logger.log('\n');
3063
- if (pkgVersion === 'latest') {
3064
- logger.logger.log(`Detailed info on socket.dev: ${format.hyperlink(`${pkgName}`, url, {
3065
- fallbackToUrl: true
3066
- })}`);
3067
- } else {
3068
- logger.logger.log(`Detailed info on socket.dev: ${format.hyperlink(`${pkgName} v${pkgVersion}`, url, {
3069
- fallbackToUrl: true
3070
- })}`);
3071
- }
3072
- if (outputKind !== 'markdown') {
3073
- logger.logger.log(colors.dim(`\nOr rerun ${colors.italic(name)} using the ${colors.italic('--json')} flag to get full JSON output`));
3074
- } else {
3075
- logger.logger.log('');
3076
- }
3077
- }
3078
- function formatPackageIssuesDetails(packageData, outputMarkdown) {
3079
- const issueDetails = packageData.filter(d => d.value?.severity === 'high' || d.value?.severity === 'critical');
3080
- const uniqueIssues = issueDetails.reduce((acc, issue) => {
3081
- const {
3082
- type
3083
- } = issue;
3084
- if (type) {
3085
- if (acc[type] === undefined) {
3086
- acc[type] = {
3087
- label: issue.value?.label,
3088
- count: 1
3089
- };
3090
- } else {
3091
- acc[type].count += 1;
3092
- }
3093
- }
3094
- return acc;
3095
- }, {});
3096
- const format = new shadowNpmInject.ColorOrMarkdown(outputMarkdown);
3097
- for (const issue of Object.keys(uniqueIssues)) {
3098
- const issueWithLink = format.hyperlink(`${uniqueIssues[issue]?.label}`, shadowNpmInject.getSocketDevAlertUrl(issue), {
3603
+ const url = shadowNpmInject.getSocketDevPackageOverviewUrl(NPM$9, pkgName, pkgVersion);
3604
+ logger.logger.log('\n');
3605
+ if (pkgVersion === 'latest') {
3606
+ logger.logger.log(`Detailed info on socket.dev: ${format.hyperlink(`${pkgName}`, url, {
3099
3607
  fallbackToUrl: true
3100
- });
3101
- if (uniqueIssues[issue]?.count === 1) {
3102
- logger.logger.log(`- ${issueWithLink}`);
3103
- } else {
3104
- logger.logger.log(`- ${issueWithLink}: ${uniqueIssues[issue]?.count}`);
3105
- }
3608
+ })}`);
3609
+ } else {
3610
+ logger.logger.log(`Detailed info on socket.dev: ${format.hyperlink(`${pkgName} v${pkgVersion}`, url, {
3611
+ fallbackToUrl: true
3612
+ })}`);
3106
3613
  }
3107
- }
3108
- function formatScore(score) {
3109
- if (score > 80) {
3110
- return colors.green(`${score}`);
3111
- } else if (score < 80 && score > 60) {
3112
- return colors.yellow(`${score}`);
3614
+ if (outputKind !== 'markdown') {
3615
+ logger.logger.log(colors.dim(`\nOr rerun ${colors.italic(name)} using the ${colors.italic('--json')} flag to get full JSON output`));
3616
+ } else {
3617
+ logger.logger.log('');
3113
3618
  }
3114
- return colors.red(`${score}`);
3115
3619
  }
3116
3620
 
3117
3621
  async function getPackageInfo({
@@ -3130,13 +3634,13 @@ async function getPackageInfo({
3130
3634
  const packageData = await fetchPackageInfo(pkgName, pkgVersion, includeAllIssues);
3131
3635
  spinner.successAndStop('Data fetched');
3132
3636
  if (packageData) {
3133
- formatPackageInfo(packageData, {
3637
+ logPackageInfo(packageData, {
3134
3638
  name: commandName,
3135
3639
  outputKind,
3136
3640
  pkgName,
3137
3641
  pkgVersion
3138
3642
  });
3139
- if (strict && objectSome(packageData.severityCount)) {
3643
+ if (strict && objects.hasKeys(packageData.severityCount)) {
3140
3644
  // Let NodeJS exit gracefully but with exit(1)
3141
3645
  process$1.exitCode = 1;
3142
3646
  }
@@ -3338,8 +3842,8 @@ async function run$r(argv, importMeta, {
3338
3842
  importMeta,
3339
3843
  parentName
3340
3844
  });
3341
- let apiBaseUrl = cli.flags['apiBaseUrl'];
3342
- let apiProxy = cli.flags['apiProxy'];
3845
+ const apiBaseUrl = cli.flags['apiBaseUrl'];
3846
+ const apiProxy = cli.flags['apiProxy'];
3343
3847
  if (cli.flags['dryRun']) {
3344
3848
  logger.logger.log(DRY_RUN_BAIL_TEXT$q);
3345
3849
  return;
@@ -3808,6 +4312,9 @@ const config$o = {
3808
4312
 
3809
4313
  Support is beta. Please report issues or give us feedback on what's missing.
3810
4314
 
4315
+ This is only for SBT. If your Scala setup uses gradle, please see the help
4316
+ sections for \`socket manifest gradle\` or \`socket cdxgen\`.
4317
+
3811
4318
  Examples
3812
4319
 
3813
4320
  $ ${command} ./build.sbt
@@ -4181,21 +4688,21 @@ async function run$l(argv, importMeta, {
4181
4688
  }
4182
4689
 
4183
4690
  const {
4184
- NPM: NPM$b
4691
+ NPM: NPM$8
4185
4692
  } = constants;
4186
4693
  async function wrapNpm(argv) {
4187
4694
  // Lazily access constants.distShadowNpmBinPath.
4188
4695
  const shadowBin = require(constants.distShadowNpmBinPath);
4189
- await shadowBin(NPM$b, argv);
4696
+ await shadowBin(NPM$8, argv);
4190
4697
  }
4191
4698
 
4192
4699
  const {
4193
4700
  DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$k,
4194
- NPM: NPM$a
4701
+ NPM: NPM$7
4195
4702
  } = constants;
4196
4703
  const config$k = {
4197
4704
  commandName: 'npm',
4198
- description: `${NPM$a} wrapper functionality`,
4705
+ description: `${NPM$7} wrapper functionality`,
4199
4706
  hidden: false,
4200
4707
  flags: {},
4201
4708
  help: (command, _config) => `
@@ -4309,273 +4816,20 @@ async function run$i(argv, importMeta, {
4309
4816
  }
4310
4817
 
4311
4818
  const {
4312
- BUN: BUN$6,
4313
- NPM: NPM$9,
4314
- PNPM: PNPM$7,
4315
- VLT: VLT$6,
4316
- YARN_BERRY: YARN_BERRY$6,
4317
- YARN_CLASSIC: YARN_CLASSIC$6
4318
- } = constants;
4319
- function matchHumanStdout(stdout, name) {
4320
- return stdout.includes(` ${name}@`);
4321
- }
4322
- function matchQueryStdout(stdout, name) {
4323
- return stdout.includes(`"${name}"`);
4324
- }
4325
- const depsIncludesByAgent = new Map([[BUN$6, matchHumanStdout], [NPM$9, matchQueryStdout], [PNPM$7, matchQueryStdout], [VLT$6, matchQueryStdout], [YARN_BERRY$6, matchHumanStdout], [YARN_CLASSIC$6, matchHumanStdout]]);
4326
-
4327
- const {
4328
- BINARY_LOCK_EXT,
4329
- BUN: BUN$5,
4330
- LOCK_EXT: LOCK_EXT$1,
4331
- NPM: NPM$8,
4819
+ BUN: BUN$4,
4820
+ NPM: NPM$6,
4332
4821
  PNPM: PNPM$6,
4333
- VLT: VLT$5,
4334
- YARN,
4335
- YARN_BERRY: YARN_BERRY$5,
4822
+ VLT: VLT$4,
4823
+ YARN_BERRY: YARN_BERRY$4,
4336
4824
  YARN_CLASSIC: YARN_CLASSIC$5
4337
4825
  } = constants;
4338
- const AGENTS = [BUN$5, NPM$8, PNPM$6, YARN_BERRY$5, YARN_CLASSIC$5, VLT$5];
4339
- const binByAgent = {
4340
- __proto__: null,
4341
- [BUN$5]: BUN$5,
4342
- [NPM$8]: NPM$8,
4343
- [PNPM$6]: PNPM$6,
4344
- [YARN_BERRY$5]: YARN,
4345
- [YARN_CLASSIC$5]: YARN,
4346
- [VLT$5]: VLT$5
4347
- };
4348
- async function getAgentExecPath(agent) {
4349
- const binName = binByAgent[agent];
4350
- return (await which(binName, {
4351
- nothrow: true
4352
- })) ?? binName;
4353
- }
4354
- async function getAgentVersion(agentExecPath, cwd) {
4355
- let result;
4356
- try {
4357
- result = semver.coerce(
4358
- // All package managers support the "--version" flag.
4359
- (await spawn.spawn(agentExecPath, ['--version'], {
4360
- cwd
4361
- })).stdout) ?? undefined;
4362
- } catch {}
4363
- return result;
4364
- }
4365
-
4366
- // The order of LOCKS properties IS significant as it affects iteration order.
4367
- const LOCKS = {
4368
- [`bun${LOCK_EXT$1}`]: BUN$5,
4369
- [`bun${BINARY_LOCK_EXT}`]: BUN$5,
4370
- // If both package-lock.json and npm-shrinkwrap.json are present in the root
4371
- // of a project, npm-shrinkwrap.json will take precedence and package-lock.json
4372
- // will be ignored.
4373
- // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#package-lockjson-vs-npm-shrinkwrapjson
4374
- 'npm-shrinkwrap.json': NPM$8,
4375
- 'package-lock.json': NPM$8,
4376
- 'pnpm-lock.yaml': PNPM$6,
4377
- 'pnpm-lock.yml': PNPM$6,
4378
- [`yarn${LOCK_EXT$1}`]: YARN_CLASSIC$5,
4379
- 'vlt-lock.json': VLT$5,
4380
- // Lastly, look for a hidden lock file which is present if .npmrc has package-lock=false:
4381
- // https://docs.npmjs.com/cli/v10/configuring-npm/package-lock-json#hidden-lockfiles
4382
- //
4383
- // Unlike the other LOCKS keys this key contains a directory AND filename so
4384
- // it has to be handled differently.
4385
- 'node_modules/.package-lock.json': NPM$8
4386
- };
4387
- const readLockFileByAgent = (() => {
4388
- function wrapReader(reader) {
4389
- return async (...args) => {
4390
- try {
4391
- return await reader(...args);
4392
- } catch {}
4393
- return undefined;
4394
- };
4395
- }
4396
- const binaryReader = wrapReader(shadowNpmInject.readFileBinary);
4397
- const defaultReader = wrapReader(async lockPath => await shadowNpmInject.readFileUtf8(lockPath));
4398
- return {
4399
- [BUN$5]: wrapReader(async (lockPath, agentExecPath) => {
4400
- const ext = path.extname(lockPath);
4401
- if (ext === LOCK_EXT$1) {
4402
- return await defaultReader(lockPath);
4403
- }
4404
- if (ext === BINARY_LOCK_EXT) {
4405
- const lockBuffer = await binaryReader(lockPath);
4406
- if (lockBuffer) {
4407
- try {
4408
- return index_cjs.parse(lockBuffer);
4409
- } catch {}
4410
- }
4411
- // To print a Yarn lockfile to your console without writing it to disk
4412
- // use `bun bun.lockb`.
4413
- // https://bun.sh/guides/install/yarnlock
4414
- return (await spawn.spawn(agentExecPath, [lockPath])).stdout.trim();
4415
- }
4416
- return undefined;
4417
- }),
4418
- [NPM$8]: defaultReader,
4419
- [PNPM$6]: defaultReader,
4420
- [VLT$5]: defaultReader,
4421
- [YARN_BERRY$5]: defaultReader,
4422
- [YARN_CLASSIC$5]: defaultReader
4423
- };
4424
- })();
4425
- async function detectPackageEnvironment({
4426
- cwd = process$1.cwd(),
4427
- onUnknown
4428
- } = {}) {
4429
- let lockPath = await shadowNpmInject.findUp(Object.keys(LOCKS), {
4430
- cwd
4431
- });
4432
- let lockName = lockPath ? path.basename(lockPath) : undefined;
4433
- const isHiddenLockFile = lockName === '.package-lock.json';
4434
- const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../package.json`) : await shadowNpmInject.findUp('package.json', {
4435
- cwd
4436
- });
4437
- const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
4438
- const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
4439
- editable: true
4440
- }) : undefined;
4441
- const pkgJson = editablePkgJson?.content;
4442
- // Read Corepack `packageManager` field in package.json:
4443
- // https://nodejs.org/api/packages.html#packagemanager
4444
- const pkgManager = strings.isNonEmptyString(pkgJson?.packageManager) ? pkgJson.packageManager : undefined;
4445
- let agent;
4446
- let agentVersion;
4447
- if (pkgManager) {
4448
- const atSignIndex = pkgManager.lastIndexOf('@');
4449
- if (atSignIndex !== -1) {
4450
- const name = pkgManager.slice(0, atSignIndex);
4451
- const version = pkgManager.slice(atSignIndex + 1);
4452
- if (version && AGENTS.includes(name)) {
4453
- agent = name;
4454
- agentVersion = semver.coerce(version) ?? undefined;
4455
- }
4456
- }
4457
- }
4458
- if (agent === undefined && !isHiddenLockFile && typeof pkgJsonPath === 'string' && typeof lockName === 'string') {
4459
- agent = LOCKS[lockName];
4460
- }
4461
- if (agent === undefined) {
4462
- agent = NPM$8;
4463
- onUnknown?.(pkgManager);
4464
- }
4465
- const agentExecPath = await getAgentExecPath(agent);
4466
- const npmExecPath = agent === NPM$8 ? agentExecPath : await getAgentExecPath(NPM$8);
4467
- if (agentVersion === undefined) {
4468
- agentVersion = await getAgentVersion(agentExecPath, cwd);
4469
- }
4470
- if (agent === YARN_CLASSIC$5 && (agentVersion?.major ?? 0) > 1) {
4471
- agent = YARN_BERRY$5;
4472
- }
4473
- const targets = {
4474
- browser: false,
4475
- node: true
4476
- };
4477
- let lockSrc;
4478
- // Lazily access constants.maintainedNodeVersions.
4479
- let minimumNodeVersion = constants.maintainedNodeVersions.previous;
4480
- if (pkgJson) {
4481
- const browserField = pkgJson.browser;
4482
- if (strings.isNonEmptyString(browserField) || objects.isObjectObject(browserField)) {
4483
- targets.browser = true;
4484
- }
4485
- const nodeRange = pkgJson.engines?.['node'];
4486
- if (strings.isNonEmptyString(nodeRange)) {
4487
- const coerced = semver.coerce(nodeRange);
4488
- if (coerced && semver.lt(coerced, minimumNodeVersion)) {
4489
- minimumNodeVersion = coerced.version;
4490
- }
4491
- }
4492
- const browserslistQuery = pkgJson['browserslist'];
4493
- if (Array.isArray(browserslistQuery)) {
4494
- const browserslistTargets = browserslist(browserslistQuery).map(s => s.toLowerCase()).sort(sorts.naturalCompare);
4495
- const browserslistNodeTargets = browserslistTargets.filter(v => v.startsWith('node ')).map(v => v.slice(5 /*'node '.length*/));
4496
- if (!targets.browser && browserslistTargets.length) {
4497
- targets.browser = browserslistTargets.length !== browserslistNodeTargets.length;
4498
- }
4499
- if (browserslistNodeTargets.length) {
4500
- const coerced = semver.coerce(browserslistNodeTargets[0]);
4501
- if (coerced && semver.lt(coerced, minimumNodeVersion)) {
4502
- minimumNodeVersion = coerced.version;
4503
- }
4504
- }
4505
- }
4506
- // Lazily access constants.maintainedNodeVersions.
4507
- targets.node = constants.maintainedNodeVersions.some(v => semver.satisfies(v, `>=${minimumNodeVersion}`));
4508
- lockSrc = typeof lockPath === 'string' ? await readLockFileByAgent[agent](lockPath, agentExecPath) : undefined;
4509
- } else {
4510
- lockName = undefined;
4511
- lockPath = undefined;
4512
- }
4513
- return {
4514
- agent,
4515
- agentExecPath,
4516
- agentVersion,
4517
- lockName,
4518
- lockPath,
4519
- lockSrc,
4520
- minimumNodeVersion,
4521
- npmExecPath,
4522
- pkgJson: editablePkgJson,
4523
- pkgPath,
4524
- supported: targets.browser || targets.node,
4525
- targets
4526
- };
4826
+ function matchLsCmdViewHumanStdout(stdout, name) {
4827
+ return stdout.includes(` ${name}@`);
4527
4828
  }
4528
-
4529
- const {
4530
- BUN: BUN$4,
4531
- VLT: VLT$4,
4532
- YARN_BERRY: YARN_BERRY$4
4533
- } = constants;
4534
- const COMMAND_TITLE$2 = 'Socket Optimize';
4535
- async function detectAndValidatePackageEnvironment(cwd, options) {
4536
- const {
4537
- logger,
4538
- prod
4539
- } = {
4540
- __proto__: null,
4541
- ...options
4542
- };
4543
- const details = await detectPackageEnvironment({
4544
- cwd,
4545
- onUnknown(pkgManager) {
4546
- logger?.warn(`${COMMAND_TITLE$2}: Unknown package manager${pkgManager ? ` ${pkgManager}` : ''}, defaulting to npm`);
4547
- }
4548
- });
4549
- if (!details.supported) {
4550
- logger?.fail(`${COMMAND_TITLE$2}: No supported Node or browser range detected`);
4551
- return;
4552
- }
4553
- if (details.agent === VLT$4) {
4554
- logger?.fail(`${COMMAND_TITLE$2}: ${details.agent} does not support overrides. Soon, though ⚡`);
4555
- return;
4556
- }
4557
- const lockName = details.lockName ?? 'lock file';
4558
- if (details.lockName === undefined || details.lockSrc === undefined) {
4559
- logger?.fail(`${COMMAND_TITLE$2}: No ${lockName} found`);
4560
- return;
4561
- }
4562
- if (details.lockSrc.trim() === '') {
4563
- logger?.fail(`${COMMAND_TITLE$2}: ${lockName} is empty`);
4564
- return;
4565
- }
4566
- if (details.pkgPath === undefined) {
4567
- logger?.fail(`${COMMAND_TITLE$2}: No package.json found`);
4568
- return;
4569
- }
4570
- if (prod && (details.agent === BUN$4 || details.agent === YARN_BERRY$4)) {
4571
- logger?.fail(`${COMMAND_TITLE$2}: --prod not supported for ${details.agent}${details.agentVersion ? `@${details.agentVersion.toString()}` : ''}`);
4572
- return;
4573
- }
4574
- if (details.lockPath && path.relative(cwd, details.lockPath).startsWith('.')) {
4575
- logger?.warn(`${COMMAND_TITLE$2}: Package ${lockName} found at ${details.lockPath}`);
4576
- }
4577
- return details;
4829
+ function matchQueryCmdStdout(stdout, name) {
4830
+ return stdout.includes(`"${name}"`);
4578
4831
  }
4832
+ const depsIncludesByAgent = new Map([[BUN$4, matchLsCmdViewHumanStdout], [NPM$6, matchQueryCmdStdout], [PNPM$6, matchQueryCmdStdout], [VLT$4, matchQueryCmdStdout], [YARN_BERRY$4, matchLsCmdViewHumanStdout], [YARN_CLASSIC$5, matchLsCmdViewHumanStdout]]);
4579
4833
 
4580
4834
  function getDependencyEntries(pkgJson) {
4581
4835
  const {
@@ -4603,7 +4857,7 @@ function getDependencyEntries(pkgJson) {
4603
4857
 
4604
4858
  const {
4605
4859
  BUN: BUN$3,
4606
- NPM: NPM$7,
4860
+ NPM: NPM$5,
4607
4861
  OVERRIDES: OVERRIDES$1,
4608
4862
  PNPM: PNPM$5,
4609
4863
  RESOLUTIONS: RESOLUTIONS$1,
@@ -4624,7 +4878,7 @@ function getOverridesDataBun(pkgJson) {
4624
4878
  function getOverridesDataNpm(pkgJson) {
4625
4879
  const overrides = pkgJson?.[OVERRIDES$1] ?? {};
4626
4880
  return {
4627
- type: NPM$7,
4881
+ type: NPM$5,
4628
4882
  overrides
4629
4883
  };
4630
4884
  }
@@ -4665,7 +4919,7 @@ function getOverridesDataClassic(pkgJson) {
4665
4919
  overrides
4666
4920
  };
4667
4921
  }
4668
- const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$7, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4922
+ const overridesDataByAgent = new Map([[BUN$3, getOverridesDataBun], [NPM$5, getOverridesDataNpm], [PNPM$5, getOverridesDataPnpm], [VLT$3, getOverridesDataVlt], [YARN_BERRY$3, getOverridesDataYarn], [YARN_CLASSIC$4, getOverridesDataClassic]]);
4669
4923
 
4670
4924
  const {
4671
4925
  PNPM: PNPM$4
@@ -4713,26 +4967,26 @@ function workspacePatternToGlobPattern(workspace) {
4713
4967
  const {
4714
4968
  BUN: BUN$2,
4715
4969
  LOCK_EXT,
4716
- NPM: NPM$6,
4970
+ NPM: NPM$4,
4717
4971
  PNPM: PNPM$3,
4718
4972
  VLT: VLT$2,
4719
4973
  YARN_BERRY: YARN_BERRY$2,
4720
4974
  YARN_CLASSIC: YARN_CLASSIC$3
4721
4975
  } = constants;
4722
- function lockIncludesNpm(lockSrc, name) {
4976
+ function includesNpm(lockSrc, name) {
4723
4977
  // Detects the package name in the following cases:
4724
4978
  // "name":
4725
4979
  return lockSrc.includes(`"${name}":`);
4726
4980
  }
4727
- function lockIncludesBun(lockSrc, name, lockName) {
4981
+ function includesBun(lockSrc, name, lockName) {
4728
4982
  // This is a bit counterintuitive. When lockName ends with a .lockb
4729
4983
  // we treat it as a yarn.lock. When lockName ends with a .lock we
4730
4984
  // treat it as a package-lock.json. The bun.lock format is not identical
4731
4985
  // package-lock.json, however it close enough for npmLockIncludes to work.
4732
- const lockScanner = lockName?.endsWith(LOCK_EXT) ? lockIncludesNpm : lockIncludesYarn;
4733
- return lockScanner(lockSrc, name);
4986
+ const lockfileScanner = lockName?.endsWith(LOCK_EXT) ? includesNpm : includesYarn;
4987
+ return lockfileScanner(lockSrc, name);
4734
4988
  }
4735
- function lockIncludesPnpm(lockSrc, name) {
4989
+ function includesPnpm(lockSrc, name) {
4736
4990
  const escapedName = regexps.escapeRegExp(name);
4737
4991
  return new RegExp(
4738
4992
  // Detects the package name in the following cases:
@@ -4742,12 +4996,12 @@ function lockIncludesPnpm(lockSrc, name) {
4742
4996
  // name@
4743
4997
  `(?<=^\\s*)(?:(['/])${escapedName}\\1|${escapedName}(?=[:@]))`, 'm').test(lockSrc);
4744
4998
  }
4745
- function lockIncludesVlt(lockSrc, name) {
4999
+ function includesVlt(lockSrc, name) {
4746
5000
  // Detects the package name in the following cases:
4747
5001
  // "name"
4748
5002
  return lockSrc.includes(`"${name}"`);
4749
5003
  }
4750
- function lockIncludesYarn(lockSrc, name) {
5004
+ function includesYarn(lockSrc, name) {
4751
5005
  const escapedName = regexps.escapeRegExp(name);
4752
5006
  return new RegExp(
4753
5007
  // Detects the package name in the following cases:
@@ -4757,11 +5011,11 @@ function lockIncludesYarn(lockSrc, name) {
4757
5011
  // , name@
4758
5012
  `(?<=(?:^\\s*|,\\s*)"?)${escapedName}(?=@)`, 'm').test(lockSrc);
4759
5013
  }
4760
- const lockIncludesByAgent = new Map([[BUN$2, lockIncludesBun], [NPM$6, lockIncludesNpm], [PNPM$3, lockIncludesPnpm], [VLT$2, lockIncludesVlt], [YARN_BERRY$2, lockIncludesYarn], [YARN_CLASSIC$3, lockIncludesYarn]]);
5014
+ const lockfileIncludesByAgent = new Map([[BUN$2, includesBun], [NPM$4, includesNpm], [PNPM$3, includesPnpm], [VLT$2, includesVlt], [YARN_BERRY$2, includesYarn], [YARN_CLASSIC$3, includesYarn]]);
4761
5015
 
4762
5016
  const {
4763
5017
  BUN: BUN$1,
4764
- NPM: NPM$5,
5018
+ NPM: NPM$3,
4765
5019
  PNPM: PNPM$2,
4766
5020
  VLT: VLT$1,
4767
5021
  YARN_BERRY: YARN_BERRY$1,
@@ -4797,11 +5051,11 @@ function cleanupQueryStdout(stdout) {
4797
5051
  }
4798
5052
  return JSON.stringify([...names], null, 2);
4799
5053
  }
4800
- function parseableToQueryStdout(stdout) {
5054
+ function parsableToQueryStdout(stdout) {
4801
5055
  if (stdout === '') {
4802
5056
  return '';
4803
5057
  }
4804
- // Convert the parseable stdout into a json array of unique names.
5058
+ // Convert the parsable stdout into a json array of unique names.
4805
5059
  // The matchAll regexp looks for a forward (posix) or backward (win32) slash
4806
5060
  // and matches one or more non-slashes until the newline.
4807
5061
  const names = new Set(stdout.matchAll(/(?<=[/\\])[^/\\]+(?=\n)/g));
@@ -4831,7 +5085,7 @@ async function lsNpm(agentExecPath, cwd) {
4831
5085
  }
4832
5086
  async function lsPnpm(agentExecPath, cwd, options) {
4833
5087
  const npmExecPath = options?.npmExecPath;
4834
- if (npmExecPath && npmExecPath !== NPM$5) {
5088
+ if (npmExecPath && npmExecPath !== NPM$3) {
4835
5089
  const result = await npmQuery(npmExecPath, cwd);
4836
5090
  if (result) {
4837
5091
  return result;
@@ -4839,15 +5093,19 @@ async function lsPnpm(agentExecPath, cwd, options) {
4839
5093
  }
4840
5094
  let stdout = '';
4841
5095
  try {
4842
- stdout = (await spawn.spawn(agentExecPath, ['ls', '--parseable', '--prod', '--depth', 'Infinity'], {
5096
+ stdout = (await spawn.spawn(agentExecPath,
5097
+ // Pnpm uses the alternative spelling of parsable.
5098
+ // https://en.wiktionary.org/wiki/parsable
5099
+ ['ls', '--parseable', '--prod', '--depth', 'Infinity'], {
4843
5100
  cwd
4844
5101
  })).stdout;
4845
5102
  } catch {}
4846
- return parseableToQueryStdout(stdout);
5103
+ return parsableToQueryStdout(stdout);
4847
5104
  }
4848
5105
  async function lsVlt(agentExecPath, cwd) {
4849
5106
  let stdout = '';
4850
5107
  try {
5108
+ // See https://docs.vlt.sh/cli/commands/list#options.
4851
5109
  stdout = (await spawn.spawn(agentExecPath, ['ls', '--view', 'human', ':not(.dev)'], {
4852
5110
  cwd
4853
5111
  })).stdout;
@@ -4878,20 +5136,39 @@ async function lsYarnClassic(agentExecPath, cwd) {
4878
5136
  } catch {}
4879
5137
  return '';
4880
5138
  }
4881
- const lsByAgent = {
4882
- // @ts-ignore
4883
- __proto__: null,
4884
- [BUN$1]: lsBun,
4885
- [NPM$5]: lsNpm,
4886
- [PNPM$2]: lsPnpm,
4887
- [VLT$1]: lsVlt,
4888
- [YARN_BERRY$1]: lsYarnBerry,
4889
- [YARN_CLASSIC$2]: lsYarnClassic
4890
- };
5139
+ const lsByAgent = new Map([[BUN$1, lsBun], [NPM$3, lsNpm], [PNPM$2, lsPnpm], [VLT$1, lsVlt], [YARN_BERRY$1, lsYarnBerry], [YARN_CLASSIC$2, lsYarnClassic]]);
5140
+
5141
+ const {
5142
+ NPM_BUGGY_OVERRIDES_PATCHED_VERSION
5143
+ } = constants;
5144
+ async function updateLockfile(pkgEnvDetails, options) {
5145
+ const {
5146
+ cmdName = '',
5147
+ logger,
5148
+ spinner
5149
+ } = {
5150
+ __proto__: null,
5151
+ ...options
5152
+ };
5153
+ spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
5154
+ try {
5155
+ await runAgentInstall(pkgEnvDetails, {
5156
+ spinner
5157
+ });
5158
+ spinner?.stop();
5159
+ if (pkgEnvDetails.features.npmBuggyOverrides) {
5160
+ logger?.log(`💡 Re-run ${cmdName ? `${cmdName} ` : ''}whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped for ${pkgEnvDetails.agent} >=${NPM_BUGGY_OVERRIDES_PATCHED_VERSION}.`);
5161
+ }
5162
+ } catch (e) {
5163
+ spinner?.stop();
5164
+ logger?.fail(cmdPrefixMessage(cmdName, `${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`));
5165
+ logger?.error(e);
5166
+ }
5167
+ }
4891
5168
 
4892
5169
  const {
4893
5170
  BUN,
4894
- NPM: NPM$4,
5171
+ NPM: NPM$2,
4895
5172
  OVERRIDES,
4896
5173
  PNPM: PNPM$1,
4897
5174
  RESOLUTIONS,
@@ -4911,7 +5188,9 @@ function getHighestEntryIndex(entries, keys) {
4911
5188
  return getEntryIndexes(entries, keys).at(-1) ?? -1;
4912
5189
  }
4913
5190
  function updatePkgJson(editablePkgJson, field, value) {
4914
- const pkgJson = editablePkgJson.content;
5191
+ const {
5192
+ content: pkgJson
5193
+ } = editablePkgJson;
4915
5194
  const oldValue = pkgJson[field];
4916
5195
  if (oldValue) {
4917
5196
  // The field already exists so we simply update the field value.
@@ -4995,177 +5274,15 @@ function updateResolutions(editablePkgJson, overrides) {
4995
5274
  function pnpmUpdatePkgJson(editablePkgJson, overrides) {
4996
5275
  updatePkgJson(editablePkgJson, PNPM_FIELD_NAME, overrides);
4997
5276
  }
4998
- const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$4, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
4999
-
5000
- const {
5001
- SOCKET_IPC_HANDSHAKE
5002
- } = constants;
5003
- function safeNpmInstall(options) {
5004
- const {
5005
- args = [],
5006
- ipc,
5007
- spinner,
5008
- ...spawnOptions
5009
- } = {
5010
- __proto__: null,
5011
- ...options
5012
- };
5013
- const terminatorPos = args.indexOf('--');
5014
- const npmArgs = (terminatorPos === -1 ? args : args.slice(0, terminatorPos)).filter(a => !npm.isAuditFlag(a) && !npm.isFundFlag(a) && !npm.isProgressFlag(a));
5015
- const otherArgs = terminatorPos === -1 ? [] : args.slice(terminatorPos);
5016
- const useIpc = objects.isObject(ipc);
5017
- const useDebug = debug.isDebug();
5018
- const isSilent = !useDebug && !npmArgs.some(npm.isLoglevelFlag);
5019
- const spawnPromise = spawn.spawn(
5020
- // Lazily access constants.execPath.
5021
- constants.execPath, [
5022
- // Lazily access constants.nodeNoWarningsFlags.
5023
- ...constants.nodeNoWarningsFlags, '--require',
5024
- // Lazily access constants.distShadowNpmInjectPath.
5025
- constants.distShadowNpmInjectPath, shadowNpmPaths.getNpmBinPath(), 'install',
5026
- // Even though the '--silent' flag is passed npm will still run through
5027
- // code paths for 'audit' and 'fund' unless '--no-audit' and '--no-fund'
5028
- // flags are passed.
5029
- '--no-audit', '--no-fund',
5030
- // Add `--no-progress` and `--silent` flags to fix input being swallowed
5031
- // by the spinner when running the command with recent versions of npm.
5032
- '--no-progress',
5033
- // Add the '--silent' flag if a loglevel flag is not provided and the
5034
- // SOCKET_CLI_DEBUG environment variable is not truthy.
5035
- ...(isSilent ? ['--silent'] : []), ...npmArgs, ...otherArgs], {
5036
- spinner,
5037
- // Set stdio to include 'ipc'.
5038
- // See https://github.com/nodejs/node/blob/v23.6.0/lib/child_process.js#L161-L166
5039
- // and https://github.com/nodejs/node/blob/v23.6.0/lib/internal/child_process.js#L238.
5040
- stdio: isSilent ?
5041
- // 'ignore'
5042
- useIpc ? ['ignore', 'ignore', 'ignore', 'ipc'] : 'ignore' :
5043
- // 'inherit'
5044
- useIpc ? [0, 1, 2, 'ipc'] : 'inherit',
5045
- ...spawnOptions,
5046
- env: {
5047
- ...process$1.env,
5048
- ...spawnOptions.env
5049
- }
5050
- });
5051
- if (useIpc) {
5052
- spawnPromise.process.send({
5053
- [SOCKET_IPC_HANDSHAKE]: ipc
5054
- });
5055
- }
5056
- return spawnPromise;
5057
- }
5058
-
5059
- const {
5060
- NPM: NPM$3,
5061
- abortSignal
5062
- } = constants;
5063
- function runAgentInstall(agent, agentExecPath, options) {
5064
- // All package managers support the "install" command.
5065
- if (agent === NPM$3) {
5066
- return safeNpmInstall(options);
5067
- }
5068
- const {
5069
- args = [],
5070
- spinner,
5071
- ...spawnOptions
5072
- } = {
5073
- __proto__: null,
5074
- ...options
5075
- };
5076
- const isSilent = !debug.isDebug();
5077
- return spawn.spawn(agentExecPath, ['install', ...args], {
5078
- signal: abortSignal,
5079
- spinner,
5080
- stdio: isSilent ? 'ignore' : 'inherit',
5081
- ...spawnOptions,
5082
- env: {
5083
- ...process.env,
5084
- ...spawnOptions.env
5085
- }
5086
- });
5087
- }
5088
-
5089
- const {
5090
- NPM: NPM$2
5091
- } = constants;
5092
- const COMMAND_TITLE$1 = 'Socket Optimize';
5093
- async function updatePackageLockJson(pkgEnvDetails, options) {
5094
- const {
5095
- logger,
5096
- spinner
5097
- } = {
5098
- __proto__: null,
5099
- ...options
5100
- };
5101
- spinner?.start(`Updating ${pkgEnvDetails.lockName}...`);
5102
- try {
5103
- await runAgentInstall(pkgEnvDetails.agent, pkgEnvDetails.agentExecPath, {
5104
- spinner
5105
- });
5106
- spinner?.stop();
5107
- if (pkgEnvDetails.agent === NPM$2) {
5108
- logger?.log(`💡 Re-run ${COMMAND_TITLE$1} whenever ${pkgEnvDetails.lockName} changes.\n This can be skipped once npm v11.2.0 is released.`);
5109
- }
5110
- } catch (e) {
5111
- spinner?.stop();
5112
- logger?.fail(`${COMMAND_TITLE$1}: ${pkgEnvDetails.agent} install failed to update ${pkgEnvDetails.lockName}`);
5113
- logger?.error(e);
5114
- }
5115
- }
5277
+ const updateManifestByAgent = new Map([[BUN, updateResolutions], [NPM$2, updateOverrides], [PNPM$1, pnpmUpdatePkgJson], [VLT, updateOverrides], [YARN_BERRY, updateResolutions], [YARN_CLASSIC$1, updateResolutions]]);
5116
5278
 
5117
5279
  const {
5118
5280
  NPM: NPM$1,
5119
5281
  PNPM,
5120
5282
  YARN_CLASSIC
5121
5283
  } = constants;
5122
- const COMMAND_TITLE = 'Socket Optimize';
5284
+ const CMD_NAME = 'socket optimize';
5123
5285
  const manifestNpmOverrides = registry.getManifestData(NPM$1);
5124
- async function applyOptimization(cwd, pin, prod) {
5125
- const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
5126
- logger: logger.logger,
5127
- prod
5128
- });
5129
- if (!pkgEnvDetails) {
5130
- return;
5131
- }
5132
- // Lazily access constants.spinner.
5133
- const {
5134
- spinner
5135
- } = constants;
5136
- spinner.start('Socket optimizing...');
5137
- const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
5138
- logger: logger.logger,
5139
- pin,
5140
- prod,
5141
- spinner
5142
- });
5143
- spinner.stop();
5144
- const addedCount = state.added.size;
5145
- const updatedCount = state.updated.size;
5146
- const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
5147
- if (pkgJsonChanged) {
5148
- if (updatedCount > 0) {
5149
- logger.logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
5150
- }
5151
- if (addedCount > 0) {
5152
- logger.logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
5153
- }
5154
- } else {
5155
- logger.logger?.log('Congratulations! Already Socket.dev optimized 🎉');
5156
- }
5157
- if (pkgEnvDetails.agent === NPM$1 || pkgJsonChanged) {
5158
- // Always update package-lock.json until the npm overrides PR lands:
5159
- // https://github.com/npm/cli/pull/8089
5160
- await updatePackageLockJson(pkgEnvDetails, {
5161
- logger: logger.logger,
5162
- spinner
5163
- });
5164
- }
5165
- }
5166
- function createActionMessage(verb, overrideCount, workspaceCount) {
5167
- return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
5168
- }
5169
5286
  async function addOverrides(pkgPath, pkgEnvDetails, options) {
5170
5287
  const {
5171
5288
  agent,
@@ -5209,16 +5326,16 @@ async function addOverrides(pkgPath, pkgEnvDetails, options) {
5209
5326
  const isWorkspace = !!workspaceGlobs;
5210
5327
  if (isWorkspace && agent === PNPM && npmExecPath === NPM$1 && !state.warnedPnpmWorkspaceRequiresNpm) {
5211
5328
  state.warnedPnpmWorkspaceRequiresNpm = true;
5212
- logger?.warn(`${COMMAND_TITLE}: pnpm workspace support requires \`npm ls\`, falling back to \`pnpm list\``);
5329
+ logger?.warn(cmdPrefixMessage(CMD_NAME, 'pnpm workspace support requires `npm ls`, falling back to `pnpm list`'));
5213
5330
  }
5214
- const thingToScan = isLockScanned ? lockSrc : await lsByAgent[agent](agentExecPath, pkgPath, {
5331
+ const thingToScan = isLockScanned ? lockSrc : await lsByAgent.get(agent)(agentExecPath, pkgPath, {
5215
5332
  npmExecPath
5216
5333
  });
5217
5334
  // The AgentDepsIncludesFn and AgentLockIncludesFn types overlap in their
5218
5335
  // first two parameters. AgentLockIncludesFn accepts an optional third
5219
5336
  // parameter which AgentDepsIncludesFn will ignore so we cast thingScanner
5220
5337
  // as an AgentLockIncludesFn type.
5221
- const thingScanner = isLockScanned ? lockIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
5338
+ const thingScanner = isLockScanned ? lockfileIncludesByAgent.get(agent) : depsIncludesByAgent.get(agent);
5222
5339
  const depEntries = getDependencyEntries(pkgJson);
5223
5340
  const overridesDataObjects = [];
5224
5341
  if (pkgJson['private'] || isWorkspace) {
@@ -5344,6 +5461,51 @@ async function addOverrides(pkgPath, pkgEnvDetails, options) {
5344
5461
  }
5345
5462
  return state;
5346
5463
  }
5464
+ function createActionMessage(verb, overrideCount, workspaceCount) {
5465
+ return `${verb} ${overrideCount} Socket.dev optimized ${words.pluralize('override', overrideCount)}${workspaceCount ? ` in ${workspaceCount} ${words.pluralize('workspace', workspaceCount)}` : ''}`;
5466
+ }
5467
+ async function applyOptimization(cwd, pin, prod) {
5468
+ const pkgEnvDetails = await detectAndValidatePackageEnvironment(cwd, {
5469
+ cmdName: CMD_NAME,
5470
+ logger: logger.logger,
5471
+ prod
5472
+ });
5473
+ if (!pkgEnvDetails) {
5474
+ return;
5475
+ }
5476
+ // Lazily access constants.spinner.
5477
+ const {
5478
+ spinner
5479
+ } = constants;
5480
+ spinner.start('Socket optimizing...');
5481
+ const state = await addOverrides(pkgEnvDetails.pkgPath, pkgEnvDetails, {
5482
+ logger: logger.logger,
5483
+ pin,
5484
+ prod,
5485
+ spinner
5486
+ });
5487
+ spinner.stop();
5488
+ const addedCount = state.added.size;
5489
+ const updatedCount = state.updated.size;
5490
+ const pkgJsonChanged = addedCount > 0 || updatedCount > 0;
5491
+ if (pkgJsonChanged) {
5492
+ if (updatedCount > 0) {
5493
+ logger.logger?.log(`${createActionMessage('Updated', updatedCount, state.updatedInWorkspaces.size)}${addedCount ? '.' : '🚀'}`);
5494
+ }
5495
+ if (addedCount > 0) {
5496
+ logger.logger?.log(`${createActionMessage('Added', addedCount, state.addedInWorkspaces.size)} 🚀`);
5497
+ }
5498
+ } else {
5499
+ logger.logger?.log('Congratulations! Already Socket.dev optimized 🎉');
5500
+ }
5501
+ if (pkgJsonChanged || pkgEnvDetails.features.npmBuggyOverrides) {
5502
+ await updateLockfile(pkgEnvDetails, {
5503
+ cmdName: CMD_NAME,
5504
+ logger: logger.logger,
5505
+ spinner
5506
+ });
5507
+ }
5508
+ }
5347
5509
 
5348
5510
  const {
5349
5511
  DRY_RUN_BAIL_TEXT: DRY_RUN_BAIL_TEXT$h
@@ -5724,8 +5886,8 @@ async function fetchReportData(reportId, includeAllIssues, strict) {
5724
5886
  spinner.error('Report result deemed unhealthy for project');
5725
5887
  }
5726
5888
  } else if (!result.data.healthy) {
5727
- const severityCount = getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5728
- const issueSummary = formatSeverityCount(severityCount);
5889
+ const severityCount = shadowNpmInject.getSeverityCount(result.data.issues, includeAllIssues ? undefined : 'high');
5890
+ const issueSummary = shadowNpmInject.formatSeverityCount(severityCount);
5729
5891
  spinner.success(`Report has these issues: ${issueSummary}`);
5730
5892
  } else {
5731
5893
  spinner.success('Report has no issues');
@@ -7026,7 +7188,7 @@ async function run$6(argv, importMeta, {
7026
7188
  });
7027
7189
  const [orgSlug = '', ...targets] = cli.input;
7028
7190
  const cwd = cli.flags['cwd'] && cli.flags['cwd'] !== 'process.cwd()' ? String(cli.flags['cwd']) : process$1.cwd();
7029
- let {
7191
+ const {
7030
7192
  branch: branchName,
7031
7193
  repo: repoName
7032
7194
  } = cli.flags;
@@ -7621,11 +7783,36 @@ const cmdScan = {
7621
7783
  }
7622
7784
  };
7623
7785
 
7786
+ // Note: Widgets does not seem to actually work as code :'(
7787
+
7624
7788
  async function getThreatFeed({
7789
+ direction,
7790
+ ecosystem,
7791
+ filter,
7792
+ outputKind,
7793
+ page,
7794
+ perPage
7795
+ }) {
7796
+ const apiToken = shadowNpmInject.getDefaultToken();
7797
+ if (!apiToken) {
7798
+ throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7799
+ }
7800
+ await getThreatFeedWithToken({
7801
+ apiToken,
7802
+ direction,
7803
+ ecosystem,
7804
+ filter,
7805
+ outputKind,
7806
+ page,
7807
+ perPage
7808
+ });
7809
+ }
7810
+ async function getThreatFeedWithToken({
7625
7811
  apiToken,
7626
7812
  direction,
7813
+ ecosystem,
7627
7814
  filter,
7628
- outputJson,
7815
+ outputKind,
7629
7816
  page,
7630
7817
  perPage
7631
7818
  }) {
@@ -7633,17 +7820,12 @@ async function getThreatFeed({
7633
7820
  const {
7634
7821
  spinner
7635
7822
  } = constants;
7636
- spinner.start('Looking up the threat feed');
7637
- const formattedQueryParams = formatQueryParams({
7638
- per_page: perPage,
7639
- page,
7640
- direction,
7641
- filter
7642
- }).join('&');
7643
- const response = await queryAPI(`threat-feed?${formattedQueryParams}`, apiToken);
7823
+ const queryParams = new URLSearchParams([['direction', direction], ['ecosystem', ecosystem], ['filter', filter], ['page', page], ['per_page', String(perPage)]]);
7824
+ spinner.start('Fetching Threat Feed data...');
7825
+ const response = await queryAPI(`threat-feed?${queryParams}`, apiToken);
7644
7826
  const data = await response.json();
7645
- spinner.stop();
7646
- if (outputJson) {
7827
+ spinner.stop('Threat feed data fetched');
7828
+ if (outputKind === 'json') {
7647
7829
  logger.logger.log(data);
7648
7830
  return;
7649
7831
  }
@@ -7656,47 +7838,98 @@ async function getThreatFeed({
7656
7838
  interactive: 'true',
7657
7839
  label: 'Threat feed',
7658
7840
  width: '100%',
7659
- height: '100%',
7841
+ height: '70%',
7842
+ // Changed from 100% to 70%
7660
7843
  border: {
7661
7844
  type: 'line',
7662
7845
  fg: 'cyan'
7663
7846
  },
7664
- columnSpacing: 3,
7665
- //in chars
7666
- columnWidth: [9, 30, 10, 17, 13, 100] /*in chars*/
7847
+ columnWidth: [10, 30, 20, 18, 15, 200],
7848
+ // TODO: the truncation doesn't seem to work too well yet but when we add
7849
+ // `pad` alignment fails, when we extend columnSpacing alignment fails
7850
+ columnSpacing: 1,
7851
+ truncate: '_'
7852
+ });
7853
+
7854
+ // Create details box at the bottom
7855
+ const detailsBox = new BoxWidget({
7856
+ bottom: 0,
7857
+ height: '30%',
7858
+ width: '100%',
7859
+ border: {
7860
+ type: 'line',
7861
+ fg: 'cyan'
7862
+ },
7863
+ label: 'Details',
7864
+ content: 'Use arrow keys to navigate. Press Enter to select a threat. Press q to exit.',
7865
+ style: {
7866
+ fg: 'white'
7867
+ }
7667
7868
  });
7668
7869
 
7669
7870
  // allow control the table with the keyboard
7670
7871
  table.focus();
7671
7872
  screen.append(table);
7873
+ screen.append(detailsBox);
7672
7874
  const formattedOutput = formatResults(data.results);
7875
+ const descriptions = data.results.map(d => d.description);
7673
7876
  table.setData({
7674
- headers: ['Ecosystem', 'Name', 'Version', 'Threat type', 'Detected at', 'Details'],
7877
+ headers: [' Ecosystem', ' Name', ' Version', ' Threat type', ' Detected at', ' Details'],
7675
7878
  data: formattedOutput
7676
7879
  });
7880
+
7881
+ // Update details box when selection changes
7882
+ table.rows.on('select item', () => {
7883
+ const selectedIndex = table.rows.selected;
7884
+ if (selectedIndex !== undefined && selectedIndex >= 0) {
7885
+ const selectedRow = formattedOutput[selectedIndex];
7886
+ if (selectedRow) {
7887
+ // Note: the spacing works around issues with the table; it refuses to pad!
7888
+ detailsBox.setContent(`Ecosystem: ${selectedRow[0]}\n` + `Name: ${selectedRow[1]}\n` + `Version:${selectedRow[2]}\n` + `Threat type:${selectedRow[3]}\n` + `Detected at:${selectedRow[4]}\n` + `Details: ${selectedRow[5]}\n` + `Description: ${descriptions[selectedIndex]}`);
7889
+ screen.render();
7890
+ }
7891
+ }
7892
+ });
7677
7893
  screen.render();
7678
7894
  screen.key(['escape', 'q', 'C-c'], () => process$1.exit(0));
7895
+ screen.key(['return'], () => {
7896
+ const selectedIndex = table.rows.selected;
7897
+ screen.destroy();
7898
+ const selectedRow = formattedOutput[selectedIndex];
7899
+ console.log(selectedRow);
7900
+ });
7679
7901
  }
7680
7902
  function formatResults(data) {
7681
7903
  return data.map(d => {
7682
7904
  const ecosystem = d.purl.split('pkg:')[1].split('/')[0];
7683
7905
  const name = d.purl.split('/')[1].split('@')[0];
7684
7906
  const version = d.purl.split('@')[1];
7685
- const timeStart = new Date(d.createdAt).getMilliseconds();
7686
- const timeEnd = Date.now();
7687
- const diff = getHourDiff(timeStart, timeEnd);
7688
- const hourDiff = diff > 0 ? `${diff} hours ago` : `${getMinDiff(timeStart, timeEnd)} minutes ago`;
7689
- return [ecosystem, decodeURIComponent(name), version, d.threatType, hourDiff, d.locationHtmlUrl];
7907
+ const timeDiff = msAtHome(d.createdAt);
7908
+
7909
+ // Note: the spacing works around issues with the table; it refuses to pad!
7910
+ return [ecosystem, decodeURIComponent(name), ` ${version}`, ` ${d.threatType}`, ` ${timeDiff}`, d.locationHtmlUrl];
7690
7911
  });
7691
7912
  }
7692
- function formatQueryParams(params) {
7693
- return Object.entries(params).map(entry => `${entry[0]}=${entry[1]}`);
7694
- }
7695
- function getHourDiff(start, end) {
7696
- return Math.floor((end - start) / 3600000);
7697
- }
7698
- function getMinDiff(start, end) {
7699
- return Math.floor((end - start) / 60000);
7913
+ function msAtHome(isoTimeStamp) {
7914
+ const timeStart = Date.parse(isoTimeStamp);
7915
+ const timeEnd = Date.now();
7916
+ const rtf = new Intl.RelativeTimeFormat('en', {
7917
+ numeric: 'always',
7918
+ style: 'short'
7919
+ });
7920
+ const delta = timeEnd - timeStart;
7921
+ if (delta < 60 * 60 * 1000) {
7922
+ return rtf.format(-Math.round(delta / (60 * 1000)), 'minute');
7923
+ // return Math.round(delta / (60 * 1000)) + ' min ago'
7924
+ } else if (delta < 24 * 60 * 60 * 1000) {
7925
+ return rtf.format(-(delta / (60 * 60 * 1000)).toFixed(1), 'hour');
7926
+ // return (delta / (60 * 60 * 1000)).toFixed(1) + ' hr ago'
7927
+ } else if (delta < 7 * 24 * 60 * 60 * 1000) {
7928
+ return rtf.format(-(delta / (24 * 60 * 60 * 1000)).toFixed(1), 'day');
7929
+ // return (delta / (24 * 60 * 60 * 1000)).toFixed(1) + ' day ago'
7930
+ } else {
7931
+ return isoTimeStamp.slice(0, 10);
7932
+ }
7700
7933
  }
7701
7934
 
7702
7935
  const {
@@ -7704,7 +7937,7 @@ const {
7704
7937
  } = constants;
7705
7938
  const config$1 = {
7706
7939
  commandName: 'threat-feed',
7707
- description: 'Look up the threat feed',
7940
+ description: '[beta] View the threat feed',
7708
7941
  hidden: false,
7709
7942
  flags: {
7710
7943
  ...commonFlags,
@@ -7727,6 +7960,12 @@ const config$1 = {
7727
7960
  default: 'desc',
7728
7961
  description: 'Order asc or desc by the createdAt attribute.'
7729
7962
  },
7963
+ eco: {
7964
+ type: 'string',
7965
+ shortFlag: 'e',
7966
+ default: '',
7967
+ description: 'Only show threats for a particular ecosystem'
7968
+ },
7730
7969
  filter: {
7731
7970
  type: 'string',
7732
7971
  shortFlag: 'f',
@@ -7738,9 +7977,35 @@ const config$1 = {
7738
7977
  Usage
7739
7978
  $ ${command}
7740
7979
 
7980
+ This feature requires a Threat Feed license. Please contact
7981
+ sales@socket.dev if you are interested in purchasing this access.
7982
+
7741
7983
  Options
7742
7984
  ${getFlagListOutput(config.flags, 6)}
7743
7985
 
7986
+ Valid filters:
7987
+
7988
+ - anom Anomaly
7989
+ - c Do not filter
7990
+ - fp False Positives
7991
+ - joke Joke / Fake
7992
+ - mal Malware and Possible Malware [default]
7993
+ - secret Secrets
7994
+ - spy Telemetry
7995
+ - tp False Positives and Unreviewed
7996
+ - typo Typo-squat
7997
+ - u Unreviewed
7998
+ - vuln Vulnerability
7999
+
8000
+ Valid ecosystems:
8001
+
8002
+ - gem
8003
+ - golang
8004
+ - maven
8005
+ - npm
8006
+ - nuget
8007
+ - pypi
8008
+
7744
8009
  Examples
7745
8010
  $ ${command}
7746
8011
  $ ${command} --perPage=5 --page=2 --direction=asc --filter=joke
@@ -7764,17 +8029,13 @@ async function run$1(argv, importMeta, {
7764
8029
  logger.logger.log(DRY_RUN_BAIL_TEXT$1);
7765
8030
  return;
7766
8031
  }
7767
- const apiToken = shadowNpmInject.getDefaultToken();
7768
- if (!apiToken) {
7769
- throw new shadowNpmInject.AuthError('User must be authenticated to run this command. To log in, run the command `socket login` and enter your API key.');
7770
- }
7771
8032
  await getThreatFeed({
7772
- apiToken,
7773
8033
  direction: String(cli.flags['direction'] || 'desc'),
8034
+ ecosystem: String(cli.flags['eco'] || ''),
7774
8035
  filter: String(cli.flags['filter'] || 'mal'),
7775
- outputJson: Boolean(cli.flags['json']),
7776
- page: String(cli.flags['filter'] || '1'),
7777
- perPage: Number(cli.flags['per_page'] || 0)
8036
+ outputKind: cli.flags['json'] ? 'json' : cli.flags['markdown'] ? 'markdown' : 'print',
8037
+ page: String(cli.flags['page'] || '1'),
8038
+ perPage: Number(cli.flags['perPage']) || 30
7778
8039
  });
7779
8040
  }
7780
8041
 
@@ -7976,14 +8237,14 @@ async function run(argv, importMeta, {
7976
8237
  }
7977
8238
 
7978
8239
  const {
7979
- SOCKET,
8240
+ SOCKET_CLI_BIN_NAME,
7980
8241
  rootPkgJsonPath
7981
8242
  } = constants;
7982
8243
 
7983
8244
  // TODO: Add autocompletion using https://socket.dev/npm/package/omelette
7984
8245
  void (async () => {
7985
8246
  await vendor.updater({
7986
- name: SOCKET,
8247
+ name: SOCKET_CLI_BIN_NAME,
7987
8248
  version: require(rootPkgJsonPath).version,
7988
8249
  ttl: 86_400_000 /* 24 hours in milliseconds */
7989
8250
  });
@@ -8020,7 +8281,7 @@ void (async () => {
8020
8281
  }
8021
8282
  },
8022
8283
  argv: process$1.argv.slice(2),
8023
- name: SOCKET,
8284
+ name: SOCKET_CLI_BIN_NAME,
8024
8285
  importMeta: {
8025
8286
  url: `${require$$0.pathToFileURL(__filename)}`
8026
8287
  }
@@ -8044,12 +8305,12 @@ void (async () => {
8044
8305
  } else {
8045
8306
  errorTitle = 'Unexpected error with no details';
8046
8307
  }
8047
- logger.logger.fail(`${colors.bgRed(colors.white(errorTitle + ':'))} ${errorMessage}`);
8308
+ logger.logger.fail(`${colors.bgRed(colors.white(`${errorTitle}:`))} ${errorMessage}`);
8048
8309
  if (errorBody) {
8049
8310
  logger.logger.error(`\n${errorBody}`);
8050
8311
  }
8051
8312
  await shadowNpmInject.captureException(e);
8052
8313
  }
8053
8314
  })();
8054
- //# debugId=da32be80-6a12-4a4c-b9c4-0cfdd490ce52
8315
+ //# debugId=2e8d9d04-20b0-4f47-8b02-b404f72bd2d
8055
8316
  //# sourceMappingURL=cli.js.map