@socketsecurity/cli-with-sentry 0.14.57 → 0.14.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +2 -0
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +11 -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 +1063 -802
- 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 +1063 -802
- 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
|
@@ -9,18 +9,18 @@ function _socketInterop(e) {
|
|
|
9
9
|
return c ? e.default : e
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
var process = require('node:process');
|
|
13
|
-
var
|
|
12
|
+
var process$1 = require('node:process');
|
|
13
|
+
var logger = require('@socketsecurity/registry/lib/logger');
|
|
14
|
+
var prompts = require('@socketsecurity/registry/lib/prompts');
|
|
15
|
+
var constants = require('./constants.js');
|
|
14
16
|
var semver = _socketInterop(require('semver'));
|
|
15
17
|
var packageurlJs = require('@socketregistry/packageurl-js');
|
|
16
18
|
var registry = require('@socketsecurity/registry');
|
|
17
19
|
var arrays = require('@socketsecurity/registry/lib/arrays');
|
|
20
|
+
var debug = require('@socketsecurity/registry/lib/debug');
|
|
18
21
|
var objects = require('@socketsecurity/registry/lib/objects');
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
var sorts = require('@socketsecurity/registry/lib/sorts');
|
|
22
|
-
var spinner = require('@socketsecurity/registry/lib/spinner');
|
|
23
|
-
var constants = require('./constants.js');
|
|
22
|
+
var shadowNpmPaths = require('./shadow-npm-paths.js');
|
|
23
|
+
var npa = _socketInterop(require('npm-package-arg'));
|
|
24
24
|
var events = require('node:events');
|
|
25
25
|
var https = require('node:https');
|
|
26
26
|
var readline = require('node:readline');
|
|
@@ -30,16 +30,15 @@ var registryConstants = require('@socketsecurity/registry/lib/constants');
|
|
|
30
30
|
var strings = require('@socketsecurity/registry/lib/strings');
|
|
31
31
|
var sdk = require('@socketsecurity/sdk');
|
|
32
32
|
var promises = require('node:timers/promises');
|
|
33
|
-
var debug = require('@socketsecurity/registry/lib/debug');
|
|
34
33
|
var fs = require('node:fs');
|
|
35
34
|
var os = require('node:os');
|
|
35
|
+
var path = require('node:path');
|
|
36
36
|
var config = require('@socketsecurity/config');
|
|
37
|
-
var
|
|
37
|
+
var packages = require('@socketsecurity/registry/lib/packages');
|
|
38
|
+
var sorts = require('@socketsecurity/registry/lib/sorts');
|
|
38
39
|
var terminalLink = _socketInterop(require('terminal-link'));
|
|
39
40
|
var colors = _socketInterop(require('yoctocolors-cjs'));
|
|
40
41
|
var indentString = require('@socketregistry/indent-string/index.cjs');
|
|
41
|
-
var shadowNpmPaths = require('./shadow-npm-paths.js');
|
|
42
|
-
var npa = _socketInterop(require('npm-package-arg'));
|
|
43
42
|
|
|
44
43
|
const {
|
|
45
44
|
kInternalsSymbol: kInternalsSymbol$1,
|
|
@@ -76,7 +75,7 @@ function isErrnoException(value) {
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
async function findUp(name, {
|
|
79
|
-
cwd = process.cwd()
|
|
78
|
+
cwd = process$1.cwd()
|
|
80
79
|
}) {
|
|
81
80
|
let dir = path.resolve(cwd);
|
|
82
81
|
const {
|
|
@@ -110,9 +109,9 @@ async function readFileUtf8(filepath, options) {
|
|
|
110
109
|
encoding: 'utf8'
|
|
111
110
|
});
|
|
112
111
|
}
|
|
113
|
-
function safeReadFile(...args) {
|
|
112
|
+
async function safeReadFile(...args) {
|
|
114
113
|
try {
|
|
115
|
-
return fs.promises.readFile(...args);
|
|
114
|
+
return await fs.promises.readFile(...args);
|
|
116
115
|
} catch {}
|
|
117
116
|
return undefined;
|
|
118
117
|
}
|
|
@@ -155,7 +154,7 @@ function getSettingsPath() {
|
|
|
155
154
|
const {
|
|
156
155
|
WIN32
|
|
157
156
|
} = constants;
|
|
158
|
-
let dataHome = WIN32 ? process.env[LOCALAPPDATA] : process.env['XDG_DATA_HOME'];
|
|
157
|
+
let dataHome = WIN32 ? process$1.env[LOCALAPPDATA] : process$1.env['XDG_DATA_HOME'];
|
|
159
158
|
if (!dataHome) {
|
|
160
159
|
if (WIN32) {
|
|
161
160
|
if (!_warnedSettingPathWin32Missing) {
|
|
@@ -163,7 +162,7 @@ function getSettingsPath() {
|
|
|
163
162
|
logger.logger.warn(`Missing %${LOCALAPPDATA}%`);
|
|
164
163
|
}
|
|
165
164
|
} else {
|
|
166
|
-
dataHome = path.join(os.homedir(), ...(process.platform === 'darwin' ? ['Library', 'Application Support'] : ['.local', 'share']));
|
|
165
|
+
dataHome = path.join(os.homedir(), ...(process$1.platform === 'darwin' ? ['Library', 'Application Support'] : ['.local', 'share']));
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
_settingsPath = dataHome ? path.join(dataHome, 'socket/settings') : undefined;
|
|
@@ -179,7 +178,7 @@ function normalizeSettingsKey(key) {
|
|
|
179
178
|
}
|
|
180
179
|
function findSocketYmlSync() {
|
|
181
180
|
let prevDir = null;
|
|
182
|
-
let dir = process.cwd();
|
|
181
|
+
let dir = process$1.cwd();
|
|
183
182
|
while (dir !== prevDir) {
|
|
184
183
|
let ymlPath = path.join(dir, 'socket.yml');
|
|
185
184
|
let yml = safeReadFileSync(ymlPath, 'utf8');
|
|
@@ -211,7 +210,7 @@ function updateSetting(key, value) {
|
|
|
211
210
|
settings[normalizeSettingsKey(key)] = value;
|
|
212
211
|
if (!pendingSave) {
|
|
213
212
|
pendingSave = true;
|
|
214
|
-
process.nextTick(() => {
|
|
213
|
+
process$1.nextTick(() => {
|
|
215
214
|
pendingSave = false;
|
|
216
215
|
const settingsPath = getSettingsPath();
|
|
217
216
|
if (settingsPath) {
|
|
@@ -227,13 +226,13 @@ const {
|
|
|
227
226
|
|
|
228
227
|
// The API server that should be used for operations.
|
|
229
228
|
function getDefaultApiBaseUrl() {
|
|
230
|
-
const baseUrl = process.env['SOCKET_SECURITY_API_BASE_URL'] || getSetting('apiBaseUrl');
|
|
229
|
+
const baseUrl = process$1.env['SOCKET_SECURITY_API_BASE_URL'] || getSetting('apiBaseUrl');
|
|
231
230
|
return strings.isNonEmptyString(baseUrl) ? baseUrl : undefined;
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
// The API server that should be used for operations.
|
|
235
234
|
function getDefaultHttpProxy() {
|
|
236
|
-
const apiProxy = process.env['SOCKET_SECURITY_API_PROXY'] || getSetting('apiProxy');
|
|
235
|
+
const apiProxy = process$1.env['SOCKET_SECURITY_API_PROXY'] || getSetting('apiProxy');
|
|
237
236
|
return strings.isNonEmptyString(apiProxy) ? apiProxy : undefined;
|
|
238
237
|
}
|
|
239
238
|
|
|
@@ -244,10 +243,10 @@ function getDefaultToken() {
|
|
|
244
243
|
if (constants.ENV[SOCKET_CLI_NO_API_TOKEN]) {
|
|
245
244
|
_defaultToken = undefined;
|
|
246
245
|
} else {
|
|
247
|
-
const key = process.env['SOCKET_SECURITY_API_TOKEN'] ||
|
|
246
|
+
const key = process$1.env['SOCKET_SECURITY_API_TOKEN'] ||
|
|
248
247
|
// Keep 'SOCKET_SECURITY_API_KEY' as an alias of 'SOCKET_SECURITY_API_TOKEN'.
|
|
249
248
|
// TODO: Remove 'SOCKET_SECURITY_API_KEY' alias.
|
|
250
|
-
process.env['SOCKET_SECURITY_API_KEY'] || getSetting('apiToken') || _defaultToken;
|
|
249
|
+
process$1.env['SOCKET_SECURITY_API_KEY'] || getSetting('apiToken') || _defaultToken;
|
|
251
250
|
_defaultToken = strings.isNonEmptyString(key) ? key : undefined;
|
|
252
251
|
}
|
|
253
252
|
return _defaultToken;
|
|
@@ -280,1177 +279,1443 @@ async function setupSdk(apiToken = getDefaultToken(), apiBaseUrl = getDefaultApi
|
|
|
280
279
|
});
|
|
281
280
|
}
|
|
282
281
|
|
|
282
|
+
let DiffAction = /*#__PURE__*/function (DiffAction) {
|
|
283
|
+
DiffAction["add"] = "ADD";
|
|
284
|
+
DiffAction["change"] = "CHANGE";
|
|
285
|
+
DiffAction["remove"] = "REMOVE";
|
|
286
|
+
return DiffAction;
|
|
287
|
+
}({});
|
|
288
|
+
|
|
289
|
+
const depValid = require(shadowNpmPaths.getArboristDepValidPath());
|
|
290
|
+
|
|
283
291
|
const {
|
|
284
|
-
|
|
285
|
-
NPM_REGISTRY_URL: NPM_REGISTRY_URL$1
|
|
292
|
+
UNDEFINED_TOKEN
|
|
286
293
|
} = constants;
|
|
287
|
-
function
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
294
|
+
function tryRequire(req, ...ids) {
|
|
295
|
+
for (const data of ids) {
|
|
296
|
+
let id;
|
|
297
|
+
let transformer;
|
|
298
|
+
if (Array.isArray(data)) {
|
|
299
|
+
id = data[0];
|
|
300
|
+
transformer = data[1];
|
|
301
|
+
} else {
|
|
302
|
+
id = data;
|
|
303
|
+
transformer = mod => mod;
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
// Check that the transformed value isn't `undefined` because older
|
|
307
|
+
// versions of packages like 'proc-log' may not export a `log` method.
|
|
308
|
+
const exported = transformer(req(id));
|
|
309
|
+
if (exported !== undefined) {
|
|
310
|
+
return exported;
|
|
311
|
+
}
|
|
312
|
+
} catch {}
|
|
313
|
+
}
|
|
314
|
+
return undefined;
|
|
292
315
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
};
|
|
301
|
-
const details = [];
|
|
302
|
-
// `diff_` is `null` when `npm install --package-lock-only` is passed.
|
|
303
|
-
if (!diff_) {
|
|
304
|
-
return details;
|
|
316
|
+
let _log = UNDEFINED_TOKEN;
|
|
317
|
+
function getLogger() {
|
|
318
|
+
if (_log === UNDEFINED_TOKEN) {
|
|
319
|
+
_log = tryRequire(shadowNpmPaths.getNpmRequire(), ['proc-log/lib/index.js',
|
|
320
|
+
// The proc-log DefinitelyTyped definition is incorrect. The type definition
|
|
321
|
+
// is really that of its export log.
|
|
322
|
+
mod => mod.log], 'npmlog/lib/log.js');
|
|
305
323
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
324
|
+
return _log;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const OverrideSet = require(shadowNpmPaths.getArboristOverrideSetClassPath());
|
|
328
|
+
|
|
329
|
+
// Implementation code not related to patch https://github.com/npm/cli/pull/8089
|
|
330
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/override-set.js:
|
|
331
|
+
class SafeOverrideSet extends OverrideSet {
|
|
332
|
+
// Patch adding doOverrideSetsConflict is based on
|
|
333
|
+
// https://github.com/npm/cli/pull/8089.
|
|
334
|
+
static doOverrideSetsConflict(first, second) {
|
|
335
|
+
// If override sets contain one another then we can try to use the more
|
|
336
|
+
// specific one. If neither one is more specific, then we consider them to
|
|
337
|
+
// be in conflict.
|
|
338
|
+
return this.findSpecificOverrideSet(first, second) === undefined;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Patch adding findSpecificOverrideSet is based on
|
|
342
|
+
// https://github.com/npm/cli/pull/8089.
|
|
343
|
+
static findSpecificOverrideSet(first, second) {
|
|
344
|
+
for (let overrideSet = second; overrideSet; overrideSet = overrideSet.parent) {
|
|
345
|
+
if (overrideSet.isEqual(first)) {
|
|
346
|
+
return second;
|
|
347
|
+
}
|
|
314
348
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
349
|
+
for (let overrideSet = first; overrideSet; overrideSet = overrideSet.parent) {
|
|
350
|
+
if (overrideSet.isEqual(second)) {
|
|
351
|
+
return first;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// The override sets are incomparable. Neither one contains the other.
|
|
355
|
+
const log = getLogger();
|
|
356
|
+
log?.silly('Conflicting override sets', first, second);
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Patch adding childrenAreEqual is based on
|
|
361
|
+
// https://github.com/npm/cli/pull/8089.
|
|
362
|
+
childrenAreEqual(otherOverrideSet) {
|
|
363
|
+
if (this.children.size !== otherOverrideSet.children.size) {
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
for (const {
|
|
367
|
+
0: key,
|
|
368
|
+
1: childOverrideSet
|
|
369
|
+
} of this.children) {
|
|
370
|
+
const otherChildOverrideSet = otherOverrideSet.children.get(key);
|
|
371
|
+
if (!otherChildOverrideSet) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
if (childOverrideSet.value !== otherChildOverrideSet.value) {
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
if (!childOverrideSet.childrenAreEqual(otherChildOverrideSet)) {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
getEdgeRule(edge) {
|
|
384
|
+
for (const rule of this.ruleset.values()) {
|
|
385
|
+
if (rule.name !== edge.name) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
// If keySpec is * we found our override.
|
|
389
|
+
if (rule.keySpec === '*') {
|
|
390
|
+
return rule;
|
|
391
|
+
}
|
|
392
|
+
// Patch replacing
|
|
393
|
+
// let spec = npa(`${edge.name}@${edge.spec}`)
|
|
394
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
395
|
+
//
|
|
396
|
+
// We need to use the rawSpec here, because the spec has the overrides
|
|
397
|
+
// applied to it already. The rawSpec can be undefined, so we need to use
|
|
398
|
+
// the fallback value of spec if it is.
|
|
399
|
+
let spec = npa(`${edge.name}@${edge.rawSpec || edge.spec}`);
|
|
400
|
+
if (spec.type === 'alias') {
|
|
401
|
+
spec = spec.subSpec;
|
|
402
|
+
}
|
|
403
|
+
if (spec.type === 'git') {
|
|
404
|
+
if (spec.gitRange && semver.intersects(spec.gitRange, rule.keySpec)) {
|
|
405
|
+
return rule;
|
|
336
406
|
}
|
|
337
|
-
|
|
338
|
-
keep = action !== 'REMOVE';
|
|
407
|
+
continue;
|
|
339
408
|
}
|
|
340
|
-
if (
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
node: pkgNode,
|
|
344
|
-
existing
|
|
345
|
-
});
|
|
409
|
+
if (spec.type === 'range' || spec.type === 'version') {
|
|
410
|
+
if (semver.intersects(spec.fetchSpec, rule.keySpec)) {
|
|
411
|
+
return rule;
|
|
346
412
|
}
|
|
413
|
+
continue;
|
|
347
414
|
}
|
|
415
|
+
// If we got this far, the spec type is one of tag, directory or file
|
|
416
|
+
// which means we have no real way to make version comparisons, so we
|
|
417
|
+
// just accept the override.
|
|
418
|
+
return rule;
|
|
348
419
|
}
|
|
349
|
-
|
|
350
|
-
queue[queueLength++] = child;
|
|
351
|
-
}
|
|
420
|
+
return this;
|
|
352
421
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
422
|
+
|
|
423
|
+
// Patch adding isEqual is based on
|
|
424
|
+
// https://github.com/npm/cli/pull/8089.
|
|
425
|
+
isEqual(otherOverrideSet) {
|
|
426
|
+
if (this === otherOverrideSet) {
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
if (!otherOverrideSet) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
if (this.key !== otherOverrideSet.key || this.value !== otherOverrideSet.value) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
if (!this.childrenAreEqual(otherOverrideSet)) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
if (!this.parent) {
|
|
439
|
+
return !otherOverrideSet.parent;
|
|
367
440
|
}
|
|
441
|
+
return this.parent.isEqual(otherOverrideSet.parent);
|
|
368
442
|
}
|
|
369
|
-
return details;
|
|
370
443
|
}
|
|
371
444
|
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const req = https
|
|
385
|
-
// Lazily access constants.BATCH_PURL_ENDPOINT.
|
|
386
|
-
.request(constants.BATCH_PURL_ENDPOINT, {
|
|
387
|
-
method: 'POST',
|
|
388
|
-
headers: {
|
|
389
|
-
Authorization: `Basic ${btoa(`${getPublicToken()}:`)}`
|
|
445
|
+
const Node = require(shadowNpmPaths.getArboristNodeClassPath());
|
|
446
|
+
|
|
447
|
+
// Implementation code not related to patch https://github.com/npm/cli/pull/8089
|
|
448
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/node.js:
|
|
449
|
+
class SafeNode extends Node {
|
|
450
|
+
// Return true if it's safe to remove this node, because anything that is
|
|
451
|
+
// depending on it would be fine with the thing that they would resolve to if
|
|
452
|
+
// it was removed, or nothing is depending on it in the first place.
|
|
453
|
+
canDedupe(preferDedupe = false) {
|
|
454
|
+
// Not allowed to mess with shrinkwraps or bundles.
|
|
455
|
+
if (this.inDepBundle || this.inShrinkwrap) {
|
|
456
|
+
return false;
|
|
390
457
|
}
|
|
391
|
-
//
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
components: chunk.map(id => ({
|
|
395
|
-
purl: `pkg:npm/${id}`
|
|
396
|
-
}))
|
|
397
|
-
}));
|
|
398
|
-
// Adds the second 'abort' listener to abortSignal.
|
|
399
|
-
const {
|
|
400
|
-
0: res
|
|
401
|
-
} = await events.once(req, 'response', {
|
|
402
|
-
signal: abortSignal$1
|
|
403
|
-
});
|
|
404
|
-
const ok = res.statusCode >= 200 && res.statusCode <= 299;
|
|
405
|
-
if (!ok) {
|
|
406
|
-
throw new Error(`Socket API Error: ${res.statusCode}`);
|
|
407
|
-
}
|
|
408
|
-
const rli = readline.createInterface({
|
|
409
|
-
input: res,
|
|
410
|
-
crlfDelay: Infinity,
|
|
411
|
-
signal: abortSignal$1
|
|
412
|
-
});
|
|
413
|
-
for await (const line of rli) {
|
|
414
|
-
yield JSON.parse(line);
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
async function* batchScan(pkgIds, concurrencyLimit = 50) {
|
|
418
|
-
// The createBatchGenerator method will add 2 'abort' event listeners to
|
|
419
|
-
// abortSignal so we multiply the concurrencyLimit by 2.
|
|
420
|
-
const neededMaxListeners = concurrencyLimit * 2;
|
|
421
|
-
// Increase abortSignal max listeners count to avoid Node's MaxListenersExceededWarning.
|
|
422
|
-
const oldAbortSignalMaxListeners = events.getMaxListeners(abortSignal$1);
|
|
423
|
-
let abortSignalMaxListeners = oldAbortSignalMaxListeners;
|
|
424
|
-
if (oldAbortSignalMaxListeners < neededMaxListeners) {
|
|
425
|
-
abortSignalMaxListeners = oldAbortSignalMaxListeners + neededMaxListeners;
|
|
426
|
-
events.setMaxListeners(abortSignalMaxListeners, abortSignal$1);
|
|
427
|
-
}
|
|
428
|
-
const {
|
|
429
|
-
length: pkgIdsCount
|
|
430
|
-
} = pkgIds;
|
|
431
|
-
const running = [];
|
|
432
|
-
let index = 0;
|
|
433
|
-
const enqueueGen = () => {
|
|
434
|
-
if (index >= pkgIdsCount) {
|
|
435
|
-
// No more work to do.
|
|
436
|
-
return;
|
|
458
|
+
// It's a top level pkg, or a dep of one.
|
|
459
|
+
if (!this.resolveParent?.resolveParent) {
|
|
460
|
+
return false;
|
|
437
461
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
continueGen(generator);
|
|
442
|
-
};
|
|
443
|
-
const continueGen = generator => {
|
|
444
|
-
let resolveFn;
|
|
445
|
-
running.push({
|
|
446
|
-
generator,
|
|
447
|
-
promise: new Promise(resolve => resolveFn = resolve)
|
|
448
|
-
});
|
|
449
|
-
void generator.next().then(res => resolveFn({
|
|
450
|
-
generator,
|
|
451
|
-
iteratorResult: res
|
|
452
|
-
}));
|
|
453
|
-
};
|
|
454
|
-
// Start initial batch of generators.
|
|
455
|
-
while (running.length < concurrencyLimit && index < pkgIdsCount) {
|
|
456
|
-
enqueueGen();
|
|
457
|
-
}
|
|
458
|
-
while (running.length > 0) {
|
|
459
|
-
// eslint-disable-next-line no-await-in-loop
|
|
460
|
-
const {
|
|
461
|
-
generator,
|
|
462
|
-
iteratorResult
|
|
463
|
-
} = await Promise.race(running.map(entry => entry.promise));
|
|
464
|
-
// Remove generator.
|
|
465
|
-
running.splice(running.findIndex(entry => entry.generator === generator), 1);
|
|
466
|
-
if (iteratorResult.done) {
|
|
467
|
-
// Start a new generator if available.
|
|
468
|
-
enqueueGen();
|
|
469
|
-
} else {
|
|
470
|
-
yield iteratorResult.value;
|
|
471
|
-
// Keep fetching values from this generator.
|
|
472
|
-
continueGen(generator);
|
|
462
|
+
// No one wants it, remove it.
|
|
463
|
+
if (this.edgesIn.size === 0) {
|
|
464
|
+
return true;
|
|
473
465
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
function isArtifactAlertCveFixable(alert) {
|
|
481
|
-
const {
|
|
482
|
-
type
|
|
483
|
-
} = alert;
|
|
484
|
-
return (type === ALERT_TYPE_CVE || type === ALERT_TYPE_MEDIUM_CVE || type === ALERT_TYPE_MILD_CVE || type === ALERT_TYPE_CRITICAL_CVE) && !!alert.props?.[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER$1] && !!alert.props?.[CVE_ALERT_PROPS_VULNERABLE_VERSION_RANGE];
|
|
485
|
-
}
|
|
486
|
-
function isArtifactAlertUpgradeFixable(alert) {
|
|
487
|
-
return alert.type === ALERT_TYPE_SOCKET_UPGRADE_AVAILABLE;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
const {
|
|
491
|
-
abortSignal
|
|
492
|
-
} = constants;
|
|
493
|
-
const ERROR_UX = {
|
|
494
|
-
block: true,
|
|
495
|
-
display: true
|
|
496
|
-
};
|
|
497
|
-
const IGNORE_UX = {
|
|
498
|
-
block: false,
|
|
499
|
-
display: false
|
|
500
|
-
};
|
|
501
|
-
const WARN_UX = {
|
|
502
|
-
block: false,
|
|
503
|
-
display: true
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
// Iterates over all entries with ordered issue rule for deferral. Iterates over
|
|
507
|
-
// all issue rules and finds the first defined value that does not defer otherwise
|
|
508
|
-
// uses the defaultValue. Takes the value and converts into a UX workflow.
|
|
509
|
-
function resolveAlertRuleUX(orderedRulesCollection, defaultValue) {
|
|
510
|
-
if (defaultValue === true || defaultValue === null || defaultValue === undefined) {
|
|
511
|
-
defaultValue = {
|
|
512
|
-
action: 'error'
|
|
513
|
-
};
|
|
514
|
-
} else if (defaultValue === false) {
|
|
515
|
-
defaultValue = {
|
|
516
|
-
action: 'ignore'
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
let block = false;
|
|
520
|
-
let display = false;
|
|
521
|
-
let needDefault = true;
|
|
522
|
-
iterate_entries: for (const rules of orderedRulesCollection) {
|
|
523
|
-
for (const rule of rules) {
|
|
524
|
-
if (ruleValueDoesNotDefer(rule)) {
|
|
525
|
-
needDefault = false;
|
|
526
|
-
const narrowingFilter = uxForDefinedNonDeferValue(rule);
|
|
527
|
-
block = block || narrowingFilter.block;
|
|
528
|
-
display = display || narrowingFilter.display;
|
|
529
|
-
continue iterate_entries;
|
|
530
|
-
}
|
|
466
|
+
const other = this.resolveParent.resolveParent.resolve(this.name);
|
|
467
|
+
// Nothing else, need this one.
|
|
468
|
+
if (!other) {
|
|
469
|
+
return false;
|
|
531
470
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
block = block || narrowingFilter.block;
|
|
539
|
-
display = display || narrowingFilter.display;
|
|
540
|
-
}
|
|
541
|
-
return {
|
|
542
|
-
block,
|
|
543
|
-
display
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Negative form because it is narrowing the type.
|
|
548
|
-
function ruleValueDoesNotDefer(rule) {
|
|
549
|
-
if (rule === undefined) {
|
|
550
|
-
return false;
|
|
551
|
-
}
|
|
552
|
-
if (objects.isObject(rule)) {
|
|
553
|
-
const {
|
|
554
|
-
action
|
|
555
|
-
} = rule;
|
|
556
|
-
if (action === undefined || action === 'defer') {
|
|
471
|
+
// If it's the same thing, then always fine to remove.
|
|
472
|
+
if (other.matches(this)) {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
// If the other thing can't replace this, then skip it.
|
|
476
|
+
if (!other.canReplace(this)) {
|
|
557
477
|
return false;
|
|
558
478
|
}
|
|
479
|
+
// Patch replacing
|
|
480
|
+
// if (preferDedupe || semver.gte(other.version, this.version)) {
|
|
481
|
+
// return true
|
|
482
|
+
// }
|
|
483
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
484
|
+
//
|
|
485
|
+
// If we prefer dedupe, or if the version is equal, take the other.
|
|
486
|
+
if (preferDedupe || semver.eq(other.version, this.version)) {
|
|
487
|
+
return true;
|
|
488
|
+
}
|
|
489
|
+
// If our current version isn't the result of an override, then prefer to
|
|
490
|
+
// take the greater version.
|
|
491
|
+
if (!this.overridden && semver.gt(other.version, this.version)) {
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
559
495
|
}
|
|
560
|
-
return true;
|
|
561
|
-
}
|
|
562
496
|
|
|
563
|
-
//
|
|
564
|
-
|
|
565
|
-
if
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
return ERROR_UX;
|
|
577
|
-
}
|
|
578
|
-
function createAlertUXLookup(settings) {
|
|
579
|
-
const cachedUX = new Map();
|
|
580
|
-
return context => {
|
|
581
|
-
const {
|
|
582
|
-
type
|
|
583
|
-
} = context.alert;
|
|
584
|
-
let ux = cachedUX.get(type);
|
|
585
|
-
if (ux) {
|
|
586
|
-
return ux;
|
|
497
|
+
// Is it safe to replace one node with another? check the edges to
|
|
498
|
+
// make sure no one will get upset. Note that the node might end up
|
|
499
|
+
// having its own unmet dependencies, if the new node has new deps.
|
|
500
|
+
// Note that there are cases where Arborist will opt to insert a node
|
|
501
|
+
// into the tree even though this function returns false! This is
|
|
502
|
+
// necessary when a root dependency is added or updated, or when a
|
|
503
|
+
// root dependency brings peer deps along with it. In that case, we
|
|
504
|
+
// will go ahead and create the invalid state, and then try to resolve
|
|
505
|
+
// it with more tree construction, because it's a user request.
|
|
506
|
+
canReplaceWith(node, ignorePeers) {
|
|
507
|
+
if (this.name !== node.name || this.packageName !== node.packageName) {
|
|
508
|
+
return false;
|
|
587
509
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
510
|
+
// Patch replacing
|
|
511
|
+
// if (node.overrides !== this.overrides) {
|
|
512
|
+
// return false
|
|
513
|
+
// }
|
|
514
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
515
|
+
//
|
|
516
|
+
// If this node has no dependencies, then it's irrelevant to check the
|
|
517
|
+
// override rules of the replacement node.
|
|
518
|
+
if (this.edgesOut.size) {
|
|
519
|
+
// XXX need to check for two root nodes?
|
|
520
|
+
if (node.overrides) {
|
|
521
|
+
if (!node.overrides.isEqual(this.overrides)) {
|
|
522
|
+
return false;
|
|
596
523
|
}
|
|
597
|
-
|
|
598
|
-
if (
|
|
599
|
-
|
|
524
|
+
} else {
|
|
525
|
+
if (this.overrides) {
|
|
526
|
+
return false;
|
|
600
527
|
}
|
|
601
|
-
target = resolvedTarget.deferTo ?? null;
|
|
602
528
|
}
|
|
603
|
-
orderedRulesCollection.push(orderedRules);
|
|
604
529
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
} else if (defaultValue && defaultValue !== true) {
|
|
614
|
-
resolvedDefaultValue = {
|
|
615
|
-
action: defaultValue.action ?? 'error'
|
|
616
|
-
};
|
|
530
|
+
// To satisfy the patch we ensure `node.overrides === this.overrides`
|
|
531
|
+
// so that the condition we want to replace,
|
|
532
|
+
// if (this.overrides !== node.overrides) {
|
|
533
|
+
// , is not hit.`
|
|
534
|
+
const oldOverrideSet = this.overrides;
|
|
535
|
+
let result = true;
|
|
536
|
+
if (oldOverrideSet !== node.overrides) {
|
|
537
|
+
this.overrides = node.overrides;
|
|
617
538
|
}
|
|
618
|
-
ux = resolveAlertRuleUX(orderedRulesCollection, resolvedDefaultValue);
|
|
619
|
-
cachedUX.set(type, ux);
|
|
620
|
-
return ux;
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
let _uxLookup;
|
|
624
|
-
async function uxLookup(settings) {
|
|
625
|
-
while (_uxLookup === undefined) {
|
|
626
|
-
// eslint-disable-next-line no-await-in-loop
|
|
627
|
-
await promises.setTimeout(1, {
|
|
628
|
-
signal: abortSignal
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
return _uxLookup(settings);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
// Start initializing the AlertUxLookupResult immediately.
|
|
635
|
-
void (async () => {
|
|
636
|
-
const {
|
|
637
|
-
orgs,
|
|
638
|
-
settings
|
|
639
|
-
} = await (async () => {
|
|
640
539
|
try {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
if (!orgResult.success) {
|
|
644
|
-
throw new Error(`Failed to fetch Socket organization info: ${orgResult.error.message}`);
|
|
645
|
-
}
|
|
646
|
-
const orgs = [];
|
|
647
|
-
for (const org of Object.values(orgResult.data.organizations)) {
|
|
648
|
-
if (org) {
|
|
649
|
-
orgs.push(org);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
const result = await sockSdk.postSettings(orgs.map(org => ({
|
|
653
|
-
organization: org.id
|
|
654
|
-
})));
|
|
655
|
-
if (!result.success) {
|
|
656
|
-
throw new Error(`Failed to fetch API key settings: ${result.error.message}`);
|
|
657
|
-
}
|
|
658
|
-
return {
|
|
659
|
-
orgs,
|
|
660
|
-
settings: result.data
|
|
661
|
-
};
|
|
540
|
+
result = super.canReplaceWith(node, ignorePeers);
|
|
541
|
+
this.overrides = oldOverrideSet;
|
|
662
542
|
} catch (e) {
|
|
663
|
-
|
|
664
|
-
if (isErrnoException(cause) && (cause.code === 'ENOTFOUND' || cause.code === 'ECONNREFUSED')) {
|
|
665
|
-
throw new Error('Unable to connect to socket.dev, ensure internet connectivity before retrying', {
|
|
666
|
-
cause: e
|
|
667
|
-
});
|
|
668
|
-
}
|
|
543
|
+
this.overrides = oldOverrideSet;
|
|
669
544
|
throw e;
|
|
670
545
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
// Remove any organizations not being enforced.
|
|
674
|
-
const enforcedOrgs = getSetting('enforcedOrgs') ?? [];
|
|
675
|
-
for (const {
|
|
676
|
-
0: i,
|
|
677
|
-
1: org
|
|
678
|
-
} of orgs.entries()) {
|
|
679
|
-
if (!enforcedOrgs.includes(org.id)) {
|
|
680
|
-
settings.entries.splice(i, 1);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
const socketYml = findSocketYmlSync();
|
|
684
|
-
if (socketYml) {
|
|
685
|
-
settings.entries.push({
|
|
686
|
-
start: socketYml.path,
|
|
687
|
-
settings: {
|
|
688
|
-
[socketYml.path]: {
|
|
689
|
-
deferTo: null,
|
|
690
|
-
// TODO: TypeScript complains about the type not matching. We should
|
|
691
|
-
// figure out why are providing
|
|
692
|
-
// issueRules: { [issueName: string]: boolean }
|
|
693
|
-
// but expecting
|
|
694
|
-
// issueRules: { [issueName: string]: { action: 'defer' | 'error' | 'ignore' | 'monitor' | 'warn' } }
|
|
695
|
-
issueRules: socketYml.parsed.issueRules
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
});
|
|
546
|
+
return result;
|
|
699
547
|
}
|
|
700
|
-
_uxLookup = createAlertUXLookup(settings);
|
|
701
|
-
})();
|
|
702
548
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
this.
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
return this.useMarkdown ? `\n${''.padStart(level, '#')} ${text}\n` : colors.underline(`\n${level === 1 ? colors.bold(text) : text}\n`);
|
|
712
|
-
}
|
|
713
|
-
hyperlink(text, url, {
|
|
714
|
-
fallback = true,
|
|
715
|
-
fallbackToUrl
|
|
716
|
-
} = {}) {
|
|
717
|
-
if (url) {
|
|
718
|
-
return this.useMarkdown ? `[${text}](${url})` : terminalLink(text, url, {
|
|
719
|
-
fallback: fallbackToUrl ? (_text, url) => url : fallback
|
|
720
|
-
});
|
|
549
|
+
// Patch adding deleteEdgeIn is based on https://github.com/npm/cli/pull/8089.
|
|
550
|
+
deleteEdgeIn(edge) {
|
|
551
|
+
this.edgesIn.delete(edge);
|
|
552
|
+
const {
|
|
553
|
+
overrides
|
|
554
|
+
} = edge;
|
|
555
|
+
if (overrides) {
|
|
556
|
+
this.updateOverridesEdgeInRemoved(overrides);
|
|
721
557
|
}
|
|
722
|
-
return text;
|
|
723
|
-
}
|
|
724
|
-
indent(...args) {
|
|
725
|
-
return indentString(...args);
|
|
726
|
-
}
|
|
727
|
-
italic(text) {
|
|
728
|
-
return this.useMarkdown ? `_${text}_` : colors.italic(`${text}`);
|
|
729
|
-
}
|
|
730
|
-
json(value) {
|
|
731
|
-
return this.useMarkdown ? '```json\n' + JSON.stringify(value) + '\n```' : JSON.stringify(value);
|
|
732
558
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
559
|
+
addEdgeIn(edge) {
|
|
560
|
+
// Patch replacing
|
|
561
|
+
// if (edge.overrides) {
|
|
562
|
+
// this.overrides = edge.overrides
|
|
563
|
+
// }
|
|
564
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
565
|
+
//
|
|
566
|
+
// We need to handle the case where the new edge in has an overrides field
|
|
567
|
+
// which is different from the current value.
|
|
568
|
+
if (!this.overrides || !this.overrides.isEqual(edge.overrides)) {
|
|
569
|
+
this.updateOverridesEdgeInAdded(edge.overrides);
|
|
570
|
+
}
|
|
571
|
+
this.edgesIn.add(edge);
|
|
572
|
+
// Try to get metadata from the yarn.lock file.
|
|
573
|
+
this.root.meta?.addEdge(edge);
|
|
736
574
|
}
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
function getSocketDevAlertUrl(alertType) {
|
|
740
|
-
return `https://socket.dev/alerts/${alertType}`;
|
|
741
|
-
}
|
|
742
|
-
function getSocketDevPackageOverviewUrl(eco, name, version) {
|
|
743
|
-
return `https://socket.dev/${eco}/package/${name}${version ? `/overview/${version}` : ''}`;
|
|
744
|
-
}
|
|
745
575
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
let id;
|
|
754
|
-
let transformer;
|
|
755
|
-
if (Array.isArray(data)) {
|
|
756
|
-
id = data[0];
|
|
757
|
-
transformer = data[1];
|
|
758
|
-
} else {
|
|
759
|
-
id = data;
|
|
760
|
-
transformer = mod => mod;
|
|
576
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
577
|
+
get overridden() {
|
|
578
|
+
// Patch replacing
|
|
579
|
+
// return !!(this.overrides && this.overrides.value && this.overrides.name === this.name)
|
|
580
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
581
|
+
if (!this.overrides || !this.overrides.value || this.overrides.name !== this.name) {
|
|
582
|
+
return false;
|
|
761
583
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
584
|
+
// The overrides rule is for a package with this name, but some override
|
|
585
|
+
// rules only apply to specific versions. To make sure this package was
|
|
586
|
+
// actually overridden, we check whether any edge going in had the rule
|
|
587
|
+
// applied to it, in which case its overrides set is different than its
|
|
588
|
+
// source node.
|
|
589
|
+
for (const edge of this.edgesIn) {
|
|
590
|
+
if (edge.overrides && edge.overrides.name === this.name && edge.overrides.value === this.version) {
|
|
591
|
+
if (!edge.overrides.isEqual(edge.from?.overrides)) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
768
594
|
}
|
|
769
|
-
}
|
|
595
|
+
}
|
|
596
|
+
return false;
|
|
770
597
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
//
|
|
778
|
-
// is really
|
|
779
|
-
|
|
598
|
+
set parent(newParent) {
|
|
599
|
+
// Patch removing
|
|
600
|
+
// if (parent.overrides) {
|
|
601
|
+
// this.overrides = parent.overrides.getNodeRule(this)
|
|
602
|
+
// }
|
|
603
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
604
|
+
//
|
|
605
|
+
// The "parent" setter is a really large and complex function. To satisfy
|
|
606
|
+
// the patch we hold on to the old overrides value and set `this.overrides`
|
|
607
|
+
// to `undefined` so that the condition we want to remove is not hit.
|
|
608
|
+
const {
|
|
609
|
+
overrides
|
|
610
|
+
} = this;
|
|
611
|
+
if (overrides) {
|
|
612
|
+
this.overrides = undefined;
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
super.parent = newParent;
|
|
616
|
+
this.overrides = overrides;
|
|
617
|
+
} catch (e) {
|
|
618
|
+
this.overrides = overrides;
|
|
619
|
+
throw e;
|
|
620
|
+
}
|
|
780
621
|
}
|
|
781
|
-
return _log;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
const OverrideSet = require(shadowNpmPaths.getArboristOverrideSetClassPath());
|
|
785
622
|
|
|
786
|
-
//
|
|
787
|
-
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/override-set.js:
|
|
788
|
-
class SafeOverrideSet extends OverrideSet {
|
|
789
|
-
// Patch adding doOverrideSetsConflict is based on
|
|
623
|
+
// Patch adding recalculateOutEdgesOverrides is based on
|
|
790
624
|
// https://github.com/npm/cli/pull/8089.
|
|
791
|
-
|
|
792
|
-
//
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
625
|
+
recalculateOutEdgesOverrides() {
|
|
626
|
+
// For each edge out propagate the new overrides through.
|
|
627
|
+
for (const edge of this.edgesOut.values()) {
|
|
628
|
+
edge.reload(true);
|
|
629
|
+
if (edge.to) {
|
|
630
|
+
edge.to.updateOverridesEdgeInAdded(edge.overrides);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
796
633
|
}
|
|
797
634
|
|
|
798
|
-
//
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
635
|
+
// @ts-ignore: Incorrectly typed to accept null.
|
|
636
|
+
set root(newRoot) {
|
|
637
|
+
// Patch removing
|
|
638
|
+
// if (!this.overrides && this.parent && this.parent.overrides) {
|
|
639
|
+
// this.overrides = this.parent.overrides.getNodeRule(this)
|
|
640
|
+
// }
|
|
641
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
642
|
+
//
|
|
643
|
+
// The "root" setter is a really large and complex function. To satisfy the
|
|
644
|
+
// patch we add a dummy value to `this.overrides` so that the condition we
|
|
645
|
+
// want to remove is not hit.
|
|
646
|
+
if (!this.overrides) {
|
|
647
|
+
this.overrides = new SafeOverrideSet({
|
|
648
|
+
overrides: ''
|
|
649
|
+
});
|
|
805
650
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
651
|
+
try {
|
|
652
|
+
super.root = newRoot;
|
|
653
|
+
this.overrides = undefined;
|
|
654
|
+
} catch (e) {
|
|
655
|
+
this.overrides = undefined;
|
|
656
|
+
throw e;
|
|
810
657
|
}
|
|
811
|
-
// The override sets are incomparable. Neither one contains the other.
|
|
812
|
-
const log = getLogger();
|
|
813
|
-
log?.silly('Conflicting override sets', first, second);
|
|
814
|
-
return undefined;
|
|
815
658
|
}
|
|
816
659
|
|
|
817
|
-
// Patch adding
|
|
818
|
-
// https://github.com/npm/cli/pull/
|
|
819
|
-
|
|
820
|
-
|
|
660
|
+
// Patch adding updateOverridesEdgeInAdded is based on
|
|
661
|
+
// https://github.com/npm/cli/pull/7025.
|
|
662
|
+
//
|
|
663
|
+
// This logic isn't perfect either. When we have two edges in that have
|
|
664
|
+
// different override sets, then we have to decide which set is correct. This
|
|
665
|
+
// function assumes the more specific override set is applicable, so if we have
|
|
666
|
+
// dependencies A->B->C and A->C and an override set that specifies what happens
|
|
667
|
+
// for C under A->B, this will work even if the new A->C edge comes along and
|
|
668
|
+
// tries to change the override set. The strictly correct logic is not to allow
|
|
669
|
+
// two edges with different overrides to point to the same node, because even
|
|
670
|
+
// if this node can satisfy both, one of its dependencies might need to be
|
|
671
|
+
// different depending on the edge leading to it. However, this might cause a
|
|
672
|
+
// lot of duplication, because the conflict in the dependencies might never
|
|
673
|
+
// actually happen.
|
|
674
|
+
updateOverridesEdgeInAdded(otherOverrideSet) {
|
|
675
|
+
if (!otherOverrideSet) {
|
|
676
|
+
// Assuming there are any overrides at all, the overrides field is never
|
|
677
|
+
// undefined for any node at the end state of the tree. So if the new edge's
|
|
678
|
+
// overrides is undefined it will be updated later. So we can wait with
|
|
679
|
+
// updating the node's overrides field.
|
|
821
680
|
return false;
|
|
822
681
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
682
|
+
if (!this.overrides) {
|
|
683
|
+
this.overrides = otherOverrideSet;
|
|
684
|
+
this.recalculateOutEdgesOverrides();
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
if (this.overrides.isEqual(otherOverrideSet)) {
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
const newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(this.overrides, otherOverrideSet);
|
|
691
|
+
if (newOverrideSet) {
|
|
692
|
+
if (this.overrides.isEqual(newOverrideSet)) {
|
|
832
693
|
return false;
|
|
833
694
|
}
|
|
834
|
-
|
|
835
|
-
|
|
695
|
+
this.overrides = newOverrideSet;
|
|
696
|
+
this.recalculateOutEdgesOverrides();
|
|
697
|
+
return true;
|
|
698
|
+
}
|
|
699
|
+
// This is an error condition. We can only get here if the new override set
|
|
700
|
+
// is in conflict with the existing.
|
|
701
|
+
const log = getLogger();
|
|
702
|
+
log?.silly('Conflicting override sets', this.name);
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Patch adding updateOverridesEdgeInRemoved is based on
|
|
707
|
+
// https://github.com/npm/cli/pull/7025.
|
|
708
|
+
updateOverridesEdgeInRemoved(otherOverrideSet) {
|
|
709
|
+
// If this edge's overrides isn't equal to this node's overrides,
|
|
710
|
+
// then removing it won't change newOverrideSet later.
|
|
711
|
+
if (!this.overrides || !this.overrides.isEqual(otherOverrideSet)) {
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
let newOverrideSet;
|
|
715
|
+
for (const edge of this.edgesIn) {
|
|
716
|
+
const {
|
|
717
|
+
overrides: edgeOverrides
|
|
718
|
+
} = edge;
|
|
719
|
+
if (newOverrideSet && edgeOverrides) {
|
|
720
|
+
newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(edgeOverrides, newOverrideSet);
|
|
721
|
+
} else {
|
|
722
|
+
newOverrideSet = edgeOverrides;
|
|
836
723
|
}
|
|
837
724
|
}
|
|
725
|
+
if (this.overrides.isEqual(newOverrideSet)) {
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
this.overrides = newOverrideSet;
|
|
729
|
+
if (newOverrideSet) {
|
|
730
|
+
// Optimization: If there's any override set at all, then no non-extraneous
|
|
731
|
+
// node has an empty override set. So if we temporarily have no override set
|
|
732
|
+
// (for example, we removed all the edges in), there's no use updating all
|
|
733
|
+
// the edges out right now. Let's just wait until we have an actual override
|
|
734
|
+
// set later.
|
|
735
|
+
this.recalculateOutEdgesOverrides();
|
|
736
|
+
}
|
|
838
737
|
return true;
|
|
839
738
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const Edge = require(shadowNpmPaths.getArboristEdgeClassPath());
|
|
742
|
+
|
|
743
|
+
// The Edge class makes heavy use of private properties which subclasses do NOT
|
|
744
|
+
// have access to. So we have to recreate any functionality that relies on those
|
|
745
|
+
// private properties and use our own "safe" prefixed non-conflicting private
|
|
746
|
+
// properties. Implementation code not related to patch https://github.com/npm/cli/pull/8089
|
|
747
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/edge.js.
|
|
748
|
+
//
|
|
749
|
+
// The npm application
|
|
750
|
+
// Copyright (c) npm, Inc. and Contributors
|
|
751
|
+
// Licensed on the terms of The Artistic License 2.0
|
|
752
|
+
//
|
|
753
|
+
// An edge in the dependency graph.
|
|
754
|
+
// Represents a dependency relationship of some kind.
|
|
755
|
+
class SafeEdge extends Edge {
|
|
756
|
+
#safeError;
|
|
757
|
+
#safeExplanation;
|
|
758
|
+
#safeFrom;
|
|
759
|
+
#safeTo;
|
|
760
|
+
constructor(options) {
|
|
761
|
+
const {
|
|
762
|
+
from
|
|
763
|
+
} = options;
|
|
764
|
+
// Defer to supper to validate options and assign non-private values.
|
|
765
|
+
super(options);
|
|
766
|
+
if (from.constructor !== SafeNode) {
|
|
767
|
+
Reflect.setPrototypeOf(from, SafeNode.prototype);
|
|
768
|
+
}
|
|
769
|
+
this.#safeError = null;
|
|
770
|
+
this.#safeExplanation = null;
|
|
771
|
+
this.#safeFrom = from;
|
|
772
|
+
this.#safeTo = null;
|
|
773
|
+
this.reload(true);
|
|
774
|
+
}
|
|
775
|
+
get bundled() {
|
|
776
|
+
return !!this.#safeFrom?.package?.bundleDependencies?.includes(this.name);
|
|
777
|
+
}
|
|
778
|
+
get error() {
|
|
779
|
+
if (!this.#safeError) {
|
|
780
|
+
if (!this.#safeTo) {
|
|
781
|
+
if (this.optional) {
|
|
782
|
+
this.#safeError = null;
|
|
783
|
+
} else {
|
|
784
|
+
this.#safeError = 'MISSING';
|
|
863
785
|
}
|
|
864
|
-
|
|
786
|
+
} else if (this.peer && this.#safeFrom === this.#safeTo.parent &&
|
|
787
|
+
// Patch adding "?." use based on
|
|
788
|
+
// https://github.com/npm/cli/pull/8089.
|
|
789
|
+
!this.#safeFrom?.isTop) {
|
|
790
|
+
this.#safeError = 'PEER LOCAL';
|
|
791
|
+
} else if (!this.satisfiedBy(this.#safeTo)) {
|
|
792
|
+
this.#safeError = 'INVALID';
|
|
865
793
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
794
|
+
// Patch adding "else if" condition is based on
|
|
795
|
+
// https://github.com/npm/cli/pull/8089.
|
|
796
|
+
else if (this.overrides && this.#safeTo.edgesOut.size && SafeOverrideSet.doOverrideSetsConflict(this.overrides, this.#safeTo.overrides)) {
|
|
797
|
+
// Any inconsistency between the edge's override set and the target's
|
|
798
|
+
// override set is potentially problematic. But we only say the edge is
|
|
799
|
+
// in error if the override sets are plainly conflicting. Note that if
|
|
800
|
+
// the target doesn't have any dependencies of their own, then this
|
|
801
|
+
// inconsistency is irrelevant.
|
|
802
|
+
this.#safeError = 'INVALID';
|
|
803
|
+
} else {
|
|
804
|
+
this.#safeError = 'OK';
|
|
871
805
|
}
|
|
872
|
-
// If we got this far, the spec type is one of tag, directory or file
|
|
873
|
-
// which means we have no real way to make version comparisons, so we
|
|
874
|
-
// just accept the override.
|
|
875
|
-
return rule;
|
|
876
|
-
}
|
|
877
|
-
return this;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
// Patch adding isEqual is based on
|
|
881
|
-
// https://github.com/npm/cli/pull/8089.
|
|
882
|
-
isEqual(otherOverrideSet) {
|
|
883
|
-
if (this === otherOverrideSet) {
|
|
884
|
-
return true;
|
|
885
|
-
}
|
|
886
|
-
if (!otherOverrideSet) {
|
|
887
|
-
return false;
|
|
888
|
-
}
|
|
889
|
-
if (this.key !== otherOverrideSet.key || this.value !== otherOverrideSet.value) {
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
if (!this.childrenAreEqual(otherOverrideSet)) {
|
|
893
|
-
return false;
|
|
894
806
|
}
|
|
895
|
-
if (
|
|
896
|
-
return
|
|
807
|
+
if (this.#safeError === 'OK') {
|
|
808
|
+
return null;
|
|
897
809
|
}
|
|
898
|
-
return this
|
|
810
|
+
return this.#safeError;
|
|
899
811
|
}
|
|
900
|
-
}
|
|
901
812
|
|
|
902
|
-
|
|
813
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
814
|
+
get from() {
|
|
815
|
+
return this.#safeFrom;
|
|
816
|
+
}
|
|
903
817
|
|
|
904
|
-
//
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
return true;
|
|
931
|
-
}
|
|
932
|
-
// If the other thing can't replace this, then skip it.
|
|
933
|
-
if (!other.canReplace(this)) {
|
|
934
|
-
return false;
|
|
818
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
819
|
+
get spec() {
|
|
820
|
+
if (this.overrides?.value && this.overrides.value !== '*' && this.overrides.name === this.name) {
|
|
821
|
+
if (this.overrides.value.startsWith('$')) {
|
|
822
|
+
const ref = this.overrides.value.slice(1);
|
|
823
|
+
// We may be a virtual root, if we are we want to resolve reference
|
|
824
|
+
// overrides from the real root, not the virtual one.
|
|
825
|
+
//
|
|
826
|
+
// Patch adding "?." use based on
|
|
827
|
+
// https://github.com/npm/cli/pull/8089.
|
|
828
|
+
const pkg = this.#safeFrom?.sourceReference ? this.#safeFrom?.sourceReference.root.package : this.#safeFrom?.root?.package;
|
|
829
|
+
if (pkg?.devDependencies?.[ref]) {
|
|
830
|
+
return pkg.devDependencies[ref];
|
|
831
|
+
}
|
|
832
|
+
if (pkg?.optionalDependencies?.[ref]) {
|
|
833
|
+
return pkg.optionalDependencies[ref];
|
|
834
|
+
}
|
|
835
|
+
if (pkg?.dependencies?.[ref]) {
|
|
836
|
+
return pkg.dependencies[ref];
|
|
837
|
+
}
|
|
838
|
+
if (pkg?.peerDependencies?.[ref]) {
|
|
839
|
+
return pkg.peerDependencies[ref];
|
|
840
|
+
}
|
|
841
|
+
throw new Error(`Unable to resolve reference ${this.overrides.value}`);
|
|
842
|
+
}
|
|
843
|
+
return this.overrides.value;
|
|
935
844
|
}
|
|
845
|
+
return this.rawSpec;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
849
|
+
get to() {
|
|
850
|
+
return this.#safeTo;
|
|
851
|
+
}
|
|
852
|
+
detach() {
|
|
853
|
+
this.#safeExplanation = null;
|
|
936
854
|
// Patch replacing
|
|
937
|
-
// if (
|
|
938
|
-
//
|
|
855
|
+
// if (this.#to) {
|
|
856
|
+
// this.#to.edgesIn.delete(this)
|
|
939
857
|
// }
|
|
858
|
+
// this.#from.edgesOut.delete(this.#name)
|
|
940
859
|
// is based on https://github.com/npm/cli/pull/8089.
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
// If our current version isn't the result of an override, then prefer to
|
|
947
|
-
// take the greater version.
|
|
948
|
-
if (!this.overridden && semver.gt(other.version, this.version)) {
|
|
949
|
-
return true;
|
|
950
|
-
}
|
|
951
|
-
return false;
|
|
860
|
+
this.#safeTo?.deleteEdgeIn(this);
|
|
861
|
+
this.#safeFrom?.edgesOut.delete(this.name);
|
|
862
|
+
this.#safeTo = null;
|
|
863
|
+
this.#safeError = 'DETACHED';
|
|
864
|
+
this.#safeFrom = null;
|
|
952
865
|
}
|
|
953
866
|
|
|
954
|
-
//
|
|
955
|
-
//
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
867
|
+
// Return the edge data, and an explanation of how that edge came to be here.
|
|
868
|
+
// @ts-ignore: Edge#explain is defined with an unused `seen = []` param.
|
|
869
|
+
explain() {
|
|
870
|
+
if (!this.#safeExplanation) {
|
|
871
|
+
const explanation = {
|
|
872
|
+
type: this.type,
|
|
873
|
+
name: this.name,
|
|
874
|
+
spec: this.spec,
|
|
875
|
+
bundled: false,
|
|
876
|
+
overridden: false,
|
|
877
|
+
error: undefined,
|
|
878
|
+
from: undefined,
|
|
879
|
+
rawSpec: undefined
|
|
880
|
+
};
|
|
881
|
+
if (this.rawSpec !== this.spec) {
|
|
882
|
+
explanation.rawSpec = this.rawSpec;
|
|
883
|
+
explanation.overridden = true;
|
|
884
|
+
}
|
|
885
|
+
if (this.bundled) {
|
|
886
|
+
explanation.bundled = this.bundled;
|
|
887
|
+
}
|
|
888
|
+
if (this.error) {
|
|
889
|
+
explanation.error = this.error;
|
|
890
|
+
}
|
|
891
|
+
if (this.#safeFrom) {
|
|
892
|
+
explanation.from = this.#safeFrom.explain();
|
|
893
|
+
}
|
|
894
|
+
this.#safeExplanation = explanation;
|
|
966
895
|
}
|
|
896
|
+
return this.#safeExplanation;
|
|
897
|
+
}
|
|
898
|
+
reload(hard = false) {
|
|
899
|
+
this.#safeExplanation = null;
|
|
967
900
|
// Patch replacing
|
|
968
|
-
// if (
|
|
969
|
-
// return false
|
|
970
|
-
// }
|
|
901
|
+
// if (this.#from.overrides) {
|
|
971
902
|
// is based on https://github.com/npm/cli/pull/8089.
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
if (this
|
|
976
|
-
|
|
977
|
-
if (
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
903
|
+
let needToUpdateOverrideSet = false;
|
|
904
|
+
let newOverrideSet;
|
|
905
|
+
let oldOverrideSet;
|
|
906
|
+
if (this.#safeFrom?.overrides) {
|
|
907
|
+
newOverrideSet = this.#safeFrom.overrides.getEdgeRule(this);
|
|
908
|
+
if (newOverrideSet && !newOverrideSet.isEqual(this.overrides)) {
|
|
909
|
+
// If there's a new different override set we need to propagate it to
|
|
910
|
+
// the nodes. If we're deleting the override set then there's no point
|
|
911
|
+
// propagating it right now since it will be filled with another value
|
|
912
|
+
// later.
|
|
913
|
+
needToUpdateOverrideSet = true;
|
|
914
|
+
oldOverrideSet = this.overrides;
|
|
915
|
+
this.overrides = newOverrideSet;
|
|
985
916
|
}
|
|
917
|
+
} else {
|
|
918
|
+
this.overrides = undefined;
|
|
986
919
|
}
|
|
987
|
-
//
|
|
988
|
-
//
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
this
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
deleteEdgeIn(edge) {
|
|
1008
|
-
this.edgesIn.delete(edge);
|
|
1009
|
-
const {
|
|
1010
|
-
overrides
|
|
1011
|
-
} = edge;
|
|
1012
|
-
if (overrides) {
|
|
1013
|
-
this.updateOverridesEdgeInRemoved(overrides);
|
|
920
|
+
// Patch adding "?." use based on
|
|
921
|
+
// https://github.com/npm/cli/pull/8089.
|
|
922
|
+
const newTo = this.#safeFrom?.resolve(this.name);
|
|
923
|
+
if (newTo !== this.#safeTo) {
|
|
924
|
+
// Patch replacing
|
|
925
|
+
// this.#to.edgesIn.delete(this)
|
|
926
|
+
// is based on https://github.com/npm/cli/pull/8089.
|
|
927
|
+
this.#safeTo?.deleteEdgeIn(this);
|
|
928
|
+
this.#safeTo = newTo ?? null;
|
|
929
|
+
this.#safeError = null;
|
|
930
|
+
this.#safeTo?.addEdgeIn(this);
|
|
931
|
+
} else if (hard) {
|
|
932
|
+
this.#safeError = null;
|
|
933
|
+
}
|
|
934
|
+
// Patch adding "else if" condition based on
|
|
935
|
+
// https://github.com/npm/cli/pull/8089.
|
|
936
|
+
else if (needToUpdateOverrideSet && this.#safeTo) {
|
|
937
|
+
// Propagate the new override set to the target node.
|
|
938
|
+
this.#safeTo.updateOverridesEdgeInRemoved(oldOverrideSet);
|
|
939
|
+
this.#safeTo.updateOverridesEdgeInAdded(newOverrideSet);
|
|
1014
940
|
}
|
|
1015
941
|
}
|
|
1016
|
-
|
|
942
|
+
satisfiedBy(node) {
|
|
1017
943
|
// Patch replacing
|
|
1018
|
-
// if (
|
|
1019
|
-
//
|
|
944
|
+
// if (node.name !== this.#name) {
|
|
945
|
+
// return false
|
|
1020
946
|
// }
|
|
1021
947
|
// is based on https://github.com/npm/cli/pull/8089.
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
948
|
+
if (node.name !== this.name || !this.#safeFrom) {
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
// NOTE: this condition means we explicitly do not support overriding
|
|
952
|
+
// bundled or shrinkwrapped dependencies
|
|
953
|
+
if (node.hasShrinkwrap || node.inShrinkwrap || node.inBundle) {
|
|
954
|
+
return depValid(node, this.rawSpec, this.accept, this.#safeFrom);
|
|
1027
955
|
}
|
|
1028
|
-
this.edgesIn.add(edge);
|
|
1029
|
-
// Try to get metadata from the yarn.lock file.
|
|
1030
|
-
this.root.meta?.addEdge(edge);
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
1034
|
-
get overridden() {
|
|
1035
956
|
// Patch replacing
|
|
1036
|
-
// return
|
|
957
|
+
// return depValid(node, this.spec, this.#accept, this.#from)
|
|
1037
958
|
// is based on https://github.com/npm/cli/pull/8089.
|
|
1038
|
-
|
|
959
|
+
//
|
|
960
|
+
// If there's no override we just use the spec.
|
|
961
|
+
if (!this.overrides?.keySpec) {
|
|
962
|
+
return depValid(node, this.spec, this.accept, this.#safeFrom);
|
|
963
|
+
}
|
|
964
|
+
// There's some override. If the target node satisfies the overriding spec
|
|
965
|
+
// then it's okay.
|
|
966
|
+
if (depValid(node, this.spec, this.accept, this.#safeFrom)) {
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
// If it doesn't, then it should at least satisfy the original spec.
|
|
970
|
+
if (!depValid(node, this.rawSpec, this.accept, this.#safeFrom)) {
|
|
1039
971
|
return false;
|
|
1040
972
|
}
|
|
1041
|
-
//
|
|
1042
|
-
//
|
|
1043
|
-
//
|
|
1044
|
-
//
|
|
1045
|
-
//
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
973
|
+
// It satisfies the original spec, not the overriding spec. We need to make
|
|
974
|
+
// sure it doesn't use the overridden spec.
|
|
975
|
+
// For example:
|
|
976
|
+
// we might have an ^8.0.0 rawSpec, and an override that makes
|
|
977
|
+
// keySpec=8.23.0 and the override value spec=9.0.0.
|
|
978
|
+
// If the node is 9.0.0, then it's okay because it's consistent with spec.
|
|
979
|
+
// If the node is 8.24.0, then it's okay because it's consistent with the rawSpec.
|
|
980
|
+
// If the node is 8.23.0, then it's not okay because even though it's consistent
|
|
981
|
+
// with the rawSpec, it's also consistent with the keySpec.
|
|
982
|
+
// So we're looking for ^8.0.0 or 9.0.0 and not 8.23.0.
|
|
983
|
+
return !depValid(node, this.overrides.keySpec, this.accept, this.#safeFrom);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
const {
|
|
988
|
+
ALERT_TYPE_CRITICAL_CVE,
|
|
989
|
+
ALERT_TYPE_CVE,
|
|
990
|
+
ALERT_TYPE_MEDIUM_CVE,
|
|
991
|
+
ALERT_TYPE_MILD_CVE,
|
|
992
|
+
ALERT_TYPE_SOCKET_UPGRADE_AVAILABLE,
|
|
993
|
+
CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER: CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER$1,
|
|
994
|
+
CVE_ALERT_PROPS_VULNERABLE_VERSION_RANGE,
|
|
995
|
+
abortSignal: abortSignal$1
|
|
996
|
+
} = constants;
|
|
997
|
+
async function* createBatchGenerator(chunk) {
|
|
998
|
+
// Adds the first 'abort' listener to abortSignal.
|
|
999
|
+
const req = https
|
|
1000
|
+
// Lazily access constants.BATCH_PURL_ENDPOINT.
|
|
1001
|
+
.request(constants.BATCH_PURL_ENDPOINT, {
|
|
1002
|
+
method: 'POST',
|
|
1003
|
+
headers: {
|
|
1004
|
+
Authorization: `Basic ${btoa(`${getPublicToken()}:`)}`
|
|
1005
|
+
}
|
|
1006
|
+
// TODO: Fix to not abort process on network abort.
|
|
1007
|
+
// signal: abortSignal
|
|
1008
|
+
}).end(JSON.stringify({
|
|
1009
|
+
components: chunk.map(id => ({
|
|
1010
|
+
purl: `pkg:npm/${id}`
|
|
1011
|
+
}))
|
|
1012
|
+
}));
|
|
1013
|
+
// Adds the second 'abort' listener to abortSignal.
|
|
1014
|
+
const {
|
|
1015
|
+
0: res
|
|
1016
|
+
} = await events.once(req, 'response', {
|
|
1017
|
+
signal: abortSignal$1
|
|
1018
|
+
});
|
|
1019
|
+
const ok = res.statusCode >= 200 && res.statusCode <= 299;
|
|
1020
|
+
if (!ok) {
|
|
1021
|
+
throw new Error(`Socket API Error: ${res.statusCode}`);
|
|
1022
|
+
}
|
|
1023
|
+
const rli = readline.createInterface({
|
|
1024
|
+
input: res,
|
|
1025
|
+
crlfDelay: Infinity,
|
|
1026
|
+
signal: abortSignal$1
|
|
1027
|
+
});
|
|
1028
|
+
for await (const line of rli) {
|
|
1029
|
+
yield JSON.parse(line);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
async function* batchScan(pkgIds, concurrencyLimit = 50) {
|
|
1033
|
+
// The createBatchGenerator method will add 2 'abort' event listeners to
|
|
1034
|
+
// abortSignal so we multiply the concurrencyLimit by 2.
|
|
1035
|
+
const neededMaxListeners = concurrencyLimit * 2;
|
|
1036
|
+
// Increase abortSignal max listeners count to avoid Node's MaxListenersExceededWarning.
|
|
1037
|
+
const oldAbortSignalMaxListeners = events.getMaxListeners(abortSignal$1);
|
|
1038
|
+
let abortSignalMaxListeners = oldAbortSignalMaxListeners;
|
|
1039
|
+
if (oldAbortSignalMaxListeners < neededMaxListeners) {
|
|
1040
|
+
abortSignalMaxListeners = oldAbortSignalMaxListeners + neededMaxListeners;
|
|
1041
|
+
events.setMaxListeners(abortSignalMaxListeners, abortSignal$1);
|
|
1042
|
+
}
|
|
1043
|
+
const {
|
|
1044
|
+
length: pkgIdsCount
|
|
1045
|
+
} = pkgIds;
|
|
1046
|
+
const running = [];
|
|
1047
|
+
let index = 0;
|
|
1048
|
+
const enqueueGen = () => {
|
|
1049
|
+
if (index >= pkgIdsCount) {
|
|
1050
|
+
// No more work to do.
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
const chunk = pkgIds.slice(index, index + 25);
|
|
1054
|
+
index += 25;
|
|
1055
|
+
const generator = createBatchGenerator(chunk);
|
|
1056
|
+
continueGen(generator);
|
|
1057
|
+
};
|
|
1058
|
+
const continueGen = generator => {
|
|
1059
|
+
let resolveFn;
|
|
1060
|
+
running.push({
|
|
1061
|
+
generator,
|
|
1062
|
+
promise: new Promise(resolve => resolveFn = resolve)
|
|
1063
|
+
});
|
|
1064
|
+
void generator.next().then(res => resolveFn({
|
|
1065
|
+
generator,
|
|
1066
|
+
iteratorResult: res
|
|
1067
|
+
}));
|
|
1068
|
+
};
|
|
1069
|
+
// Start initial batch of generators.
|
|
1070
|
+
while (running.length < concurrencyLimit && index < pkgIdsCount) {
|
|
1071
|
+
enqueueGen();
|
|
1072
|
+
}
|
|
1073
|
+
while (running.length > 0) {
|
|
1074
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1075
|
+
const {
|
|
1076
|
+
generator,
|
|
1077
|
+
iteratorResult
|
|
1078
|
+
} = await Promise.race(running.map(entry => entry.promise));
|
|
1079
|
+
// Remove generator.
|
|
1080
|
+
running.splice(running.findIndex(entry => entry.generator === generator), 1);
|
|
1081
|
+
if (iteratorResult.done) {
|
|
1082
|
+
// Start a new generator if available.
|
|
1083
|
+
enqueueGen();
|
|
1084
|
+
} else {
|
|
1085
|
+
yield iteratorResult.value;
|
|
1086
|
+
// Keep fetching values from this generator.
|
|
1087
|
+
continueGen(generator);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
// Reset abortSignal max listeners count.
|
|
1091
|
+
if (abortSignalMaxListeners > oldAbortSignalMaxListeners) {
|
|
1092
|
+
events.setMaxListeners(oldAbortSignalMaxListeners, abortSignal$1);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
function isArtifactAlertCve(alert) {
|
|
1096
|
+
const {
|
|
1097
|
+
type
|
|
1098
|
+
} = alert;
|
|
1099
|
+
return type === ALERT_TYPE_CVE || type === ALERT_TYPE_MEDIUM_CVE || type === ALERT_TYPE_MILD_CVE || type === ALERT_TYPE_CRITICAL_CVE;
|
|
1100
|
+
}
|
|
1101
|
+
function isArtifactAlertCveFixable(alert) {
|
|
1102
|
+
if (!isArtifactAlertCve(alert)) {
|
|
1103
|
+
return false;
|
|
1104
|
+
}
|
|
1105
|
+
const {
|
|
1106
|
+
props
|
|
1107
|
+
} = alert;
|
|
1108
|
+
return !!props?.[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER$1] && !!props?.[CVE_ALERT_PROPS_VULNERABLE_VERSION_RANGE];
|
|
1109
|
+
}
|
|
1110
|
+
function isArtifactAlertUpgrade(alert) {
|
|
1111
|
+
return alert.type === ALERT_TYPE_SOCKET_UPGRADE_AVAILABLE;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
const {
|
|
1115
|
+
abortSignal
|
|
1116
|
+
} = constants;
|
|
1117
|
+
const ERROR_UX = {
|
|
1118
|
+
block: true,
|
|
1119
|
+
display: true
|
|
1120
|
+
};
|
|
1121
|
+
const IGNORE_UX = {
|
|
1122
|
+
block: false,
|
|
1123
|
+
display: false
|
|
1124
|
+
};
|
|
1125
|
+
const WARN_UX = {
|
|
1126
|
+
block: false,
|
|
1127
|
+
display: true
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
// Iterates over all entries with ordered issue rule for deferral. Iterates over
|
|
1131
|
+
// all issue rules and finds the first defined value that does not defer otherwise
|
|
1132
|
+
// uses the defaultValue. Takes the value and converts into a UX workflow.
|
|
1133
|
+
function resolveAlertRuleUX(orderedRulesCollection, defaultValue) {
|
|
1134
|
+
if (defaultValue === true || defaultValue === null || defaultValue === undefined) {
|
|
1135
|
+
defaultValue = {
|
|
1136
|
+
action: 'error'
|
|
1137
|
+
};
|
|
1138
|
+
} else if (defaultValue === false) {
|
|
1139
|
+
defaultValue = {
|
|
1140
|
+
action: 'ignore'
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
let block = false;
|
|
1144
|
+
let display = false;
|
|
1145
|
+
let needDefault = true;
|
|
1146
|
+
iterate_entries: for (const rules of orderedRulesCollection) {
|
|
1147
|
+
for (const rule of rules) {
|
|
1148
|
+
if (ruleValueDoesNotDefer(rule)) {
|
|
1149
|
+
needDefault = false;
|
|
1150
|
+
const narrowingFilter = uxForDefinedNonDeferValue(rule);
|
|
1151
|
+
block = block || narrowingFilter.block;
|
|
1152
|
+
display = display || narrowingFilter.display;
|
|
1153
|
+
continue iterate_entries;
|
|
1051
1154
|
}
|
|
1052
1155
|
}
|
|
1156
|
+
const narrowingFilter = uxForDefinedNonDeferValue(defaultValue);
|
|
1157
|
+
block = block || narrowingFilter.block;
|
|
1158
|
+
display = display || narrowingFilter.display;
|
|
1159
|
+
}
|
|
1160
|
+
if (needDefault) {
|
|
1161
|
+
const narrowingFilter = uxForDefinedNonDeferValue(defaultValue);
|
|
1162
|
+
block = block || narrowingFilter.block;
|
|
1163
|
+
display = display || narrowingFilter.display;
|
|
1164
|
+
}
|
|
1165
|
+
return {
|
|
1166
|
+
block,
|
|
1167
|
+
display
|
|
1168
|
+
};
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// Negative form because it is narrowing the type.
|
|
1172
|
+
function ruleValueDoesNotDefer(rule) {
|
|
1173
|
+
if (rule === undefined) {
|
|
1053
1174
|
return false;
|
|
1054
1175
|
}
|
|
1055
|
-
|
|
1056
|
-
// Patch removing
|
|
1057
|
-
// if (parent.overrides) {
|
|
1058
|
-
// this.overrides = parent.overrides.getNodeRule(this)
|
|
1059
|
-
// }
|
|
1060
|
-
// is based on https://github.com/npm/cli/pull/8089.
|
|
1061
|
-
//
|
|
1062
|
-
// The "parent" setter is a really large and complex function. To satisfy
|
|
1063
|
-
// the patch we hold on to the old overrides value and set `this.overrides`
|
|
1064
|
-
// to `undefined` so that the condition we want to remove is not hit.
|
|
1176
|
+
if (objects.isObject(rule)) {
|
|
1065
1177
|
const {
|
|
1066
|
-
|
|
1067
|
-
} =
|
|
1068
|
-
if (
|
|
1069
|
-
|
|
1070
|
-
}
|
|
1071
|
-
try {
|
|
1072
|
-
super.parent = newParent;
|
|
1073
|
-
this.overrides = overrides;
|
|
1074
|
-
} catch (e) {
|
|
1075
|
-
this.overrides = overrides;
|
|
1076
|
-
throw e;
|
|
1178
|
+
action
|
|
1179
|
+
} = rule;
|
|
1180
|
+
if (action === undefined || action === 'defer') {
|
|
1181
|
+
return false;
|
|
1077
1182
|
}
|
|
1078
1183
|
}
|
|
1184
|
+
return true;
|
|
1185
|
+
}
|
|
1079
1186
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1187
|
+
// Handles booleans for backwards compatibility.
|
|
1188
|
+
function uxForDefinedNonDeferValue(ruleValue) {
|
|
1189
|
+
if (typeof ruleValue === 'boolean') {
|
|
1190
|
+
return ruleValue ? ERROR_UX : IGNORE_UX;
|
|
1191
|
+
}
|
|
1192
|
+
const {
|
|
1193
|
+
action
|
|
1194
|
+
} = ruleValue;
|
|
1195
|
+
if (action === 'warn') {
|
|
1196
|
+
return WARN_UX;
|
|
1197
|
+
} else if (action === 'ignore') {
|
|
1198
|
+
return IGNORE_UX;
|
|
1199
|
+
}
|
|
1200
|
+
return ERROR_UX;
|
|
1201
|
+
}
|
|
1202
|
+
function createAlertUXLookup(settings) {
|
|
1203
|
+
const cachedUX = new Map();
|
|
1204
|
+
return context => {
|
|
1205
|
+
const {
|
|
1206
|
+
type
|
|
1207
|
+
} = context.alert;
|
|
1208
|
+
let ux = cachedUX.get(type);
|
|
1209
|
+
if (ux) {
|
|
1210
|
+
return ux;
|
|
1211
|
+
}
|
|
1212
|
+
const orderedRulesCollection = [];
|
|
1213
|
+
for (const settingsEntry of settings.entries) {
|
|
1214
|
+
const orderedRules = [];
|
|
1215
|
+
let target = settingsEntry.start;
|
|
1216
|
+
while (target !== null) {
|
|
1217
|
+
const resolvedTarget = settingsEntry.settings[target];
|
|
1218
|
+
if (!resolvedTarget) {
|
|
1219
|
+
break;
|
|
1220
|
+
}
|
|
1221
|
+
const issueRuleValue = resolvedTarget.issueRules?.[type];
|
|
1222
|
+
if (typeof issueRuleValue !== 'undefined') {
|
|
1223
|
+
orderedRules.push(issueRuleValue);
|
|
1224
|
+
}
|
|
1225
|
+
target = resolvedTarget.deferTo ?? null;
|
|
1088
1226
|
}
|
|
1227
|
+
orderedRulesCollection.push(orderedRules);
|
|
1228
|
+
}
|
|
1229
|
+
const defaultValue = settings.defaults.issueRules[type];
|
|
1230
|
+
let resolvedDefaultValue = {
|
|
1231
|
+
action: 'error'
|
|
1232
|
+
};
|
|
1233
|
+
if (defaultValue === false) {
|
|
1234
|
+
resolvedDefaultValue = {
|
|
1235
|
+
action: 'ignore'
|
|
1236
|
+
};
|
|
1237
|
+
} else if (defaultValue && defaultValue !== true) {
|
|
1238
|
+
resolvedDefaultValue = {
|
|
1239
|
+
action: defaultValue.action ?? 'error'
|
|
1240
|
+
};
|
|
1089
1241
|
}
|
|
1242
|
+
ux = resolveAlertRuleUX(orderedRulesCollection, resolvedDefaultValue);
|
|
1243
|
+
cachedUX.set(type, ux);
|
|
1244
|
+
return ux;
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
let _uxLookup;
|
|
1248
|
+
async function uxLookup(settings) {
|
|
1249
|
+
while (_uxLookup === undefined) {
|
|
1250
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1251
|
+
await promises.setTimeout(1, {
|
|
1252
|
+
signal: abortSignal
|
|
1253
|
+
});
|
|
1090
1254
|
}
|
|
1255
|
+
return _uxLookup(settings);
|
|
1256
|
+
}
|
|
1091
1257
|
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
// is based on https://github.com/npm/cli/pull/8089.
|
|
1099
|
-
//
|
|
1100
|
-
// The "root" setter is a really large and complex function. To satisfy the
|
|
1101
|
-
// patch we add a dummy value to `this.overrides` so that the condition we
|
|
1102
|
-
// want to remove is not hit.
|
|
1103
|
-
if (!this.overrides) {
|
|
1104
|
-
this.overrides = new SafeOverrideSet({
|
|
1105
|
-
overrides: ''
|
|
1106
|
-
});
|
|
1107
|
-
}
|
|
1258
|
+
// Start initializing the AlertUxLookupResult immediately.
|
|
1259
|
+
void (async () => {
|
|
1260
|
+
const {
|
|
1261
|
+
orgs,
|
|
1262
|
+
settings
|
|
1263
|
+
} = await (async () => {
|
|
1108
1264
|
try {
|
|
1109
|
-
|
|
1110
|
-
|
|
1265
|
+
const sockSdk = await setupSdk(getPublicToken());
|
|
1266
|
+
const orgResult = await sockSdk.getOrganizations();
|
|
1267
|
+
if (!orgResult.success) {
|
|
1268
|
+
throw new Error(`Failed to fetch Socket organization info: ${orgResult.error.message}`);
|
|
1269
|
+
}
|
|
1270
|
+
const orgs = [];
|
|
1271
|
+
for (const org of Object.values(orgResult.data.organizations)) {
|
|
1272
|
+
if (org) {
|
|
1273
|
+
orgs.push(org);
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
const result = await sockSdk.postSettings(orgs.map(org => ({
|
|
1277
|
+
organization: org.id
|
|
1278
|
+
})));
|
|
1279
|
+
if (!result.success) {
|
|
1280
|
+
throw new Error(`Failed to fetch API key settings: ${result.error.message}`);
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
orgs,
|
|
1284
|
+
settings: result.data
|
|
1285
|
+
};
|
|
1111
1286
|
} catch (e) {
|
|
1112
|
-
|
|
1287
|
+
const cause = objects.isObject(e) && 'cause' in e ? e['cause'] : undefined;
|
|
1288
|
+
if (isErrnoException(cause) && (cause.code === 'ENOTFOUND' || cause.code === 'ECONNREFUSED')) {
|
|
1289
|
+
throw new Error('Unable to connect to socket.dev, ensure internet connectivity before retrying', {
|
|
1290
|
+
cause: e
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1113
1293
|
throw e;
|
|
1114
1294
|
}
|
|
1115
|
-
}
|
|
1295
|
+
})();
|
|
1116
1296
|
|
|
1117
|
-
//
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
// tries to change the override set. The strictly correct logic is not to allow
|
|
1126
|
-
// two edges with different overrides to point to the same node, because even
|
|
1127
|
-
// if this node can satisfy both, one of its dependencies might need to be
|
|
1128
|
-
// different depending on the edge leading to it. However, this might cause a
|
|
1129
|
-
// lot of duplication, because the conflict in the dependencies might never
|
|
1130
|
-
// actually happen.
|
|
1131
|
-
updateOverridesEdgeInAdded(otherOverrideSet) {
|
|
1132
|
-
if (!otherOverrideSet) {
|
|
1133
|
-
// Assuming there are any overrides at all, the overrides field is never
|
|
1134
|
-
// undefined for any node at the end state of the tree. So if the new edge's
|
|
1135
|
-
// overrides is undefined it will be updated later. So we can wait with
|
|
1136
|
-
// updating the node's overrides field.
|
|
1137
|
-
return false;
|
|
1138
|
-
}
|
|
1139
|
-
if (!this.overrides) {
|
|
1140
|
-
this.overrides = otherOverrideSet;
|
|
1141
|
-
this.recalculateOutEdgesOverrides();
|
|
1142
|
-
return true;
|
|
1143
|
-
}
|
|
1144
|
-
if (this.overrides.isEqual(otherOverrideSet)) {
|
|
1145
|
-
return false;
|
|
1146
|
-
}
|
|
1147
|
-
const newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(this.overrides, otherOverrideSet);
|
|
1148
|
-
if (newOverrideSet) {
|
|
1149
|
-
if (this.overrides.isEqual(newOverrideSet)) {
|
|
1150
|
-
return false;
|
|
1151
|
-
}
|
|
1152
|
-
this.overrides = newOverrideSet;
|
|
1153
|
-
this.recalculateOutEdgesOverrides();
|
|
1154
|
-
return true;
|
|
1297
|
+
// Remove any organizations not being enforced.
|
|
1298
|
+
const enforcedOrgs = getSetting('enforcedOrgs') ?? [];
|
|
1299
|
+
for (const {
|
|
1300
|
+
0: i,
|
|
1301
|
+
1: org
|
|
1302
|
+
} of orgs.entries()) {
|
|
1303
|
+
if (!enforcedOrgs.includes(org.id)) {
|
|
1304
|
+
settings.entries.splice(i, 1);
|
|
1155
1305
|
}
|
|
1156
|
-
// This is an error condition. We can only get here if the new override set
|
|
1157
|
-
// is in conflict with the existing.
|
|
1158
|
-
const log = getLogger();
|
|
1159
|
-
log?.silly('Conflicting override sets', this.name);
|
|
1160
|
-
return false;
|
|
1161
1306
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
if (newOverrideSet) {
|
|
1187
|
-
// Optimization: If there's any override set at all, then no non-extraneous
|
|
1188
|
-
// node has an empty override set. So if we temporarily have no override set
|
|
1189
|
-
// (for example, we removed all the edges in), there's no use updating all
|
|
1190
|
-
// the edges out right now. Let's just wait until we have an actual override
|
|
1191
|
-
// set later.
|
|
1192
|
-
this.recalculateOutEdgesOverrides();
|
|
1193
|
-
}
|
|
1194
|
-
return true;
|
|
1307
|
+
const socketYml = findSocketYmlSync();
|
|
1308
|
+
if (socketYml) {
|
|
1309
|
+
settings.entries.push({
|
|
1310
|
+
start: socketYml.path,
|
|
1311
|
+
settings: {
|
|
1312
|
+
[socketYml.path]: {
|
|
1313
|
+
deferTo: null,
|
|
1314
|
+
// TODO: TypeScript complains about the type not matching. We should
|
|
1315
|
+
// figure out why are providing
|
|
1316
|
+
// issueRules: { [issueName: string]: boolean }
|
|
1317
|
+
// but expecting
|
|
1318
|
+
// issueRules: { [issueName: string]: { action: 'defer' | 'error' | 'ignore' | 'monitor' | 'warn' } }
|
|
1319
|
+
issueRules: socketYml.parsed.issueRules
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1324
|
+
_uxLookup = createAlertUXLookup(settings);
|
|
1325
|
+
})();
|
|
1326
|
+
|
|
1327
|
+
function pick(input, keys) {
|
|
1328
|
+
const result = {};
|
|
1329
|
+
for (const key of keys) {
|
|
1330
|
+
result[key] = input[key];
|
|
1195
1331
|
}
|
|
1332
|
+
return result;
|
|
1196
1333
|
}
|
|
1197
1334
|
|
|
1198
|
-
|
|
1335
|
+
function stringJoinWithSeparateFinalSeparator(list, separator = ' and ') {
|
|
1336
|
+
const values = list.filter(Boolean);
|
|
1337
|
+
const {
|
|
1338
|
+
length
|
|
1339
|
+
} = values;
|
|
1340
|
+
if (!length) {
|
|
1341
|
+
return '';
|
|
1342
|
+
}
|
|
1343
|
+
if (length === 1) {
|
|
1344
|
+
return values[0];
|
|
1345
|
+
}
|
|
1346
|
+
const finalValue = values.pop();
|
|
1347
|
+
return `${values.join(', ')}${separator}${finalValue}`;
|
|
1348
|
+
}
|
|
1199
1349
|
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
//
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
#safeTo;
|
|
1217
|
-
constructor(options) {
|
|
1218
|
-
const {
|
|
1219
|
-
from
|
|
1220
|
-
} = options;
|
|
1221
|
-
// Defer to supper to validate options and assign non-private values.
|
|
1222
|
-
super(options);
|
|
1223
|
-
if (from.constructor !== SafeNode) {
|
|
1224
|
-
Reflect.setPrototypeOf(from, SafeNode.prototype);
|
|
1350
|
+
let SEVERITY = /*#__PURE__*/function (SEVERITY) {
|
|
1351
|
+
SEVERITY["critical"] = "critical";
|
|
1352
|
+
SEVERITY["high"] = "high";
|
|
1353
|
+
SEVERITY["middle"] = "middle";
|
|
1354
|
+
SEVERITY["low"] = "low";
|
|
1355
|
+
return SEVERITY;
|
|
1356
|
+
}({});
|
|
1357
|
+
|
|
1358
|
+
// Ordered from most severe to least.
|
|
1359
|
+
const SEVERITIES_BY_ORDER = ['critical', 'high', 'middle', 'low'];
|
|
1360
|
+
function getDesiredSeverities(lowestToInclude) {
|
|
1361
|
+
const result = [];
|
|
1362
|
+
for (const severity of SEVERITIES_BY_ORDER) {
|
|
1363
|
+
result.push(severity);
|
|
1364
|
+
if (severity === lowestToInclude) {
|
|
1365
|
+
break;
|
|
1225
1366
|
}
|
|
1226
|
-
this.#safeError = null;
|
|
1227
|
-
this.#safeExplanation = null;
|
|
1228
|
-
this.#safeFrom = from;
|
|
1229
|
-
this.#safeTo = null;
|
|
1230
|
-
this.reload(true);
|
|
1231
1367
|
}
|
|
1232
|
-
|
|
1233
|
-
|
|
1368
|
+
return result;
|
|
1369
|
+
}
|
|
1370
|
+
function formatSeverityCount(severityCount) {
|
|
1371
|
+
const summary = [];
|
|
1372
|
+
for (const severity of SEVERITIES_BY_ORDER) {
|
|
1373
|
+
if (severityCount[severity]) {
|
|
1374
|
+
summary.push(`${severityCount[severity]} ${severity}`);
|
|
1375
|
+
}
|
|
1234
1376
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
}
|
|
1251
|
-
// Patch adding "else if" condition is based on
|
|
1252
|
-
// https://github.com/npm/cli/pull/8089.
|
|
1253
|
-
else if (this.overrides && this.#safeTo.edgesOut.size && SafeOverrideSet.doOverrideSetsConflict(this.overrides, this.#safeTo.overrides)) {
|
|
1254
|
-
// Any inconsistency between the edge's override set and the target's
|
|
1255
|
-
// override set is potentially problematic. But we only say the edge is
|
|
1256
|
-
// in error if the override sets are plainly conflicting. Note that if
|
|
1257
|
-
// the target doesn't have any dependencies of their own, then this
|
|
1258
|
-
// inconsistency is irrelevant.
|
|
1259
|
-
this.#safeError = 'INVALID';
|
|
1260
|
-
} else {
|
|
1261
|
-
this.#safeError = 'OK';
|
|
1262
|
-
}
|
|
1377
|
+
return stringJoinWithSeparateFinalSeparator(summary);
|
|
1378
|
+
}
|
|
1379
|
+
function getSeverityCount(issues, lowestToInclude) {
|
|
1380
|
+
const severityCount = pick({
|
|
1381
|
+
low: 0,
|
|
1382
|
+
middle: 0,
|
|
1383
|
+
high: 0,
|
|
1384
|
+
critical: 0
|
|
1385
|
+
}, getDesiredSeverities(lowestToInclude));
|
|
1386
|
+
for (const issue of issues) {
|
|
1387
|
+
const {
|
|
1388
|
+
value
|
|
1389
|
+
} = issue;
|
|
1390
|
+
if (!value) {
|
|
1391
|
+
continue;
|
|
1263
1392
|
}
|
|
1264
|
-
if (
|
|
1265
|
-
|
|
1393
|
+
if (severityCount[value.severity] !== undefined) {
|
|
1394
|
+
severityCount[value.severity] += 1;
|
|
1266
1395
|
}
|
|
1267
|
-
return this.#safeError;
|
|
1268
1396
|
}
|
|
1397
|
+
return severityCount;
|
|
1398
|
+
}
|
|
1269
1399
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1400
|
+
class ColorOrMarkdown {
|
|
1401
|
+
constructor(useMarkdown) {
|
|
1402
|
+
this.useMarkdown = !!useMarkdown;
|
|
1273
1403
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
}
|
|
1289
|
-
if (pkg?.optionalDependencies?.[ref]) {
|
|
1290
|
-
return pkg.optionalDependencies[ref];
|
|
1291
|
-
}
|
|
1292
|
-
if (pkg?.dependencies?.[ref]) {
|
|
1293
|
-
return pkg.dependencies[ref];
|
|
1294
|
-
}
|
|
1295
|
-
if (pkg?.peerDependencies?.[ref]) {
|
|
1296
|
-
return pkg.peerDependencies[ref];
|
|
1297
|
-
}
|
|
1298
|
-
throw new Error(`Unable to resolve reference ${this.overrides.value}`);
|
|
1299
|
-
}
|
|
1300
|
-
return this.overrides.value;
|
|
1404
|
+
bold(text) {
|
|
1405
|
+
return this.useMarkdown ? `**${text}**` : colors.bold(`${text}`);
|
|
1406
|
+
}
|
|
1407
|
+
header(text, level = 1) {
|
|
1408
|
+
return this.useMarkdown ? `\n${''.padStart(level, '#')} ${text}\n` : colors.underline(`\n${level === 1 ? colors.bold(text) : text}\n`);
|
|
1409
|
+
}
|
|
1410
|
+
hyperlink(text, url, {
|
|
1411
|
+
fallback = true,
|
|
1412
|
+
fallbackToUrl
|
|
1413
|
+
} = {}) {
|
|
1414
|
+
if (url) {
|
|
1415
|
+
return this.useMarkdown ? `[${text}](${url})` : terminalLink(text, url, {
|
|
1416
|
+
fallback: fallbackToUrl ? (_text, url) => url : fallback
|
|
1417
|
+
});
|
|
1301
1418
|
}
|
|
1302
|
-
return
|
|
1419
|
+
return text;
|
|
1303
1420
|
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
get to() {
|
|
1307
|
-
return this.#safeTo;
|
|
1421
|
+
indent(...args) {
|
|
1422
|
+
return indentString(...args);
|
|
1308
1423
|
}
|
|
1309
|
-
|
|
1310
|
-
this
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
this
|
|
1318
|
-
this.#safeFrom?.edgesOut.delete(this.name);
|
|
1319
|
-
this.#safeTo = null;
|
|
1320
|
-
this.#safeError = 'DETACHED';
|
|
1321
|
-
this.#safeFrom = null;
|
|
1424
|
+
italic(text) {
|
|
1425
|
+
return this.useMarkdown ? `_${text}_` : colors.italic(`${text}`);
|
|
1426
|
+
}
|
|
1427
|
+
json(value) {
|
|
1428
|
+
return this.useMarkdown ? '```json\n' + JSON.stringify(value) + '\n```' : JSON.stringify(value);
|
|
1429
|
+
}
|
|
1430
|
+
list(items) {
|
|
1431
|
+
const indentedContent = items.map(item => this.indent(item).trimStart());
|
|
1432
|
+
return this.useMarkdown ? `* ${indentedContent.join('\n* ')}\n` : `${indentedContent.join('\n')}\n`;
|
|
1322
1433
|
}
|
|
1434
|
+
}
|
|
1323
1435
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
};
|
|
1338
|
-
if (this.rawSpec !== this.spec) {
|
|
1339
|
-
explanation.rawSpec = this.rawSpec;
|
|
1340
|
-
explanation.overridden = true;
|
|
1341
|
-
}
|
|
1342
|
-
if (this.bundled) {
|
|
1343
|
-
explanation.bundled = this.bundled;
|
|
1344
|
-
}
|
|
1345
|
-
if (this.error) {
|
|
1346
|
-
explanation.error = this.error;
|
|
1347
|
-
}
|
|
1348
|
-
if (this.#safeFrom) {
|
|
1349
|
-
explanation.from = this.#safeFrom.explain();
|
|
1350
|
-
}
|
|
1351
|
-
this.#safeExplanation = explanation;
|
|
1352
|
-
}
|
|
1353
|
-
return this.#safeExplanation;
|
|
1436
|
+
function getSocketDevAlertUrl(alertType) {
|
|
1437
|
+
return `https://socket.dev/alerts/${alertType}`;
|
|
1438
|
+
}
|
|
1439
|
+
function getSocketDevPackageOverviewUrl(eco, name, version) {
|
|
1440
|
+
return `https://socket.dev/${eco}/package/${name}${version ? `/overview/${version}` : ''}`;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
let _translations;
|
|
1444
|
+
function getTranslations() {
|
|
1445
|
+
if (_translations === undefined) {
|
|
1446
|
+
_translations = require(
|
|
1447
|
+
// Lazily access constants.rootPath.
|
|
1448
|
+
path.join(constants.rootPath, 'translations.json'));
|
|
1354
1449
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
//
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1450
|
+
return _translations;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
const {
|
|
1454
|
+
CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER,
|
|
1455
|
+
NPM: NPM$1
|
|
1456
|
+
} = constants;
|
|
1457
|
+
const format = new ColorOrMarkdown(false);
|
|
1458
|
+
async function addArtifactToAlertsMap(artifact, alertsByPkgId, options) {
|
|
1459
|
+
// Make TypeScript happy.
|
|
1460
|
+
if (!artifact.name || !artifact.version || !artifact.alerts?.length) {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
const {
|
|
1464
|
+
consolidate = false,
|
|
1465
|
+
include: _include,
|
|
1466
|
+
overrides
|
|
1467
|
+
} = {
|
|
1468
|
+
__proto__: null,
|
|
1469
|
+
...options
|
|
1470
|
+
};
|
|
1471
|
+
const include = {
|
|
1472
|
+
__proto__: null,
|
|
1473
|
+
critical: true,
|
|
1474
|
+
cve: true,
|
|
1475
|
+
unfixable: true,
|
|
1476
|
+
upgrade: false,
|
|
1477
|
+
..._include
|
|
1478
|
+
};
|
|
1479
|
+
const name = packages.resolvePackageName(artifact);
|
|
1480
|
+
const {
|
|
1481
|
+
version
|
|
1482
|
+
} = artifact;
|
|
1483
|
+
const pkgId = `${name}@${version}`;
|
|
1484
|
+
const major = semver.major(version);
|
|
1485
|
+
let sockPkgAlerts = [];
|
|
1486
|
+
for (const alert of artifact.alerts) {
|
|
1487
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1488
|
+
const ux = await uxLookup({
|
|
1489
|
+
package: {
|
|
1490
|
+
name,
|
|
1491
|
+
version
|
|
1492
|
+
},
|
|
1493
|
+
alert: {
|
|
1494
|
+
type: alert.type
|
|
1495
|
+
}
|
|
1496
|
+
});
|
|
1497
|
+
const critical = alert.severity === SEVERITY.critical;
|
|
1498
|
+
const cve = isArtifactAlertCve(alert);
|
|
1499
|
+
const fixableCve = isArtifactAlertCveFixable(alert);
|
|
1500
|
+
const fixableUpgrade = isArtifactAlertUpgrade(alert);
|
|
1501
|
+
const fixable = fixableCve || fixableUpgrade;
|
|
1502
|
+
const upgrade = fixableUpgrade && !objects.hasOwn(overrides, name);
|
|
1503
|
+
if (include.cve && cve || include.unfixable && !fixable || include.critical && critical || include.upgrade && upgrade) {
|
|
1504
|
+
sockPkgAlerts.push({
|
|
1505
|
+
name,
|
|
1506
|
+
version,
|
|
1507
|
+
key: alert.key,
|
|
1508
|
+
type: alert.type,
|
|
1509
|
+
block: ux.block,
|
|
1510
|
+
critical,
|
|
1511
|
+
display: ux.display,
|
|
1512
|
+
fixable,
|
|
1513
|
+
raw: alert,
|
|
1514
|
+
upgrade
|
|
1515
|
+
});
|
|
1397
1516
|
}
|
|
1398
1517
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1518
|
+
if (!sockPkgAlerts.length) {
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1521
|
+
if (consolidate) {
|
|
1522
|
+
const highestForCve = new Map();
|
|
1523
|
+
const highestForUpgrade = new Map();
|
|
1524
|
+
const unfixableAlerts = [];
|
|
1525
|
+
for (const sockPkgAlert of sockPkgAlerts) {
|
|
1526
|
+
if (isArtifactAlertCveFixable(sockPkgAlert.raw)) {
|
|
1527
|
+
const patchedVersion = sockPkgAlert.raw.props[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER];
|
|
1528
|
+
const patchedMajor = semver.major(patchedVersion);
|
|
1529
|
+
const oldHighest = highestForCve.get(patchedMajor);
|
|
1530
|
+
const highest = oldHighest?.version ?? '0.0.0';
|
|
1531
|
+
if (semver.gt(patchedVersion, highest)) {
|
|
1532
|
+
highestForCve.set(patchedMajor, {
|
|
1533
|
+
alert: sockPkgAlert,
|
|
1534
|
+
version: patchedVersion
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
} else if (isArtifactAlertUpgrade(sockPkgAlert.raw)) {
|
|
1538
|
+
const oldHighest = highestForUpgrade.get(major);
|
|
1539
|
+
const highest = oldHighest?.version ?? '0.0.0';
|
|
1540
|
+
if (semver.gt(version, highest)) {
|
|
1541
|
+
highestForUpgrade.set(major, {
|
|
1542
|
+
alert: sockPkgAlert,
|
|
1543
|
+
version
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
} else {
|
|
1547
|
+
unfixableAlerts.push(sockPkgAlert);
|
|
1548
|
+
}
|
|
1420
1549
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1550
|
+
sockPkgAlerts = [...unfixableAlerts, ...[...highestForCve.values()].map(d => d.alert), ...[...highestForUpgrade.values()].map(d => d.alert)];
|
|
1551
|
+
}
|
|
1552
|
+
if (!sockPkgAlerts.length) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
sockPkgAlerts.sort((a, b) => sorts.naturalCompare(a.type, b.type));
|
|
1556
|
+
alertsByPkgId.set(pkgId, sockPkgAlerts);
|
|
1557
|
+
}
|
|
1558
|
+
function getCveInfoByAlertsMap(alertsMap, options) {
|
|
1559
|
+
const exclude = {
|
|
1560
|
+
upgrade: true,
|
|
1561
|
+
...{
|
|
1562
|
+
__proto__: null,
|
|
1563
|
+
...options
|
|
1564
|
+
}.exclude
|
|
1565
|
+
};
|
|
1566
|
+
let infoByPkg = null;
|
|
1567
|
+
for (const [pkgId, alerts] of alertsMap) {
|
|
1568
|
+
const purlObj = packageurlJs.PackageURL.fromString(`pkg:npm/${pkgId}`);
|
|
1569
|
+
const name = packages.resolvePackageName(purlObj);
|
|
1570
|
+
for (const alert of alerts) {
|
|
1571
|
+
if (!isArtifactAlertCveFixable(alert.raw) || exclude.upgrade && registry.getManifestData(NPM$1, name)) {
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (!infoByPkg) {
|
|
1575
|
+
infoByPkg = new Map();
|
|
1576
|
+
}
|
|
1577
|
+
let infos = infoByPkg.get(name);
|
|
1578
|
+
if (!infos) {
|
|
1579
|
+
infos = [];
|
|
1580
|
+
infoByPkg.set(name, infos);
|
|
1581
|
+
}
|
|
1582
|
+
const {
|
|
1583
|
+
firstPatchedVersionIdentifier,
|
|
1584
|
+
vulnerableVersionRange
|
|
1585
|
+
} = alert.raw.props;
|
|
1586
|
+
infos.push({
|
|
1587
|
+
firstPatchedVersionIdentifier,
|
|
1588
|
+
vulnerableVersionRange: new semver.Range(vulnerableVersionRange).format()
|
|
1589
|
+
});
|
|
1425
1590
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1591
|
+
}
|
|
1592
|
+
return infoByPkg;
|
|
1593
|
+
}
|
|
1594
|
+
function logAlertsMap(alertsMap, options) {
|
|
1595
|
+
const {
|
|
1596
|
+
output = process.stderr
|
|
1597
|
+
} = {
|
|
1598
|
+
__proto__: null,
|
|
1599
|
+
...options
|
|
1600
|
+
};
|
|
1601
|
+
const translations = getTranslations();
|
|
1602
|
+
for (const [pkgId, alerts] of alertsMap) {
|
|
1603
|
+
const purlObj = packageurlJs.PackageURL.fromString(`pkg:npm/${pkgId}`);
|
|
1604
|
+
const lines = new Set();
|
|
1605
|
+
for (const alert of alerts) {
|
|
1606
|
+
const {
|
|
1607
|
+
type
|
|
1608
|
+
} = alert;
|
|
1609
|
+
const attributes = [...(alert.fixable ? ['fixable'] : []), ...(alert.block ? [] : ['non-blocking'])];
|
|
1610
|
+
const maybeAttributes = attributes.length ? ` (${attributes.join('; ')})` : '';
|
|
1611
|
+
// Based data from { pageProps: { alertTypes } } of:
|
|
1612
|
+
// https://socket.dev/_next/data/94666139314b6437ee4491a0864e72b264547585/en-US.json
|
|
1613
|
+
const info = translations.alerts[type];
|
|
1614
|
+
const title = info?.title ?? type;
|
|
1615
|
+
const maybeDesc = info?.description ? ` - ${info.description}` : '';
|
|
1616
|
+
// TODO: emoji seems to mis-align terminals sometimes
|
|
1617
|
+
lines.add(` ${title}${maybeAttributes}${maybeDesc}`);
|
|
1618
|
+
}
|
|
1619
|
+
output.write(`(socket) ${format.hyperlink(pkgId, getSocketDevPackageOverviewUrl(NPM$1, packages.resolvePackageName(purlObj), purlObj.version))} contains risks:\n`);
|
|
1620
|
+
for (const line of lines) {
|
|
1621
|
+
output.write(`${line}\n`);
|
|
1429
1622
|
}
|
|
1430
|
-
// It satisfies the original spec, not the overriding spec. We need to make
|
|
1431
|
-
// sure it doesn't use the overridden spec.
|
|
1432
|
-
// For example:
|
|
1433
|
-
// we might have an ^8.0.0 rawSpec, and an override that makes
|
|
1434
|
-
// keySpec=8.23.0 and the override value spec=9.0.0.
|
|
1435
|
-
// If the node is 9.0.0, then it's okay because it's consistent with spec.
|
|
1436
|
-
// If the node is 8.24.0, then it's okay because it's consistent with the rawSpec.
|
|
1437
|
-
// If the node is 8.23.0, then it's not okay because even though it's consistent
|
|
1438
|
-
// with the rawSpec, it's also consistent with the keySpec.
|
|
1439
|
-
// So we're looking for ^8.0.0 or 9.0.0 and not 8.23.0.
|
|
1440
|
-
return !depValid(node, this.overrides.keySpec, this.accept, this.#safeFrom);
|
|
1441
1623
|
}
|
|
1442
1624
|
}
|
|
1443
1625
|
|
|
1444
1626
|
const {
|
|
1445
|
-
CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER,
|
|
1446
1627
|
LOOP_SENTINEL,
|
|
1447
1628
|
NPM,
|
|
1448
|
-
NPM_REGISTRY_URL
|
|
1449
|
-
OVERRIDES,
|
|
1450
|
-
PNPM,
|
|
1451
|
-
RESOLUTIONS
|
|
1629
|
+
NPM_REGISTRY_URL
|
|
1452
1630
|
} = constants;
|
|
1453
|
-
|
|
1631
|
+
function getDetailsFromDiff(diff_, options) {
|
|
1632
|
+
const details = [];
|
|
1633
|
+
// `diff_` is `null` when `npm install --package-lock-only` is passed.
|
|
1634
|
+
if (!diff_) {
|
|
1635
|
+
return details;
|
|
1636
|
+
}
|
|
1637
|
+
const include = {
|
|
1638
|
+
__proto__: null,
|
|
1639
|
+
unchanged: false,
|
|
1640
|
+
unknownOrigin: false,
|
|
1641
|
+
...{
|
|
1642
|
+
__proto__: null,
|
|
1643
|
+
...options
|
|
1644
|
+
}.include
|
|
1645
|
+
};
|
|
1646
|
+
const queue = [...diff_.children];
|
|
1647
|
+
let pos = 0;
|
|
1648
|
+
let {
|
|
1649
|
+
length: queueLength
|
|
1650
|
+
} = queue;
|
|
1651
|
+
while (pos < queueLength) {
|
|
1652
|
+
if (pos === LOOP_SENTINEL) {
|
|
1653
|
+
throw new Error('Detected infinite loop while walking Arborist diff');
|
|
1654
|
+
}
|
|
1655
|
+
const diff = queue[pos++];
|
|
1656
|
+
const {
|
|
1657
|
+
action
|
|
1658
|
+
} = diff;
|
|
1659
|
+
if (action) {
|
|
1660
|
+
// The `pkgNode`, i.e. the `ideal` node, will be `undefined` if the diff
|
|
1661
|
+
// action is 'REMOVE'
|
|
1662
|
+
// The `oldNode`, i.e. the `actual` node, will be `undefined` if the diff
|
|
1663
|
+
// action is 'ADD'.
|
|
1664
|
+
const {
|
|
1665
|
+
actual: oldNode,
|
|
1666
|
+
ideal: pkgNode
|
|
1667
|
+
} = diff;
|
|
1668
|
+
let existing;
|
|
1669
|
+
let keep = false;
|
|
1670
|
+
if (action === DiffAction.change) {
|
|
1671
|
+
if (pkgNode?.package.version !== oldNode?.package.version) {
|
|
1672
|
+
keep = true;
|
|
1673
|
+
if (oldNode?.package.name && oldNode.package.name === pkgNode?.package.name) {
|
|
1674
|
+
existing = oldNode;
|
|
1675
|
+
}
|
|
1676
|
+
} else {
|
|
1677
|
+
debug.debugLog('SKIPPING META CHANGE ON', diff);
|
|
1678
|
+
}
|
|
1679
|
+
} else {
|
|
1680
|
+
keep = action !== DiffAction.remove;
|
|
1681
|
+
}
|
|
1682
|
+
if (keep && pkgNode?.resolved && (!oldNode || oldNode.resolved)) {
|
|
1683
|
+
if (include.unknownOrigin || getUrlOrigin(pkgNode.resolved) === NPM_REGISTRY_URL) {
|
|
1684
|
+
details.push({
|
|
1685
|
+
node: pkgNode,
|
|
1686
|
+
existing
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
for (const child of diff.children) {
|
|
1692
|
+
queue[queueLength++] = child;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
if (include.unchanged) {
|
|
1696
|
+
const {
|
|
1697
|
+
unchanged
|
|
1698
|
+
} = diff_;
|
|
1699
|
+
for (let i = 0, {
|
|
1700
|
+
length
|
|
1701
|
+
} = unchanged; i < length; i += 1) {
|
|
1702
|
+
const pkgNode = unchanged[i];
|
|
1703
|
+
if (include.unknownOrigin || getUrlOrigin(pkgNode.resolved) === NPM_REGISTRY_URL) {
|
|
1704
|
+
details.push({
|
|
1705
|
+
node: pkgNode,
|
|
1706
|
+
existing: pkgNode
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
return details;
|
|
1712
|
+
}
|
|
1713
|
+
function getUrlOrigin(input) {
|
|
1714
|
+
try {
|
|
1715
|
+
return URL.parse(input)?.origin ?? '';
|
|
1716
|
+
} catch {}
|
|
1717
|
+
return '';
|
|
1718
|
+
}
|
|
1454
1719
|
function findBestPatchVersion(node, availableVersions, vulnerableVersionRange, _firstPatchedVersionIdentifier) {
|
|
1455
1720
|
const manifestData = registry.getManifestData(NPM, node.name);
|
|
1456
1721
|
let eligibleVersions;
|
|
@@ -1460,8 +1725,8 @@ function findBestPatchVersion(node, availableVersions, vulnerableVersionRange, _
|
|
|
1460
1725
|
} else {
|
|
1461
1726
|
const major = semver.major(node.version);
|
|
1462
1727
|
eligibleVersions = availableVersions.filter(v =>
|
|
1463
|
-
// Filter for versions that are within the current major version
|
|
1464
|
-
//
|
|
1728
|
+
// Filter for versions that are within the current major version and
|
|
1729
|
+
// are NOT in the vulnerable range.
|
|
1465
1730
|
semver.major(v) === major && (!vulnerableVersionRange || !semver.satisfies(v, vulnerableVersionRange)));
|
|
1466
1731
|
}
|
|
1467
1732
|
return semver.maxSatisfying(eligibleVersions, '*');
|
|
@@ -1492,17 +1757,55 @@ function findPackageNodes(tree, packageName) {
|
|
|
1492
1757
|
}
|
|
1493
1758
|
return matches;
|
|
1494
1759
|
}
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1760
|
+
async function getAlertsMapFromArborist(arb, options) {
|
|
1761
|
+
const {
|
|
1762
|
+
include: _include,
|
|
1763
|
+
spinner
|
|
1764
|
+
} = {
|
|
1765
|
+
__proto__: null,
|
|
1766
|
+
...options
|
|
1767
|
+
};
|
|
1768
|
+
const include = {
|
|
1769
|
+
__proto__: null,
|
|
1770
|
+
existing: false,
|
|
1771
|
+
..._include
|
|
1772
|
+
};
|
|
1773
|
+
const needInfoOn = getDetailsFromDiff(arb.diff, {
|
|
1774
|
+
include: {
|
|
1775
|
+
unchanged: include.existing
|
|
1776
|
+
}
|
|
1777
|
+
});
|
|
1778
|
+
const pkgIds = arrays.arrayUnique(needInfoOn.map(d => d.node.pkgid));
|
|
1779
|
+
let {
|
|
1780
|
+
length: remaining
|
|
1781
|
+
} = pkgIds;
|
|
1782
|
+
const alertsByPkgId = new Map();
|
|
1783
|
+
if (!remaining) {
|
|
1784
|
+
return alertsByPkgId;
|
|
1501
1785
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1786
|
+
const getText = () => `Looking up data for ${remaining} packages`;
|
|
1787
|
+
spinner?.start(getText());
|
|
1788
|
+
let overrides;
|
|
1789
|
+
const overridesMap = (arb.actualTree ?? arb.idealTree ?? (await arb.loadActual()))?.overrides?.children;
|
|
1790
|
+
if (overridesMap) {
|
|
1791
|
+
overrides = Object.fromEntries([...overridesMap.entries()].map(([key, overrideSet]) => {
|
|
1792
|
+
return [key, overrideSet.value];
|
|
1793
|
+
}));
|
|
1794
|
+
}
|
|
1795
|
+
const toAlertsMapOptions = {
|
|
1796
|
+
overrides,
|
|
1797
|
+
...options
|
|
1798
|
+
};
|
|
1799
|
+
for await (const artifact of batchScan(pkgIds)) {
|
|
1800
|
+
await addArtifactToAlertsMap(artifact, alertsByPkgId, toAlertsMapOptions);
|
|
1801
|
+
remaining -= 1;
|
|
1802
|
+
if (spinner && remaining > 0) {
|
|
1803
|
+
spinner.start();
|
|
1804
|
+
spinner.setText(getText());
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
spinner?.stop();
|
|
1808
|
+
return alertsByPkgId;
|
|
1506
1809
|
}
|
|
1507
1810
|
function updateNode(node, packument, vulnerableVersionRange, firstPatchedVersionIdentifier) {
|
|
1508
1811
|
const availableVersions = Object.keys(packument.versions);
|
|
@@ -1563,208 +1866,6 @@ function updateNode(node, packument, vulnerableVersionRange, firstPatchedVersion
|
|
|
1563
1866
|
}
|
|
1564
1867
|
return true;
|
|
1565
1868
|
}
|
|
1566
|
-
async function getPackagesAlerts(arb, options) {
|
|
1567
|
-
const {
|
|
1568
|
-
consolidate = false,
|
|
1569
|
-
includeExisting = false,
|
|
1570
|
-
includeUnfixable = true,
|
|
1571
|
-
includeUpgrades = false,
|
|
1572
|
-
output
|
|
1573
|
-
} = {
|
|
1574
|
-
__proto__: null,
|
|
1575
|
-
...options
|
|
1576
|
-
};
|
|
1577
|
-
const needInfoOn = getPackagesToQueryFromDiff(arb.diff, {
|
|
1578
|
-
includeUnchanged: includeExisting
|
|
1579
|
-
});
|
|
1580
|
-
const purls = arrays.arrayUnique(needInfoOn.map(d => d.node.pkgid));
|
|
1581
|
-
let {
|
|
1582
|
-
length: remaining
|
|
1583
|
-
} = purls;
|
|
1584
|
-
const results = [];
|
|
1585
|
-
if (!remaining) {
|
|
1586
|
-
return results;
|
|
1587
|
-
}
|
|
1588
|
-
const pkgJson = (arb.actualTree ?? arb.idealTree).package;
|
|
1589
|
-
const spinner$1 = output ? new spinner.Spinner({
|
|
1590
|
-
stream: output
|
|
1591
|
-
}) : undefined;
|
|
1592
|
-
const getText = () => `Looking up data for ${remaining} packages`;
|
|
1593
|
-
const decrementRemaining = () => {
|
|
1594
|
-
remaining -= 1;
|
|
1595
|
-
if (spinner$1 && remaining > 0) {
|
|
1596
|
-
spinner$1.start();
|
|
1597
|
-
spinner$1.setText(getText());
|
|
1598
|
-
}
|
|
1599
|
-
};
|
|
1600
|
-
spinner$1?.start(getText());
|
|
1601
|
-
for await (const artifact of batchScan(purls)) {
|
|
1602
|
-
if (!artifact.name || !artifact.version || !artifact.alerts?.length) {
|
|
1603
|
-
decrementRemaining();
|
|
1604
|
-
continue;
|
|
1605
|
-
}
|
|
1606
|
-
const name = packages.resolvePackageName(artifact);
|
|
1607
|
-
const {
|
|
1608
|
-
version
|
|
1609
|
-
} = artifact;
|
|
1610
|
-
let displayWarning = false;
|
|
1611
|
-
let sockPkgAlerts = [];
|
|
1612
|
-
for (const alert of artifact.alerts) {
|
|
1613
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1614
|
-
const ux = await uxLookup({
|
|
1615
|
-
package: {
|
|
1616
|
-
name,
|
|
1617
|
-
version
|
|
1618
|
-
},
|
|
1619
|
-
alert: {
|
|
1620
|
-
type: alert.type
|
|
1621
|
-
}
|
|
1622
|
-
});
|
|
1623
|
-
if (ux.display) {
|
|
1624
|
-
displayWarning = !!output;
|
|
1625
|
-
}
|
|
1626
|
-
const fixableCve = isArtifactAlertCveFixable(alert);
|
|
1627
|
-
const fixableUpgrade = isArtifactAlertUpgradeFixable(alert);
|
|
1628
|
-
if (includeUnfixable || fixableCve || includeUpgrades && fixableUpgrade && !hasOverride(pkgJson, name)) {
|
|
1629
|
-
sockPkgAlerts.push({
|
|
1630
|
-
name,
|
|
1631
|
-
version,
|
|
1632
|
-
key: alert.key,
|
|
1633
|
-
type: alert.type,
|
|
1634
|
-
block: ux.block,
|
|
1635
|
-
raw: alert,
|
|
1636
|
-
fixable: fixableCve || fixableUpgrade
|
|
1637
|
-
});
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
if (!includeExisting && sockPkgAlerts.length) {
|
|
1641
|
-
// Before we ask about problematic issues, check to see if they
|
|
1642
|
-
// already existed in the old version if they did, be quiet.
|
|
1643
|
-
const allExisting = needInfoOn.filter(d => d.existing?.pkgid.startsWith(`${name}@`));
|
|
1644
|
-
for (const {
|
|
1645
|
-
existing
|
|
1646
|
-
} of allExisting) {
|
|
1647
|
-
const oldAlerts =
|
|
1648
|
-
// eslint-disable-next-line no-await-in-loop
|
|
1649
|
-
(await batchScan([existing.pkgid]).next()).value?.alerts;
|
|
1650
|
-
if (oldAlerts?.length) {
|
|
1651
|
-
// SocketArtifactAlert and SocketPackageAlert both have the 'key' property.
|
|
1652
|
-
sockPkgAlerts = sockPkgAlerts.filter(({
|
|
1653
|
-
key
|
|
1654
|
-
}) => !oldAlerts.find(a => a.key === key));
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
if (consolidate && sockPkgAlerts.length) {
|
|
1659
|
-
const highestForCve = new Map();
|
|
1660
|
-
const highestForUpgrade = new Map();
|
|
1661
|
-
const unfixableAlerts = [];
|
|
1662
|
-
for (const sockPkgAlert of sockPkgAlerts) {
|
|
1663
|
-
if (isArtifactAlertCveFixable(sockPkgAlert.raw)) {
|
|
1664
|
-
const version = sockPkgAlert.raw.props[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER];
|
|
1665
|
-
const major = semver.major(version);
|
|
1666
|
-
const highest = highestForCve.get(major)?.raw[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER] ?? '0.0.0';
|
|
1667
|
-
if (semver.gt(version, highest)) {
|
|
1668
|
-
highestForCve.set(major, sockPkgAlert);
|
|
1669
|
-
}
|
|
1670
|
-
} else if (isArtifactAlertUpgradeFixable(sockPkgAlert.raw)) {
|
|
1671
|
-
const {
|
|
1672
|
-
version
|
|
1673
|
-
} = sockPkgAlert;
|
|
1674
|
-
const major = semver.major(version);
|
|
1675
|
-
const highest = highestForUpgrade.get(major)?.version ?? '0.0.0';
|
|
1676
|
-
if (semver.gt(version, highest)) {
|
|
1677
|
-
highestForUpgrade.set(major, sockPkgAlert);
|
|
1678
|
-
}
|
|
1679
|
-
} else {
|
|
1680
|
-
unfixableAlerts.push(sockPkgAlert);
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
sockPkgAlerts = [...unfixableAlerts, ...highestForCve.values(), ...highestForUpgrade.values()];
|
|
1684
|
-
}
|
|
1685
|
-
sockPkgAlerts.sort((a, b) => sorts.naturalCompare(a.type, b.type));
|
|
1686
|
-
spinner$1?.stop();
|
|
1687
|
-
if (displayWarning && sockPkgAlerts.length) {
|
|
1688
|
-
const lines = new Set();
|
|
1689
|
-
const translations = getTranslations();
|
|
1690
|
-
for (const sockPkgAlert of sockPkgAlerts) {
|
|
1691
|
-
const attributes = [...(sockPkgAlert.fixable ? ['fixable'] : []), ...(sockPkgAlert.block ? [] : ['non-blocking'])];
|
|
1692
|
-
const maybeAttributes = attributes.length ? ` (${attributes.join('; ')})` : '';
|
|
1693
|
-
// Based data from { pageProps: { alertTypes } } of:
|
|
1694
|
-
// https://socket.dev/_next/data/94666139314b6437ee4491a0864e72b264547585/en-US.json
|
|
1695
|
-
const info = translations.alerts[sockPkgAlert.type];
|
|
1696
|
-
const title = info?.title ?? sockPkgAlert.type;
|
|
1697
|
-
const maybeDesc = info?.description ? ` - ${info.description}` : '';
|
|
1698
|
-
// TODO: emoji seems to mis-align terminals sometimes
|
|
1699
|
-
lines.add(` ${title}${maybeAttributes}${maybeDesc}\n`);
|
|
1700
|
-
}
|
|
1701
|
-
output?.write(`(socket) ${formatter.hyperlink(`${name}@${version}`, getSocketDevPackageOverviewUrl(NPM, name, version))} contains risks:\n`);
|
|
1702
|
-
for (const line of lines) {
|
|
1703
|
-
output?.write(line);
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
results.push(...sockPkgAlerts);
|
|
1707
|
-
decrementRemaining();
|
|
1708
|
-
}
|
|
1709
|
-
spinner$1?.stop();
|
|
1710
|
-
return results;
|
|
1711
|
-
}
|
|
1712
|
-
function getCveInfoByPackage(alerts, options) {
|
|
1713
|
-
const {
|
|
1714
|
-
excludeUpgrades
|
|
1715
|
-
} = {
|
|
1716
|
-
__proto__: null,
|
|
1717
|
-
...options
|
|
1718
|
-
};
|
|
1719
|
-
let infoByPkg = null;
|
|
1720
|
-
for (const alert of alerts) {
|
|
1721
|
-
if (!isArtifactAlertCveFixable(alert.raw) || excludeUpgrades && registry.getManifestData(NPM, alert.name)) {
|
|
1722
|
-
continue;
|
|
1723
|
-
}
|
|
1724
|
-
if (!infoByPkg) {
|
|
1725
|
-
infoByPkg = new Map();
|
|
1726
|
-
}
|
|
1727
|
-
const {
|
|
1728
|
-
name
|
|
1729
|
-
} = alert;
|
|
1730
|
-
let infos = infoByPkg.get(name);
|
|
1731
|
-
if (!infos) {
|
|
1732
|
-
infos = [];
|
|
1733
|
-
infoByPkg.set(name, infos);
|
|
1734
|
-
}
|
|
1735
|
-
const {
|
|
1736
|
-
firstPatchedVersionIdentifier,
|
|
1737
|
-
vulnerableVersionRange
|
|
1738
|
-
} = alert.raw.props;
|
|
1739
|
-
infos.push({
|
|
1740
|
-
firstPatchedVersionIdentifier,
|
|
1741
|
-
vulnerableVersionRange
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
|
-
return infoByPkg;
|
|
1745
|
-
}
|
|
1746
|
-
const kCtorArgs = Symbol('ctorArgs');
|
|
1747
|
-
const kRiskyReify = Symbol('riskyReify');
|
|
1748
|
-
async function reify(arb, args, level = 1) {
|
|
1749
|
-
const {
|
|
1750
|
-
stderr: output,
|
|
1751
|
-
stdin: input
|
|
1752
|
-
} = process;
|
|
1753
|
-
const alerts = await getPackagesAlerts(arb, {
|
|
1754
|
-
output,
|
|
1755
|
-
includeUnfixable: level < 2
|
|
1756
|
-
});
|
|
1757
|
-
if (alerts.length && !(await prompts.confirm({
|
|
1758
|
-
message: 'Accept risks of installing these packages?',
|
|
1759
|
-
default: false
|
|
1760
|
-
}, {
|
|
1761
|
-
input,
|
|
1762
|
-
output
|
|
1763
|
-
}))) {
|
|
1764
|
-
throw new Error('Socket npm exiting due to risks');
|
|
1765
|
-
}
|
|
1766
|
-
return await arb[kRiskyReify](...args);
|
|
1767
|
-
}
|
|
1768
1869
|
|
|
1769
1870
|
const {
|
|
1770
1871
|
SOCKET_CLI_SAFE_WRAPPER,
|
|
@@ -1773,7 +1874,6 @@ const {
|
|
|
1773
1874
|
getIPC
|
|
1774
1875
|
}
|
|
1775
1876
|
} = constants;
|
|
1776
|
-
const Arborist = require(shadowNpmPaths.getArboristClassPath());
|
|
1777
1877
|
const SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES = {
|
|
1778
1878
|
__proto__: null,
|
|
1779
1879
|
audit: false,
|
|
@@ -1785,13 +1885,16 @@ const SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES = {
|
|
|
1785
1885
|
saveBundle: false,
|
|
1786
1886
|
silent: true
|
|
1787
1887
|
};
|
|
1888
|
+
const kCtorArgs = Symbol('ctorArgs');
|
|
1889
|
+
const kRiskyReify = Symbol('riskyReify');
|
|
1890
|
+
const Arborist = require(shadowNpmPaths.getArboristClassPath());
|
|
1788
1891
|
|
|
1789
1892
|
// Implementation code not related to our custom behavior is based on
|
|
1790
1893
|
// https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/arborist/index.js:
|
|
1791
1894
|
class SafeArborist extends Arborist {
|
|
1792
1895
|
constructor(...ctorArgs) {
|
|
1793
1896
|
super({
|
|
1794
|
-
path: (ctorArgs.length ? ctorArgs[0]?.path : undefined) ?? process.cwd(),
|
|
1897
|
+
path: (ctorArgs.length ? ctorArgs[0]?.path : undefined) ?? process$1.cwd(),
|
|
1795
1898
|
...(ctorArgs.length ? ctorArgs[0] : undefined),
|
|
1796
1899
|
...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
|
|
1797
1900
|
}, ...ctorArgs.slice(1));
|
|
@@ -1817,23 +1920,41 @@ class SafeArborist extends Arborist {
|
|
|
1817
1920
|
__proto__: null,
|
|
1818
1921
|
...(args.length ? args[0] : undefined)
|
|
1819
1922
|
};
|
|
1820
|
-
|
|
1821
|
-
return await this[kRiskyReify](...args);
|
|
1822
|
-
}
|
|
1823
|
-
const level = await getIPC(SOCKET_CLI_SAFE_WRAPPER);
|
|
1923
|
+
const level = options.dryRun ? 0 : await getIPC(SOCKET_CLI_SAFE_WRAPPER);
|
|
1824
1924
|
if (!level) {
|
|
1825
1925
|
return await this[kRiskyReify](...args);
|
|
1826
1926
|
}
|
|
1827
|
-
|
|
1927
|
+
// Lazily access constants.spinner.
|
|
1928
|
+
const {
|
|
1929
|
+
spinner
|
|
1930
|
+
} = constants;
|
|
1931
|
+
await super.reify({
|
|
1828
1932
|
...options,
|
|
1933
|
+
...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,
|
|
1829
1934
|
progress: false
|
|
1830
|
-
},
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1935
|
+
},
|
|
1936
|
+
// @ts-ignore: TS gets grumpy about rest parameters.
|
|
1937
|
+
...args.slice(1));
|
|
1938
|
+
const alertsMap = await getAlertsMapFromArborist(this, {
|
|
1939
|
+
spinner,
|
|
1940
|
+
include: {
|
|
1941
|
+
unfixable: level < 2
|
|
1942
|
+
}
|
|
1943
|
+
});
|
|
1944
|
+
if (alertsMap.size) {
|
|
1945
|
+
logAlertsMap(alertsMap, {
|
|
1946
|
+
output: process$1.stderr
|
|
1947
|
+
});
|
|
1948
|
+
if (!(await prompts.confirm({
|
|
1949
|
+
message: 'Accept risks of installing these packages?',
|
|
1950
|
+
default: false
|
|
1951
|
+
}))) {
|
|
1952
|
+
throw new Error('Socket npm exiting due to risks');
|
|
1953
|
+
}
|
|
1954
|
+
} else {
|
|
1955
|
+
logger.logger.success('Socket npm found no risks!');
|
|
1956
|
+
}
|
|
1957
|
+
return await this[kRiskyReify](...args);
|
|
1837
1958
|
}
|
|
1838
1959
|
}
|
|
1839
1960
|
|
|
@@ -1862,15 +1983,21 @@ exports.AuthError = AuthError;
|
|
|
1862
1983
|
exports.ColorOrMarkdown = ColorOrMarkdown;
|
|
1863
1984
|
exports.InputError = InputError;
|
|
1864
1985
|
exports.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES = SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES;
|
|
1986
|
+
exports.SEVERITY = SEVERITY;
|
|
1865
1987
|
exports.SafeArborist = SafeArborist;
|
|
1988
|
+
exports.addArtifactToAlertsMap = addArtifactToAlertsMap;
|
|
1989
|
+
exports.batchScan = batchScan;
|
|
1866
1990
|
exports.captureException = captureException;
|
|
1991
|
+
exports.findBestPatchVersion = findBestPatchVersion;
|
|
1867
1992
|
exports.findPackageNodes = findPackageNodes;
|
|
1868
1993
|
exports.findUp = findUp;
|
|
1869
|
-
exports.
|
|
1994
|
+
exports.formatSeverityCount = formatSeverityCount;
|
|
1995
|
+
exports.getAlertsMapFromArborist = getAlertsMapFromArborist;
|
|
1996
|
+
exports.getCveInfoByAlertsMap = getCveInfoByAlertsMap;
|
|
1870
1997
|
exports.getDefaultToken = getDefaultToken;
|
|
1871
|
-
exports.getPackagesAlerts = getPackagesAlerts;
|
|
1872
1998
|
exports.getPublicToken = getPublicToken;
|
|
1873
1999
|
exports.getSetting = getSetting;
|
|
2000
|
+
exports.getSeverityCount = getSeverityCount;
|
|
1874
2001
|
exports.getSocketDevAlertUrl = getSocketDevAlertUrl;
|
|
1875
2002
|
exports.getSocketDevPackageOverviewUrl = getSocketDevPackageOverviewUrl;
|
|
1876
2003
|
exports.readFileBinary = readFileBinary;
|
|
@@ -1879,5 +2006,5 @@ exports.safeReadFile = safeReadFile;
|
|
|
1879
2006
|
exports.setupSdk = setupSdk;
|
|
1880
2007
|
exports.updateNode = updateNode;
|
|
1881
2008
|
exports.updateSetting = updateSetting;
|
|
1882
|
-
//# debugId=
|
|
2009
|
+
//# debugId=1b6e4e80-401e-49a9-9b56-3f777bfba08f
|
|
1883
2010
|
//# sourceMappingURL=shadow-npm-inject.js.map
|