@socketsecurity/cli-with-sentry 0.14.44

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