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