@socketsecurity/cli 0.14.3 → 0.14.4

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.
@@ -0,0 +1,1249 @@
1
+ 'use strict';
2
+
3
+ var vendor = require('./vendor.js');
4
+ var require$$0 = require('node:fs');
5
+ var require$$1 = require('node:path');
6
+ var link = require('./link.js');
7
+ var require$$0$1 = require('node:events');
8
+ var require$$4 = require('node:https');
9
+ var require$$3 = require('node:readline');
10
+ var require$$1$2 = require('node:stream');
11
+ var require$$8 = require('node:timers/promises');
12
+ var require$$3$1 = require('@socketsecurity/config');
13
+ var require$$1$1 = require('node:net');
14
+ var require$$2 = require('node:os');
15
+ var require$$6 = require('../package.json');
16
+ var sdk = require('./sdk.js');
17
+ var pathResolve = require('./path-resolve.js');
18
+ var require$$21 = require('pacote');
19
+
20
+ var npmInjection$1 = {};
21
+
22
+ var npmInjection = {};
23
+
24
+ var arborist = {};
25
+
26
+ var ttyServer$1 = {};
27
+
28
+ Object.defineProperty(ttyServer$1, "__esModule", {
29
+ value: true
30
+ });
31
+ ttyServer$1.createTTYServer = createTTYServer;
32
+ var _nodeFs$2 = require$$0;
33
+ var _nodeNet = require$$1$1;
34
+ var _nodeOs = require$$2;
35
+ var _nodePath$2 = require$$1;
36
+ var _nodeReadline$1 = require$$3;
37
+ var _nodeStream$1 = require$$1$2;
38
+ var _package = require$$6;
39
+ var _misc$1 = sdk.misc;
40
+ const NEWLINE_CHAR_CODE = 10; /*'\n'*/
41
+
42
+ const TTY_IPC = process.env['SOCKET_SECURITY_TTY_IPC'];
43
+ const sock = _nodePath$2.join(_nodeOs.tmpdir(), `socket-security-tty-${process.pid}.sock`);
44
+ process.env['SOCKET_SECURITY_TTY_IPC'] = sock;
45
+ function createNonStandardTTYServer() {
46
+ return {
47
+ async captureTTY(mutexFn) {
48
+ return await new Promise((resolve, reject) => {
49
+ const conn = _nodeNet.createConnection({
50
+ path: TTY_IPC
51
+ }).on('error', reject);
52
+ let captured = false;
53
+ const buffs = [];
54
+ conn.on('data', function awaitCapture(chunk) {
55
+ buffs.push(chunk);
56
+ let lineBuff = Buffer.concat(buffs);
57
+ if (captured) return;
58
+ try {
59
+ const eolIndex = lineBuff.indexOf(NEWLINE_CHAR_CODE);
60
+ if (eolIndex !== -1) {
61
+ conn.removeListener('data', awaitCapture);
62
+ conn.push(lineBuff.slice(eolIndex + 1));
63
+ const {
64
+ ipc_version: remote_ipc_version,
65
+ capabilities: {
66
+ input: hasInput,
67
+ output: hasOutput,
68
+ colorLevel: ipcColorLevel
69
+ }
70
+ } = JSON.parse(lineBuff.slice(0, eolIndex).toString('utf-8'));
71
+ lineBuff = null;
72
+ captured = true;
73
+ if (remote_ipc_version !== _package.version) {
74
+ throw new Error('Mismatched STDIO tunnel IPC version, ensure you only have 1 version of socket CLI being called.');
75
+ }
76
+ const input = hasInput ? new _nodeStream$1.PassThrough() : null;
77
+ input?.pause();
78
+ if (input) conn.pipe(input);
79
+ const output = hasOutput ? new _nodeStream$1.PassThrough() : null;
80
+ if (output) {
81
+ output.pipe(conn)
82
+ // Make ora happy
83
+ ;
84
+ output.isTTY = true;
85
+ output.cursorTo = function cursorTo(x, y, callback) {
86
+ _nodeReadline$1.cursorTo(this, x, y, callback);
87
+ };
88
+ output.clearLine = function clearLine(dir, callback) {
89
+ _nodeReadline$1.clearLine(this, dir, callback);
90
+ };
91
+ }
92
+ mutexFn(ipcColorLevel, hasInput ? input : undefined, hasOutput ? output : undefined).then(resolve, reject).finally(() => {
93
+ conn.unref();
94
+ conn.end();
95
+ input?.end();
96
+ output?.end();
97
+ // process.exit(13)
98
+ });
99
+ }
100
+ } catch (e) {
101
+ reject(e);
102
+ }
103
+ });
104
+ });
105
+ }
106
+ };
107
+ }
108
+ function createIPCServer(colorLevel, captureState, npmlog) {
109
+ const input = process.stdin;
110
+ const output = process.stderr;
111
+ return new Promise((resolve, reject) => {
112
+ const server = _nodeNet
113
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
114
+ .createServer(async conn => {
115
+ if (captureState.captured) {
116
+ await new Promise(resolve => {
117
+ captureState.pendingCaptures.push({
118
+ resolve() {
119
+ resolve();
120
+ }
121
+ });
122
+ });
123
+ } else {
124
+ captureState.captured = true;
125
+ }
126
+ const wasProgressEnabled = npmlog.progressEnabled;
127
+ npmlog.pause();
128
+ if (wasProgressEnabled) {
129
+ npmlog.disableProgress();
130
+ }
131
+ conn.write(`${JSON.stringify({
132
+ ipc_version: _package.version,
133
+ capabilities: {
134
+ input: Boolean(input),
135
+ output: true,
136
+ colorLevel
137
+ }
138
+ })}\n`);
139
+ conn.on('data', data => {
140
+ output.write(data);
141
+ }).on('error', e => {
142
+ output.write(`there was an error prompting from a sub shell (${e?.message}), socket npm closing`);
143
+ process.exit(1);
144
+ });
145
+ input.on('data', data => {
146
+ conn.write(data);
147
+ }).on('end', () => {
148
+ conn.unref();
149
+ conn.end();
150
+ if (wasProgressEnabled) {
151
+ npmlog.enableProgress();
152
+ }
153
+ npmlog.resume();
154
+ captureState.nextCapture();
155
+ });
156
+ }).listen(sock, () => resolve(server)).on('error', reject).unref();
157
+ process.on('exit', () => {
158
+ server.close();
159
+ tryUnlinkSync(sock);
160
+ });
161
+ resolve(server);
162
+ });
163
+ }
164
+ function createStandardTTYServer(colorLevel, isInteractive, npmlog) {
165
+ const captureState = {
166
+ captured: false,
167
+ nextCapture: () => {
168
+ if (captureState.pendingCaptures.length > 0) {
169
+ const pendingCapture = captureState.pendingCaptures.shift();
170
+ pendingCapture?.resolve();
171
+ } else {
172
+ captureState.captured = false;
173
+ }
174
+ },
175
+ pendingCaptures: []
176
+ };
177
+ tryUnlinkSync(sock);
178
+ const input = isInteractive ? process.stdin : undefined;
179
+ const output = process.stderr;
180
+ let ipcServerPromise;
181
+ if (input) {
182
+ ipcServerPromise = createIPCServer(colorLevel, captureState, npmlog);
183
+ }
184
+ return {
185
+ async captureTTY(mutexFn) {
186
+ await ipcServerPromise;
187
+ if (captureState.captured) {
188
+ const captured = new Promise(resolve => {
189
+ captureState.pendingCaptures.push({
190
+ resolve() {
191
+ resolve();
192
+ }
193
+ });
194
+ });
195
+ await captured;
196
+ } else {
197
+ captureState.captured = true;
198
+ }
199
+ const wasProgressEnabled = npmlog.progressEnabled;
200
+ try {
201
+ npmlog.pause();
202
+ if (wasProgressEnabled) {
203
+ npmlog.disableProgress();
204
+ }
205
+ return await mutexFn(colorLevel, input, output);
206
+ } finally {
207
+ if (wasProgressEnabled) {
208
+ npmlog.enableProgress();
209
+ }
210
+ npmlog.resume();
211
+ captureState.nextCapture();
212
+ }
213
+ }
214
+ };
215
+ }
216
+ function tryUnlinkSync(filepath) {
217
+ try {
218
+ (0, _nodeFs$2.unlinkSync)(filepath);
219
+ } catch (e) {
220
+ if ((0, _misc$1.isErrnoException)(e) && e.code !== 'ENOENT') {
221
+ throw e;
222
+ }
223
+ }
224
+ }
225
+ function createTTYServer(colorLevel, isInteractive, npmlog) {
226
+ return !isInteractive && TTY_IPC ? createNonStandardTTYServer() : createStandardTTYServer(colorLevel, isInteractive, npmlog);
227
+ }
228
+
229
+ var issueRules = {};
230
+
231
+ Object.defineProperty(issueRules, "__esModule", {
232
+ value: true
233
+ });
234
+ issueRules.createIssueUXLookup = createIssueUXLookup;
235
+ //#region UX Constants
236
+
237
+ const IGNORE_UX = {
238
+ block: false,
239
+ display: false
240
+ };
241
+ const WARN_UX = {
242
+ block: false,
243
+ display: true
244
+ };
245
+ const ERROR_UX = {
246
+ block: true,
247
+ display: true
248
+ };
249
+ //#endregion
250
+ //#region utils
251
+
252
+ /**
253
+ * Iterates over all entries with ordered issue rule for deferral. Iterates over
254
+ * all issue rules and finds the first defined value that does not defer otherwise
255
+ * uses the defaultValue. Takes the value and converts into a UX workflow
256
+ */
257
+ function resolveIssueRuleUX(entriesOrderedIssueRules, defaultValue) {
258
+ if (defaultValue === true || defaultValue == null) {
259
+ defaultValue = {
260
+ action: 'error'
261
+ };
262
+ } else if (defaultValue === false) {
263
+ defaultValue = {
264
+ action: 'ignore'
265
+ };
266
+ }
267
+ let block = false;
268
+ let display = false;
269
+ let needDefault = true;
270
+ iterate_entries: for (const issueRuleArr of entriesOrderedIssueRules) {
271
+ for (const rule of issueRuleArr) {
272
+ if (issueRuleValueDoesNotDefer(rule)) {
273
+ needDefault = false;
274
+ const narrowingFilter = uxForDefinedNonDeferValue(rule);
275
+ block = block || narrowingFilter.block;
276
+ display = display || narrowingFilter.display;
277
+ continue iterate_entries;
278
+ }
279
+ }
280
+ const narrowingFilter = uxForDefinedNonDeferValue(defaultValue);
281
+ block = block || narrowingFilter.block;
282
+ display = display || narrowingFilter.display;
283
+ }
284
+ if (needDefault) {
285
+ const narrowingFilter = uxForDefinedNonDeferValue(defaultValue);
286
+ block = block || narrowingFilter.block;
287
+ display = display || narrowingFilter.display;
288
+ }
289
+ return {
290
+ block,
291
+ display
292
+ };
293
+ }
294
+
295
+ /**
296
+ * Negative form because it is narrowing the type
297
+ */
298
+ function issueRuleValueDoesNotDefer(issueRule) {
299
+ if (issueRule === undefined) {
300
+ return false;
301
+ } else if (typeof issueRule === 'object' && issueRule) {
302
+ const {
303
+ action
304
+ } = issueRule;
305
+ if (action === undefined || action === 'defer') {
306
+ return false;
307
+ }
308
+ }
309
+ return true;
310
+ }
311
+
312
+ /**
313
+ * Handles booleans for backwards compatibility
314
+
315
+ */
316
+ function uxForDefinedNonDeferValue(issueRuleValue) {
317
+ if (typeof issueRuleValue === 'boolean') {
318
+ return issueRuleValue ? ERROR_UX : IGNORE_UX;
319
+ }
320
+ const {
321
+ action
322
+ } = issueRuleValue;
323
+ if (action === 'warn') {
324
+ return WARN_UX;
325
+ } else if (action === 'ignore') {
326
+ return IGNORE_UX;
327
+ }
328
+ return ERROR_UX;
329
+ }
330
+ //#endregion
331
+
332
+ //#region exports
333
+
334
+ function createIssueUXLookup(settings) {
335
+ const cachedUX = new Map();
336
+ return context => {
337
+ const key = context.issue.type;
338
+ let ux = cachedUX.get(key);
339
+ if (ux) {
340
+ return ux;
341
+ }
342
+ const entriesOrderedIssueRules = [];
343
+ for (const settingsEntry of settings.entries) {
344
+ const orderedIssueRules = [];
345
+ let target = settingsEntry.start;
346
+ while (target !== null) {
347
+ const resolvedTarget = settingsEntry.settings[target];
348
+ if (!resolvedTarget) {
349
+ break;
350
+ }
351
+ const issueRuleValue = resolvedTarget.issueRules?.[key];
352
+ if (typeof issueRuleValue !== 'undefined') {
353
+ orderedIssueRules.push(issueRuleValue);
354
+ }
355
+ target = resolvedTarget.deferTo ?? null;
356
+ }
357
+ entriesOrderedIssueRules.push(orderedIssueRules);
358
+ }
359
+ const defaultValue = settings.defaults.issueRules[key];
360
+ let resolvedDefaultValue = {
361
+ action: 'error'
362
+ };
363
+ if (defaultValue === false) {
364
+ resolvedDefaultValue = {
365
+ action: 'ignore'
366
+ };
367
+ } else if (defaultValue && defaultValue !== true) {
368
+ resolvedDefaultValue = {
369
+ action: defaultValue.action ?? 'error'
370
+ };
371
+ }
372
+ ux = resolveIssueRuleUX(entriesOrderedIssueRules, resolvedDefaultValue);
373
+ cachedUX.set(key, ux);
374
+ return ux;
375
+ };
376
+ }
377
+
378
+ var _interopRequireWildcard = vendor.interopRequireWildcard.default;
379
+ var _interopRequireDefault = vendor.interopRequireDefault.default;
380
+ Object.defineProperty(arborist, "__esModule", {
381
+ value: true
382
+ });
383
+ arborist.SafeArborist = void 0;
384
+ arborist.installSafeArborist = installSafeArborist;
385
+ var _nodeEvents = require$$0$1;
386
+ var _nodeFs$1 = require$$0;
387
+ var _nodeHttps = require$$4;
388
+ var _nodePath$1 = require$$1;
389
+ var _nodeReadline = require$$3;
390
+ var _nodeStream = require$$1$2;
391
+ var _promises = require$$8;
392
+ var _config = require$$3$1;
393
+ var _chalk = _interopRequireDefault(vendor.source);
394
+ var _isInteractive = _interopRequireDefault(vendor.isInteractive);
395
+ var _ora = _interopRequireWildcard(vendor.ora);
396
+ var _ttyServer = ttyServer$1;
397
+ var _chalkMarkdown = sdk.chalkMarkdown;
398
+ var _issueRules = issueRules;
399
+ var _misc = sdk.misc;
400
+ var _pathResolve = pathResolve.pathResolve;
401
+ var _sdk = sdk.sdk;
402
+ var _settings = sdk.settings;
403
+ var _constants = sdk.constants;
404
+ const LOOP_SENTINEL = 1_000_000;
405
+ const POTENTIALLY_BUG_ERROR_SNIPPET = 'this is potentially a bug with socket-npm caused by changes to the npm cli';
406
+ const distPath$1 = __dirname;
407
+ const rootPath$1 = _nodePath$1.resolve(distPath$1, '..');
408
+ const translations = require(_nodePath$1.join(rootPath$1, 'translations.json'));
409
+ const npmEntrypoint = (0, _nodeFs$1.realpathSync)(`${process.argv[1]}`);
410
+ const npmRootPath = (0, _pathResolve.findRoot)(_nodePath$1.dirname(npmEntrypoint));
411
+ const abortController = new AbortController();
412
+ const {
413
+ signal: abortSignal
414
+ } = abortController;
415
+ if (npmRootPath === undefined) {
416
+ console.error(`Unable to find npm cli install directory, ${POTENTIALLY_BUG_ERROR_SNIPPET}.`);
417
+ console.error(`Searched parent directories of ${npmEntrypoint}`);
418
+ process.exit(127);
419
+ }
420
+ const npmNmPath = _nodePath$1.join(npmRootPath, 'node_modules');
421
+ const arboristClassPath = _nodePath$1.join(npmNmPath, '@npmcli/arborist/lib/arborist/index.js');
422
+ const arboristEdgeClassPath = _nodePath$1.join(npmNmPath, '@npmcli/arborist/lib/edge.js');
423
+ let npmlog;
424
+ try {
425
+ npmlog = require(_nodePath$1.join(npmNmPath, 'proc-log/lib/index.js')).log;
426
+ } catch {}
427
+ if (npmlog === undefined) {
428
+ try {
429
+ npmlog = require(_nodePath$1.join(npmNmPath, 'npmlog/lib/log.js'));
430
+ } catch {}
431
+ }
432
+ if (npmlog === undefined) {
433
+ console.error(`Unable to integrate with npm cli logging infrastructure, ${POTENTIALLY_BUG_ERROR_SNIPPET}.`);
434
+ process.exit(127);
435
+ }
436
+ let tarball;
437
+ try {
438
+ tarball = require(_nodePath$1.join(npmNmPath, 'pacote')).tarball;
439
+ } catch {
440
+ tarball = require$$21.tarball;
441
+ }
442
+ const Arborist = require(arboristClassPath);
443
+ const Edge = require(arboristEdgeClassPath);
444
+ const kCtorArgs = Symbol('ctorArgs');
445
+ const kRiskyReify = Symbol('riskyReify');
446
+ const formatter = new _chalkMarkdown.ChalkOrMarkdown(false);
447
+ const pubToken = (0, _sdk.getDefaultKey)() ?? _sdk.FREE_API_KEY;
448
+ const ttyServer = (0, _ttyServer.createTTYServer)(_chalk.default.level, (0, _isInteractive.default)({
449
+ stream: process.stdin
450
+ }), npmlog);
451
+ let _uxLookup;
452
+ async function uxLookup(settings) {
453
+ while (_uxLookup === undefined) {
454
+ await (0, _promises.setTimeout)(1, {
455
+ signal: abortSignal
456
+ });
457
+ }
458
+ return _uxLookup(settings);
459
+ }
460
+ async function* batchScan(pkgIds) {
461
+ const query = {
462
+ packages: pkgIds.map(pkgid => {
463
+ const {
464
+ name,
465
+ version
466
+ } = pkgidParts(pkgid);
467
+ return {
468
+ eco: 'npm',
469
+ pkg: name,
470
+ ver: version,
471
+ top: true
472
+ };
473
+ })
474
+ };
475
+ // TODO: Migrate to SDK.
476
+ const pkgDataReq = _nodeHttps.request(`${_constants.API_V0_URL}/scan/batch`, {
477
+ method: 'POST',
478
+ headers: {
479
+ Authorization: `Basic ${Buffer.from(`${pubToken}:`).toString('base64url')}`
480
+ },
481
+ signal: abortSignal
482
+ }).end(JSON.stringify(query));
483
+ const {
484
+ 0: res
485
+ } = await _nodeEvents.once(pkgDataReq, 'response');
486
+ const ok = res.statusCode >= 200 && res.statusCode <= 299;
487
+ if (!ok) {
488
+ throw new Error(`Socket API Error: ${res.statusCode}`);
489
+ }
490
+ const rli = _nodeReadline.createInterface(res);
491
+ for await (const line of rli) {
492
+ yield JSON.parse(line);
493
+ }
494
+ }
495
+ function deleteEdgeIn(node, edge) {
496
+ node.edgesIn.delete(edge);
497
+ const {
498
+ overrides
499
+ } = edge;
500
+ if (overrides) {
501
+ updateNodeOverrideSetDueToEdgeRemoval(node, overrides);
502
+ }
503
+ }
504
+ function findSocketYmlSync() {
505
+ let prevDir = null;
506
+ let dir = process.cwd();
507
+ while (dir !== prevDir) {
508
+ let ymlPath = _nodePath$1.join(dir, 'socket.yml');
509
+ let yml = maybeReadfileSync(ymlPath);
510
+ if (yml === undefined) {
511
+ ymlPath = _nodePath$1.join(dir, 'socket.yaml');
512
+ yml = maybeReadfileSync(ymlPath);
513
+ }
514
+ if (typeof yml === 'string') {
515
+ try {
516
+ return {
517
+ path: ymlPath,
518
+ parsed: _config.parseSocketConfig(yml)
519
+ };
520
+ } catch {
521
+ throw new Error(`Found file but was unable to parse ${ymlPath}`);
522
+ }
523
+ }
524
+ prevDir = dir;
525
+ dir = _nodePath$1.join(dir, '..');
526
+ }
527
+ return null;
528
+ }
529
+ function findSpecificOverrideSet(first, second) {
530
+ let overrideSet = second;
531
+ while (overrideSet) {
532
+ if (overrideSetsEqual(overrideSet, first)) {
533
+ return second;
534
+ }
535
+ overrideSet = overrideSet.parent;
536
+ }
537
+ overrideSet = first;
538
+ while (overrideSet) {
539
+ if (overrideSetsEqual(overrideSet, second)) {
540
+ return first;
541
+ }
542
+ overrideSet = overrideSet.parent;
543
+ }
544
+ console.error('Conflicting override sets');
545
+ return undefined;
546
+ }
547
+ function maybeReadfileSync(filepath) {
548
+ try {
549
+ return (0, _nodeFs$1.readFileSync)(filepath, 'utf8');
550
+ } catch {}
551
+ return undefined;
552
+ }
553
+ function overrideSetsChildrenAreEqual(overrideSet, other) {
554
+ const queue = [[overrideSet, other]];
555
+ let pos = 0;
556
+ let {
557
+ length: queueLength
558
+ } = queue;
559
+ while (pos < queueLength) {
560
+ if (pos === LOOP_SENTINEL) {
561
+ throw new Error('Detected infinite loop while comparing override sets');
562
+ }
563
+ const {
564
+ 0: currSet,
565
+ 1: currOtherSet
566
+ } = queue[pos++];
567
+ const {
568
+ children
569
+ } = currSet;
570
+ const {
571
+ children: otherChildren
572
+ } = currOtherSet;
573
+ if (children.size !== otherChildren.size) {
574
+ return false;
575
+ }
576
+ for (const key of children.keys()) {
577
+ if (!otherChildren.has(key)) {
578
+ return false;
579
+ }
580
+ const child = children.get(key);
581
+ const otherChild = otherChildren.get(key);
582
+ if (child.value !== otherChild.value) {
583
+ return false;
584
+ }
585
+ queue[queueLength++] = [child, otherChild];
586
+ }
587
+ }
588
+ return true;
589
+ }
590
+ function overrideSetsEqual(overrideSet, other) {
591
+ if (overrideSet === other) {
592
+ return true;
593
+ }
594
+ if (!other) {
595
+ return false;
596
+ }
597
+ if (overrideSet.key !== other.key || overrideSet.value !== other.value) {
598
+ return false;
599
+ }
600
+ if (!overrideSetsChildrenAreEqual(overrideSet, other)) {
601
+ return false;
602
+ }
603
+ if (!overrideSet.parent) {
604
+ return !other.parent;
605
+ }
606
+ return overrideSetsEqual(overrideSet.parent, other.parent);
607
+ }
608
+ async function packagesHaveRiskyIssues(safeArb, _registry, pkgs, output) {
609
+ let result = false;
610
+ let remaining = pkgs.length;
611
+ if (!remaining) {
612
+ (0, _ora.default)('').succeed('No changes detected');
613
+ return result;
614
+ }
615
+ const getText = () => `Looking up data for ${remaining} packages`;
616
+ const spinner = (0, _ora.default)({
617
+ color: 'cyan',
618
+ stream: output,
619
+ isEnabled: true,
620
+ isSilent: false,
621
+ hideCursor: true,
622
+ discardStdin: true,
623
+ spinner: _ora.spinners.dots
624
+ }).start(getText());
625
+ try {
626
+ for await (const pkgData of batchScan(pkgs.map(pkg => pkg.pkgid))) {
627
+ let failures = [];
628
+ let displayWarning = false;
629
+ const name = pkgData.pkg;
630
+ const version = pkgData.ver;
631
+ const id = `${name}@${version}`;
632
+ if (pkgData.type === 'missing') {
633
+ result = true;
634
+ failures.push({
635
+ type: 'missingDependency'
636
+ });
637
+ } else {
638
+ let blocked = false;
639
+ for (const failure of pkgData.value.issues) {
640
+ const ux = await uxLookup({
641
+ package: {
642
+ name,
643
+ version
644
+ },
645
+ issue: {
646
+ type: failure.type
647
+ }
648
+ });
649
+ if (ux.display || ux.block) {
650
+ failures.push({
651
+ raw: failure,
652
+ block: ux.block
653
+ });
654
+ // Before we ask about problematic issues, check to see if they
655
+ // already existed in the old version if they did, be quiet.
656
+ const pkg = pkgs.find(pkg => pkg.pkgid === id && pkg.existing?.startsWith(`${name}@`));
657
+ if (pkg?.existing) {
658
+ for await (const oldPkgData of batchScan([pkg.existing])) {
659
+ if (oldPkgData.type === 'success') {
660
+ failures = failures.filter(issue => oldPkgData.value.issues.find(oldIssue => oldIssue.type === issue.raw.type) == null);
661
+ }
662
+ }
663
+ }
664
+ }
665
+ if (ux.block) {
666
+ result = true;
667
+ blocked = true;
668
+ }
669
+ if (ux.display) {
670
+ displayWarning = true;
671
+ }
672
+ }
673
+ if (!blocked) {
674
+ const pkg = pkgs.find(pkg => pkg.pkgid === id);
675
+ if (pkg) {
676
+ await tarball.stream(id, stream => {
677
+ stream.resume();
678
+ return stream.promise();
679
+ }, {
680
+ ...safeArb[kCtorArgs][0]
681
+ });
682
+ }
683
+ }
684
+ }
685
+ if (displayWarning) {
686
+ spinner.stop();
687
+ output?.write(`(socket) ${formatter.hyperlink(id, `https://socket.dev/npm/package/${name}/overview/${version}`)} contains risks:\n`);
688
+ failures.sort((a, b) => a.raw.type < b.raw.type ? -1 : 1);
689
+ const lines = new Set();
690
+ for (const failure of failures) {
691
+ const type = failure.raw.type;
692
+ if (type) {
693
+ const issueTypeTranslation = translations.issues[type];
694
+ // TODO: emoji seems to mis-align terminals sometimes
695
+ lines.add(` ${issueTypeTranslation?.title ?? type}${failure.block ? '' : ' (non-blocking)'} - ${issueTypeTranslation?.description ?? ''}\n`);
696
+ }
697
+ }
698
+ for (const line of lines) {
699
+ output?.write(line);
700
+ }
701
+ spinner.start();
702
+ }
703
+ remaining -= 1;
704
+ spinner.text = remaining > 0 ? getText() : '';
705
+ }
706
+ return result;
707
+ } finally {
708
+ if (spinner.isSpinning) {
709
+ spinner.stop();
710
+ }
711
+ }
712
+ }
713
+ function pkgidParts(pkgid) {
714
+ const delimiter = pkgid.lastIndexOf('@');
715
+ const name = pkgid.slice(0, delimiter);
716
+ const version = pkgid.slice(delimiter + 1);
717
+ return {
718
+ name,
719
+ version
720
+ };
721
+ }
722
+ function recalculateOutEdgesOverrides(node) {
723
+ // For each edge out propagate the new overrides through.
724
+ for (const edge of node.edgesOut.values()) {
725
+ edge.reload(true);
726
+ if (edge.to) {
727
+ updateNodeOverrideSet(edge.to, edge.overrides);
728
+ }
729
+ }
730
+ }
731
+ function toPURL(pkgid, resolved) {
732
+ const repo = resolved.replace(/#[\s\S]*$/u, '').replace(/\?[\s\S]*$/u, '').replace(/\/[^/]*\/-\/[\s\S]*$/u, '');
733
+ const {
734
+ name,
735
+ version
736
+ } = pkgidParts(pkgid);
737
+ return {
738
+ type: 'npm',
739
+ namespace_and_name: name,
740
+ version,
741
+ repository_url: repo
742
+ };
743
+ }
744
+ function updateNodeOverrideSetDueToEdgeRemoval(node, other) {
745
+ const {
746
+ overrides
747
+ } = node;
748
+ // If this edge's overrides isn't equal to this node's overrides, then removing
749
+ // it won't change newOverrideSet later.
750
+ if (!overrides || !overrideSetsEqual(overrides, other)) {
751
+ return false;
752
+ }
753
+ let newOverrideSet;
754
+ for (const edge of node.edgesIn) {
755
+ const {
756
+ overrides: edgeOverrides
757
+ } = edge;
758
+ if (newOverrideSet) {
759
+ newOverrideSet = findSpecificOverrideSet(edgeOverrides, newOverrideSet);
760
+ } else {
761
+ newOverrideSet = edgeOverrides;
762
+ }
763
+ }
764
+ if (overrideSetsEqual(overrides, newOverrideSet)) {
765
+ return false;
766
+ }
767
+ node.overrides = newOverrideSet;
768
+ if (newOverrideSet) {
769
+ // Optimization: If there's any override set at all, then no non-extraneous
770
+ // node has an empty override set. So if we temporarily have no override set
771
+ // (for example, we removed all the edges in), there's no use updating all
772
+ // the edges out right now. Let's just wait until we have an actual override
773
+ // set later.
774
+ recalculateOutEdgesOverrides(node);
775
+ }
776
+ return true;
777
+ }
778
+
779
+ // This logic isn't perfect either. When we have two edges in that have different
780
+ // override sets, then we have to decide which set is correct. This function
781
+ // assumes the more specific override set is applicable, so if we have dependencies
782
+ // A->B->C and A->C and an override set that specifies what happens for C under
783
+ // A->B, this will work even if the new A->C edge comes along and tries to change
784
+ // the override set. The strictly correct logic is not to allow two edges with
785
+ // different overrides to point to the same node, because even if this node can
786
+ // satisfy both, one of its dependencies might need to be different depending on
787
+ // the edge leading to it. However, this might cause a lot of duplication, because
788
+ // the conflict in the dependencies might never actually happen.
789
+ function updateNodeOverrideSet(node, otherOverrideSet) {
790
+ if (!node.overrides) {
791
+ // Assuming there are any overrides at all, the overrides field is never
792
+ // undefined for any node at the end state of the tree. So if the new edge's
793
+ // overrides is undefined it will be updated later. So we can wait with
794
+ // updating the node's overrides field.
795
+ if (!otherOverrideSet) {
796
+ return false;
797
+ }
798
+ node.overrides = otherOverrideSet;
799
+ recalculateOutEdgesOverrides(node);
800
+ return true;
801
+ }
802
+ const {
803
+ overrides
804
+ } = node;
805
+ if (overrideSetsEqual(overrides, otherOverrideSet)) {
806
+ return false;
807
+ }
808
+ const newOverrideSet = findSpecificOverrideSet(overrides, otherOverrideSet);
809
+ if (newOverrideSet) {
810
+ if (overrideSetsEqual(overrides, newOverrideSet)) {
811
+ return false;
812
+ }
813
+ node.overrides = newOverrideSet;
814
+ recalculateOutEdgesOverrides(node);
815
+ return true;
816
+ }
817
+ // This is an error condition. We can only get here if the new override set is
818
+ // in conflict with the existing.
819
+ console.error('Conflicting override sets');
820
+ return false;
821
+ }
822
+ function walk(diff_, needInfoOn = []) {
823
+ const queue = [diff_];
824
+ let pos = 0;
825
+ let {
826
+ length: queueLength
827
+ } = queue;
828
+ while (pos < queueLength) {
829
+ if (pos === LOOP_SENTINEL) {
830
+ throw new Error('Detected infinite loop while walking Arborist diff');
831
+ }
832
+ const diff = queue[pos++];
833
+ if (!diff) {
834
+ continue;
835
+ }
836
+ if (diff.action) {
837
+ const sameVersion = diff.actual?.package.version === diff.ideal?.package.version;
838
+ let keep = false;
839
+ let existing = null;
840
+ if (diff.action === 'CHANGE') {
841
+ if (!sameVersion) {
842
+ existing = diff.actual.pkgid;
843
+ keep = true;
844
+ }
845
+ } else {
846
+ keep = diff.action !== 'REMOVE';
847
+ }
848
+ if (keep && diff.ideal?.pkgid && diff.ideal.resolved && (!diff.actual || diff.actual.resolved)) {
849
+ needInfoOn.push({
850
+ existing,
851
+ action: diff.action,
852
+ location: diff.ideal.location,
853
+ pkgid: diff.ideal.pkgid,
854
+ newPackage: toPURL(diff.ideal.pkgid, diff.ideal.resolved),
855
+ oldPackage: diff.actual && diff.actual.resolved ? toPURL(diff.actual.pkgid, diff.actual.resolved) : null,
856
+ resolved: diff.ideal.resolved
857
+ });
858
+ }
859
+ }
860
+ if (diff.children) {
861
+ for (const child of diff.children) {
862
+ queue[queueLength++] = child;
863
+ }
864
+ }
865
+ }
866
+ return needInfoOn;
867
+ }
868
+
869
+ // Copied from
870
+ // https://github.com/npm/cli/blob/v10.9.0/workspaces/arborist/lib/edge.js:
871
+ // The npm application
872
+ // Copyright (c) npm, Inc. and Contributors
873
+ // Licensed on the terms of The Artistic License 2.0
874
+ //
875
+ // An edge in the dependency graph.
876
+ // Represents a dependency relationship of some kind.
877
+
878
+ class SafeEdge extends Edge {
879
+ #safeAccept;
880
+ #safeError;
881
+ #safeExplanation;
882
+ #safeFrom;
883
+ #safeTo;
884
+ constructor(options) {
885
+ const {
886
+ accept,
887
+ from
888
+ } = options;
889
+ // Defer to supper to validate options and assign non-private values.
890
+ super(options);
891
+ if (accept !== undefined) {
892
+ this.#safeAccept = accept || '*';
893
+ }
894
+ this.#safeError = null;
895
+ this.#safeExplanation = null;
896
+ this.#safeFrom = from;
897
+ this.#safeTo = null;
898
+ this.reload(true);
899
+ }
900
+
901
+ // Return the edge data, and an explanation of how that edge came to be here.
902
+ // @ts-ignore: Edge#explain is defined with an unused `seen = []` param.
903
+ explain() {
904
+ if (!this.#safeExplanation) {
905
+ const explanation = {
906
+ type: this.type,
907
+ name: this.name,
908
+ spec: this.spec,
909
+ bundled: false,
910
+ overridden: false,
911
+ error: undefined,
912
+ from: undefined,
913
+ rawSpec: undefined
914
+ };
915
+ if (this.rawSpec !== this.spec) {
916
+ explanation.rawSpec = this.rawSpec;
917
+ explanation.overridden = true;
918
+ }
919
+ if (this.bundled) {
920
+ explanation.bundled = this.bundled;
921
+ }
922
+ if (this.error) {
923
+ explanation.error = this.error;
924
+ }
925
+ if (this.#safeFrom) {
926
+ explanation.from = this.#safeFrom.explain();
927
+ }
928
+ this.#safeExplanation = explanation;
929
+ }
930
+ return this.#safeExplanation;
931
+ }
932
+ get bundled() {
933
+ return !!this.#safeFrom?.package?.bundleDependencies?.includes(this.name);
934
+ }
935
+
936
+ // @ts-ignore: Incorrectly typed as a property instead of an accessor.
937
+ get spec() {
938
+ if (this.overrides?.value && this.overrides.value !== '*' && this.overrides.name === this.name) {
939
+ if (this.overrides.value.startsWith('$')) {
940
+ const ref = this.overrides.value.slice(1);
941
+ // We may be a virtual root, if we are we want to resolve reference
942
+ // overrides from the real root, not the virtual one.
943
+ const pkg = this.#safeFrom?.sourceReference ? this.#safeFrom.sourceReference.root.package : this.#safeFrom?.root.package;
944
+ if (pkg?.devDependencies?.[ref]) {
945
+ return pkg.devDependencies[ref];
946
+ }
947
+ if (pkg?.optionalDependencies?.[ref]) {
948
+ return pkg.optionalDependencies[ref];
949
+ }
950
+ if (pkg?.dependencies?.[ref]) {
951
+ return pkg.dependencies[ref];
952
+ }
953
+ if (pkg?.peerDependencies?.[ref]) {
954
+ return pkg.peerDependencies[ref];
955
+ }
956
+ throw new Error(`Unable to resolve reference ${this.overrides.value}`);
957
+ }
958
+ return this.overrides.value;
959
+ }
960
+ return this.rawSpec;
961
+ }
962
+ get accept() {
963
+ return this.#safeAccept;
964
+ }
965
+ get error() {
966
+ if (!this.#safeError) {
967
+ if (!this.#safeTo) {
968
+ if (this.optional) {
969
+ this.#safeError = null;
970
+ } else {
971
+ this.#safeError = 'MISSING';
972
+ }
973
+ } else if (this.peer && this.#safeFrom === this.#safeTo.parent && !this.#safeFrom?.isTop) {
974
+ this.#safeError = 'PEER LOCAL';
975
+ } else if (!this.satisfiedBy(this.#safeTo)) {
976
+ this.#safeError = 'INVALID';
977
+ } else {
978
+ this.#safeError = 'OK';
979
+ }
980
+ }
981
+ if (this.#safeError === 'OK') {
982
+ return null;
983
+ }
984
+ return this.#safeError;
985
+ }
986
+ reload(hard = false) {
987
+ this.#safeExplanation = null;
988
+ if (this.#safeFrom?.overrides) {
989
+ this.overrides = this.#safeFrom.overrides.getEdgeRule(this);
990
+ } else {
991
+ this.overrides = undefined;
992
+ }
993
+ const newTo = this.#safeFrom?.resolve(this.name);
994
+ if (newTo !== this.#safeTo) {
995
+ if (this.#safeTo) {
996
+ // Instead of `this.#safeTo.edgesIn.delete(this)` we patch based on
997
+ // https://github.com/npm/cli/pull/7025.
998
+ deleteEdgeIn(this.#safeTo, this);
999
+ }
1000
+ this.#safeTo = newTo ?? null;
1001
+ this.#safeError = null;
1002
+ if (this.#safeTo) {
1003
+ this.#safeTo.addEdgeIn(this);
1004
+ }
1005
+ } else if (hard) {
1006
+ this.#safeError = null;
1007
+ }
1008
+ }
1009
+ detach() {
1010
+ this.#safeExplanation = null;
1011
+ if (this.#safeTo) {
1012
+ // Instead of `this.#safeTo.edgesIn.delete(this)` we patch based on
1013
+ // https://github.com/npm/cli/pull/7025.
1014
+ deleteEdgeIn(this.#safeTo, this);
1015
+ }
1016
+ if (this.#safeFrom) {
1017
+ this.#safeFrom.edgesOut.delete(this.name);
1018
+ }
1019
+ this.#safeTo = null;
1020
+ this.#safeError = 'DETACHED';
1021
+ this.#safeFrom = null;
1022
+ }
1023
+
1024
+ // @ts-ignore: Incorrectly typed as a property instead of an accessor.
1025
+ get from() {
1026
+ return this.#safeFrom;
1027
+ }
1028
+
1029
+ // @ts-ignore: Incorrectly typed as a property instead of an accessor.
1030
+ get to() {
1031
+ return this.#safeTo;
1032
+ }
1033
+ }
1034
+ class SafeArborist extends Arborist {
1035
+ constructor(...ctorArgs) {
1036
+ const mutedArguments = [{
1037
+ ...ctorArgs[0],
1038
+ audit: true,
1039
+ dryRun: true,
1040
+ ignoreScripts: true,
1041
+ save: false,
1042
+ saveBundle: false,
1043
+ // progress: false,
1044
+ fund: false
1045
+ }, ctorArgs.slice(1)];
1046
+ super(...mutedArguments);
1047
+ this[kCtorArgs] = ctorArgs;
1048
+ }
1049
+ async [kRiskyReify](...args) {
1050
+ // SafeArborist has suffered side effects and must be rebuilt from scratch.
1051
+ const arb = new Arborist(...this[kCtorArgs]);
1052
+ const ret = await arb.reify(...args);
1053
+ Object.assign(this, arb);
1054
+ return ret;
1055
+ }
1056
+
1057
+ // @ts-ignore Incorrectly typed.
1058
+ async reify(...args) {
1059
+ const options = args[0] ? {
1060
+ ...args[0]
1061
+ } : {};
1062
+ if (options.dryRun) {
1063
+ return await this[kRiskyReify](...args);
1064
+ }
1065
+ const old = {
1066
+ ...options,
1067
+ dryRun: false,
1068
+ save: Boolean(options['save'] ?? true),
1069
+ saveBundle: Boolean(options['saveBundle'] ?? false)
1070
+ };
1071
+ args[0] = options;
1072
+ options.dryRun = true;
1073
+ options['save'] = false;
1074
+ options['saveBundle'] = false;
1075
+ // TODO: Make this deal w/ any refactor to private fields by punching the
1076
+ // class itself.
1077
+ await super.reify(...args);
1078
+ const diff = walk(this['diff']);
1079
+ options.dryRun = old.dryRun;
1080
+ options['save'] = old.save;
1081
+ options['saveBundle'] = old.saveBundle;
1082
+ // Nothing to check, mmm already installed or all private?
1083
+ if (diff.findIndex(c => c.newPackage.repository_url === 'https://registry.npmjs.org') === -1) {
1084
+ return await this[kRiskyReify](...args);
1085
+ }
1086
+ let proceed = _constants.ENV.UPDATE_SOCKET_OVERRIDES_IN_PACKAGE_LOCK_FILE;
1087
+ if (!proceed) {
1088
+ proceed = await ttyServer.captureTTY(async (colorLevel, input, output) => {
1089
+ _chalk.default.level = colorLevel;
1090
+ if (input && output) {
1091
+ const risky = await packagesHaveRiskyIssues(this, this['registry'], diff, output);
1092
+ if (!risky) {
1093
+ return true;
1094
+ }
1095
+ const rlin = new _nodeStream.PassThrough();
1096
+ input.pipe(rlin);
1097
+ const rlout = new _nodeStream.PassThrough();
1098
+ rlout.pipe(output, {
1099
+ end: false
1100
+ });
1101
+ const rli = _nodeReadline.createInterface(rlin, rlout);
1102
+ try {
1103
+ while (true) {
1104
+ const answer = await new Promise(resolve => {
1105
+ rli.question('Accept risks of installing these packages (y/N)?\n', {
1106
+ signal: abortSignal
1107
+ }, resolve);
1108
+ });
1109
+ if (/^\s*y(?:es)?\s*$/i.test(answer)) {
1110
+ return true;
1111
+ }
1112
+ if (/^(?:\s*no?\s*|)$/i.test(answer)) {
1113
+ return false;
1114
+ }
1115
+ }
1116
+ } finally {
1117
+ rli.close();
1118
+ }
1119
+ } else if (await packagesHaveRiskyIssues(this, this['registry'], diff, output)) {
1120
+ throw new Error('Socket npm Unable to prompt to accept risk, need TTY to do so');
1121
+ }
1122
+ return true;
1123
+ });
1124
+ }
1125
+ if (proceed) {
1126
+ return await this[kRiskyReify](...args);
1127
+ } else {
1128
+ throw new Error('Socket npm exiting due to risks');
1129
+ }
1130
+ }
1131
+ }
1132
+ arborist.SafeArborist = SafeArborist;
1133
+ function installSafeArborist() {
1134
+ require.cache[arboristEdgeClassPath].exports = SafeEdge;
1135
+ require.cache[arboristClassPath].exports = SafeArborist;
1136
+ }
1137
+ void (async () => {
1138
+ const remoteSettings = await (async () => {
1139
+ try {
1140
+ const socketSdk = await (0, _sdk.setupSdk)(pubToken);
1141
+ const orgResult = await socketSdk.getOrganizations();
1142
+ if (!orgResult.success) {
1143
+ throw new Error('Failed to fetch Socket organization info: ' + orgResult.error.message);
1144
+ }
1145
+ const orgs = [];
1146
+ for (const org of Object.values(orgResult.data.organizations)) {
1147
+ if (org) {
1148
+ orgs.push(org);
1149
+ }
1150
+ }
1151
+ const result = await socketSdk.postSettings(orgs.map(org => {
1152
+ return {
1153
+ organization: org.id
1154
+ };
1155
+ }));
1156
+ if (!result.success) {
1157
+ throw new Error('Failed to fetch API key settings: ' + result.error.message);
1158
+ }
1159
+ return {
1160
+ orgs,
1161
+ settings: result.data
1162
+ };
1163
+ } catch (e) {
1164
+ if (typeof e === 'object' && e !== null && 'cause' in e) {
1165
+ const {
1166
+ cause
1167
+ } = e;
1168
+ if ((0, _misc.isErrnoException)(cause)) {
1169
+ if (cause.code === 'ENOTFOUND' || cause.code === 'ECONNREFUSED') {
1170
+ throw new Error('Unable to connect to socket.dev, ensure internet connectivity before retrying', {
1171
+ cause: e
1172
+ });
1173
+ }
1174
+ }
1175
+ }
1176
+ throw e;
1177
+ }
1178
+ })();
1179
+ const {
1180
+ orgs,
1181
+ settings
1182
+ } = remoteSettings;
1183
+ const enforcedOrgs = (0, _settings.getSetting)('enforcedOrgs') ?? [];
1184
+
1185
+ // remove any organizations not being enforced
1186
+ for (const {
1187
+ 0: i,
1188
+ 1: org
1189
+ } of orgs.entries()) {
1190
+ if (!enforcedOrgs.includes(org.id)) {
1191
+ settings.entries.splice(i, 1);
1192
+ }
1193
+ }
1194
+ const socketYml = findSocketYmlSync();
1195
+ if (socketYml) {
1196
+ settings.entries.push({
1197
+ start: socketYml.path,
1198
+ // @ts-ignore
1199
+ settings: {
1200
+ [socketYml.path]: {
1201
+ deferTo: null,
1202
+ issueRules: socketYml.parsed.issueRules
1203
+ }
1204
+ }
1205
+ });
1206
+ }
1207
+ _uxLookup = (0, _issueRules.createIssueUXLookup)(settings);
1208
+ })();
1209
+
1210
+ var _nodeFs = require$$0;
1211
+ var _nodePath = require$$1;
1212
+ var _link = link.link;
1213
+ var _arborist = arborist;
1214
+ const distPath = __dirname;
1215
+ const rootPath = _nodePath.resolve(distPath, '..');
1216
+ const binPath = _nodePath.join(rootPath, 'bin');
1217
+
1218
+ // shadow `npm` and `npx` to mitigate subshells
1219
+ (0, _link.installLinks)((0, _nodeFs.realpathSync)(binPath), 'npm');
1220
+ (0, _arborist.installSafeArborist)();
1221
+
1222
+ (function (exports) {
1223
+
1224
+ var _interopRequireWildcard = vendor.interopRequireWildcard.default;
1225
+ Object.defineProperty(exports, "__esModule", {
1226
+ value: true
1227
+ });
1228
+ var _exportNames = {};
1229
+ Object.defineProperty(exports, "default", {
1230
+ enumerable: true,
1231
+ get: function () {
1232
+ return _npmInjection.default;
1233
+ }
1234
+ });
1235
+ var _npmInjection = _interopRequireWildcard(npmInjection, true);
1236
+ Object.keys(_npmInjection).forEach(function (key) {
1237
+ if (key === "default" || key === "__esModule") return;
1238
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
1239
+ if (key in exports && exports[key] === _npmInjection[key]) return;
1240
+ Object.defineProperty(exports, key, {
1241
+ enumerable: true,
1242
+ get: function () {
1243
+ return _npmInjection[key];
1244
+ }
1245
+ });
1246
+ });
1247
+ } (npmInjection$1));
1248
+
1249
+ module.exports = npmInjection$1;