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