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