@socketsecurity/cli 0.14.40 → 0.14.41

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.
@@ -13,78 +13,45 @@ var path = require('node:path');
13
13
  var process = require('node:process');
14
14
  var semver = _socketInterop(require('semver'));
15
15
  var registry = require('@socketsecurity/registry');
16
+ var arrays = require('@socketsecurity/registry/lib/arrays');
16
17
  var objects = require('@socketsecurity/registry/lib/objects');
17
18
  var packages = require('@socketsecurity/registry/lib/packages');
18
19
  var prompts = require('@socketsecurity/registry/lib/prompts');
19
20
  var spinner = require('@socketsecurity/registry/lib/spinner');
21
+ var constants = require('./constants.js');
20
22
  var events = require('node:events');
21
23
  var https = require('node:https');
22
24
  var readline = require('node:readline');
23
- var constants = require('./constants.js');
24
25
  var socketUrl = require('./socket-url.js');
25
- var fs = require('node:fs');
26
26
  var promises = require('node:timers/promises');
27
- var config = require('@socketsecurity/config');
28
27
  var pathResolve = require('./path-resolve.js');
28
+ var fs = require('node:fs');
29
29
  var npa = _socketInterop(require('npm-package-arg'));
30
30
 
31
31
  const {
32
- API_V0_URL,
33
32
  LOOP_SENTINEL: LOOP_SENTINEL$2,
34
- SOCKET_CLI_FIX_PACKAGE_LOCK_FILE: SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1,
35
- abortSignal: abortSignal$2
33
+ NPM_REGISTRY_URL: NPM_REGISTRY_URL$1,
34
+ SOCKET_CLI_FIX_PACKAGE_LOCK_FILE: SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1
36
35
  } = constants;
37
- async function* batchScan(pkgIds) {
38
- const req = https.request(`${API_V0_URL}/purl?alerts=true`, {
39
- method: 'POST',
40
- headers: {
41
- Authorization: `Basic ${Buffer.from(`${socketUrl.getPublicToken()}:`).toString('base64url')}`
42
- },
43
- signal: abortSignal$2
44
- }).end(JSON.stringify({
45
- components: pkgIds.map(id => ({
46
- purl: `pkg:npm/${id}`
47
- }))
48
- }));
49
- const {
50
- 0: res
51
- } = await events.once(req, 'response');
52
- const ok = res.statusCode >= 200 && res.statusCode <= 299;
53
- if (!ok) {
54
- throw new Error(`Socket API Error: ${res.statusCode}`);
55
- }
56
- const rli = readline.createInterface(res);
57
- for await (const line of rli) {
58
- yield JSON.parse(line);
59
- }
60
- }
61
- function isAlertFixable(alert) {
62
- return alert.type === 'socketUpgradeAvailable' || isAlertFixableCve(alert);
63
- }
64
- function isAlertFixableCve(alert) {
65
- const {
66
- type
67
- } = alert;
68
- return (type === 'cve' || type === 'mediumCVE' || type === 'mildCVE' || type === 'criticalCVE') && !!alert.props?.['firstPatchedVersionIdentifier'];
69
- }
70
- function toRepoUrl(resolved) {
36
+ function getUrlOrigin(input) {
71
37
  try {
72
- return URL.parse(resolved)?.origin ?? '';
38
+ return URL.parse(input)?.origin ?? '';
73
39
  } catch {}
74
40
  return '';
75
41
  }
76
- function walk(diff_, options) {
42
+ function getPackagesToQueryFromDiff(diff_, options) {
77
43
  const {
78
44
  // Lazily access constants.IPC.
79
- fix = constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1]
45
+ includeUnchanged = constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1],
46
+ includeUnknownOrigin = false
80
47
  } = {
81
48
  __proto__: null,
82
49
  ...options
83
50
  };
84
- const needInfoOn = [];
51
+ const details = [];
85
52
  // `diff_` is `null` when `npm install --package-lock-only` is passed.
86
53
  if (!diff_) {
87
- return needInfoOn;
54
+ return details;
88
55
  }
89
56
  const queue = [...diff_.children];
90
57
  let pos = 0;
@@ -114,25 +81,28 @@ function walk(diff_, options) {
114
81
  if (pkgNode?.package.version !== oldNode?.package.version) {
115
82
  keep = true;
116
83
  if (oldNode?.package.name && oldNode.package.name === pkgNode?.package.name) {
117
- existing = oldNode.pkgid;
84
+ existing = oldNode;
118
85
  }
119
86
  }
120
87
  } else {
121
88
  keep = action !== 'REMOVE';
122
89
  }
123
90
  if (keep && pkgNode?.resolved && (!oldNode || oldNode.resolved)) {
124
- needInfoOn.push({
125
- existing,
126
- pkgid: pkgNode.pkgid,
127
- repository_url: toRepoUrl(pkgNode.resolved)
128
- });
91
+ const origin = getUrlOrigin(pkgNode.resolved);
92
+ if (includeUnknownOrigin || origin === NPM_REGISTRY_URL$1) {
93
+ details.push({
94
+ node: pkgNode,
95
+ origin,
96
+ existing
97
+ });
98
+ }
129
99
  }
130
100
  }
131
101
  for (const child of diff.children) {
132
102
  queue[queueLength++] = child;
133
103
  }
134
104
  }
135
- if (fix) {
105
+ if (includeUnchanged) {
136
106
  const {
137
107
  unchanged
138
108
  } = diff_;
@@ -140,14 +110,55 @@ function walk(diff_, options) {
140
110
  length
141
111
  } = unchanged; i < length; i += 1) {
142
112
  const pkgNode = unchanged[i];
143
- needInfoOn.push({
144
- existing: pkgNode.pkgid,
145
- pkgid: pkgNode.pkgid,
146
- repository_url: toRepoUrl(pkgNode.resolved)
147
- });
113
+ const origin = getUrlOrigin(pkgNode.resolved);
114
+ if (includeUnknownOrigin || origin === NPM_REGISTRY_URL$1) {
115
+ details.push({
116
+ node: pkgNode,
117
+ origin,
118
+ existing: pkgNode
119
+ });
120
+ }
148
121
  }
149
122
  }
150
- return needInfoOn;
123
+ return details;
124
+ }
125
+
126
+ const {
127
+ API_V0_URL,
128
+ abortSignal: abortSignal$2
129
+ } = constants;
130
+ async function* batchScan(pkgIds) {
131
+ const req = https.request(`${API_V0_URL}/purl?alerts=true`, {
132
+ method: 'POST',
133
+ headers: {
134
+ Authorization: `Basic ${Buffer.from(`${socketUrl.getPublicToken()}:`).toString('base64url')}`
135
+ },
136
+ signal: abortSignal$2
137
+ }).end(JSON.stringify({
138
+ components: pkgIds.map(id => ({
139
+ purl: `pkg:npm/${id}`
140
+ }))
141
+ }));
142
+ const {
143
+ 0: res
144
+ } = await events.once(req, 'response');
145
+ const ok = res.statusCode >= 200 && res.statusCode <= 299;
146
+ if (!ok) {
147
+ throw new Error(`Socket API Error: ${res.statusCode}`);
148
+ }
149
+ const rli = readline.createInterface(res);
150
+ for await (const line of rli) {
151
+ yield JSON.parse(line);
152
+ }
153
+ }
154
+ function isArtifactAlertCveFixable(alert) {
155
+ const {
156
+ type
157
+ } = alert;
158
+ return (type === 'cve' || type === 'mediumCVE' || type === 'mildCVE' || type === 'criticalCVE') && !!alert.props?.['firstPatchedVersionIdentifier'];
159
+ }
160
+ function isArtifactAlertFixable(alert) {
161
+ return alert.type === 'socketUpgradeAvailable' || isArtifactAlertCveFixable(alert);
151
162
  }
152
163
 
153
164
  const {
@@ -165,37 +176,6 @@ const WARN_UX = {
165
176
  block: false,
166
177
  display: true
167
178
  };
168
- function findSocketYmlSync() {
169
- let prevDir = null;
170
- let dir = process.cwd();
171
- while (dir !== prevDir) {
172
- let ymlPath = path.join(dir, 'socket.yml');
173
- let yml = maybeReadfileSync(ymlPath);
174
- if (yml === undefined) {
175
- ymlPath = path.join(dir, 'socket.yaml');
176
- yml = maybeReadfileSync(ymlPath);
177
- }
178
- if (typeof yml === 'string') {
179
- try {
180
- return {
181
- path: ymlPath,
182
- parsed: config.parseSocketConfig(yml)
183
- };
184
- } catch {
185
- throw new Error(`Found file but was unable to parse ${ymlPath}`);
186
- }
187
- }
188
- prevDir = dir;
189
- dir = path.join(dir, '..');
190
- }
191
- return null;
192
- }
193
- function maybeReadfileSync(filepath) {
194
- try {
195
- return fs.readFileSync(filepath, 'utf8');
196
- } catch {}
197
- return undefined;
198
- }
199
179
 
200
180
  // Iterates over all entries with ordered issue rule for deferral. Iterates over
201
181
  // all issue rules and finds the first defined value that does not defer otherwise
@@ -374,7 +354,7 @@ void (async () => {
374
354
  settings.entries.splice(i, 1);
375
355
  }
376
356
  }
377
- const socketYml = findSocketYmlSync();
357
+ const socketYml = socketUrl.findSocketYmlSync();
378
358
  if (socketYml) {
379
359
  settings.entries.push({
380
360
  start: socketYml.path,
@@ -417,7 +397,6 @@ const arboristDepValidPath = path.join(arboristPkgPath, 'lib/dep-valid.js');
417
397
  const arboristEdgeClassPath = path.join(arboristPkgPath, 'lib/edge.js');
418
398
  const arboristNodeClassPath = path.join(arboristPkgPath, 'lib/node.js');
419
399
  const arboristOverrideSetClassPath = path.join(arboristPkgPath, 'lib/override-set.js');
420
- const pacotePath = path.join(npmNmPath, 'pacote');
421
400
 
422
401
  const depValid = require(arboristDepValidPath);
423
402
 
@@ -1083,7 +1062,7 @@ class SafeEdge extends Edge {
1083
1062
  this.#safeError = null;
1084
1063
  }
1085
1064
  // Patch adding "else if" condition based on
1086
- // https://github.com/npm/cli/pull/7025
1065
+ // https://github.com/npm/cli/pull/7025.
1087
1066
  else if (oldOverrideSet) {
1088
1067
  // Propagate the new override set to the target node.
1089
1068
  this.#safeTo.updateOverridesEdgeInRemoved(oldOverrideSet);
@@ -1134,7 +1113,6 @@ class SafeEdge extends Edge {
1134
1113
  }
1135
1114
  }
1136
1115
 
1137
- const pacote = require(pacotePath);
1138
1116
  const {
1139
1117
  LOOP_SENTINEL,
1140
1118
  NPM,
@@ -1161,22 +1139,22 @@ function findBestPatchVersion(name, availableVersions, currentMajorVersion, vuln
1161
1139
  // Use semver to find the max satisfying version.
1162
1140
  return semver.maxSatisfying(eligibleVersions, '*');
1163
1141
  }
1164
- function findPackage(tree, packageName) {
1142
+ function findPackageNodes(tree, packageName) {
1165
1143
  const queue = [{
1166
1144
  node: tree
1167
1145
  }];
1146
+ const matches = [];
1168
1147
  let sentinel = 0;
1169
1148
  while (queue.length) {
1170
1149
  if (sentinel++ === LOOP_SENTINEL) {
1171
- throw new Error('Detected infinite loop in findPackage');
1150
+ throw new Error('Detected infinite loop in findPackageNodes');
1172
1151
  }
1173
1152
  const {
1174
1153
  node: currentNode
1175
1154
  } = queue.pop();
1176
1155
  const node = currentNode.children.get(packageName);
1177
1156
  if (node) {
1178
- // Found package.
1179
- return node;
1157
+ matches.push(node);
1180
1158
  }
1181
1159
  const children = [...currentNode.children.values()];
1182
1160
  for (let i = children.length - 1; i >= 0; i -= 1) {
@@ -1185,18 +1163,19 @@ function findPackage(tree, packageName) {
1185
1163
  });
1186
1164
  }
1187
1165
  }
1188
- return null;
1166
+ return matches;
1189
1167
  }
1190
- async function getPackagesAlerts(safeArb, pkgs, options) {
1168
+ async function getPackagesAlerts(details, options) {
1191
1169
  let {
1192
1170
  length: remaining
1193
- } = pkgs;
1171
+ } = details;
1194
1172
  const packageAlerts = [];
1195
1173
  if (!remaining) {
1196
1174
  return packageAlerts;
1197
1175
  }
1198
1176
  const {
1199
- fixable,
1177
+ includeExisting = false,
1178
+ includeUnfixable = true,
1200
1179
  output
1201
1180
  } = {
1202
1181
  __proto__: null,
@@ -1208,7 +1187,7 @@ async function getPackagesAlerts(safeArb, pkgs, options) {
1208
1187
  const getText = spinner$1 ? () => `Looking up data for ${remaining} packages` : () => '';
1209
1188
  spinner$1?.start(getText());
1210
1189
  try {
1211
- for await (const artifact of batchScan(pkgs.map(p => p.pkgid))) {
1190
+ for await (const artifact of batchScan(arrays.arrayUnique(details.map(d => d.node.pkgid)))) {
1212
1191
  if (!artifact.name || !artifact.version || !artifact.alerts?.length) {
1213
1192
  continue;
1214
1193
  }
@@ -1217,7 +1196,6 @@ async function getPackagesAlerts(safeArb, pkgs, options) {
1217
1196
  } = artifact;
1218
1197
  const name = packages.resolvePackageName(artifact);
1219
1198
  const id = `${name}@${artifact.version}`;
1220
- let blocked = false;
1221
1199
  let displayWarning = false;
1222
1200
  let alerts = [];
1223
1201
  for (const alert of artifact.alerts) {
@@ -1231,15 +1209,12 @@ async function getPackagesAlerts(safeArb, pkgs, options) {
1231
1209
  type: alert.type
1232
1210
  }
1233
1211
  });
1234
- if (ux.block) {
1235
- blocked = true;
1236
- }
1237
1212
  if (ux.display && output) {
1238
1213
  displayWarning = true;
1239
1214
  }
1240
1215
  if (ux.block || ux.display) {
1241
- const isFixable = isAlertFixable(alert);
1242
- if (!fixable || isFixable) {
1216
+ const fixable = isArtifactAlertFixable(alert);
1217
+ if (includeUnfixable || fixable) {
1243
1218
  alerts.push({
1244
1219
  name,
1245
1220
  version,
@@ -1247,38 +1222,27 @@ async function getPackagesAlerts(safeArb, pkgs, options) {
1247
1222
  type: alert.type,
1248
1223
  block: ux.block,
1249
1224
  raw: alert,
1250
- fixable: isFixable
1225
+ fixable
1251
1226
  });
1252
1227
  }
1253
1228
  // Lazily access constants.IPC.
1254
- if (!fixable && !constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE]) {
1229
+ if (includeExisting && !constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE]) {
1255
1230
  // Before we ask about problematic issues, check to see if they
1256
1231
  // already existed in the old version if they did, be quiet.
1257
- const existing = pkgs.find(p => p.existing?.startsWith(`${name}@`))?.existing;
1232
+ const existing = details.find(d => d.existing?.pkgid.startsWith(`${name}@`))?.existing;
1258
1233
  if (existing) {
1259
1234
  const oldArtifact =
1260
1235
  // eslint-disable-next-line no-await-in-loop
1261
- (await batchScan([existing]).next()).value;
1236
+ (await batchScan([existing.pkgid]).next()).value;
1262
1237
  if (oldArtifact?.alerts?.length) {
1263
1238
  alerts = alerts.filter(({
1264
1239
  type
1265
- }) => !oldArtifact.alerts?.find(a => a.type === type));
1240
+ }) => !oldArtifact.alerts.find(a => a.type === type));
1266
1241
  }
1267
1242
  }
1268
1243
  }
1269
1244
  }
1270
1245
  }
1271
- if (!blocked) {
1272
- const pkg = pkgs.find(p => p.pkgid === id);
1273
- if (pkg) {
1274
- await pacote.tarball.stream(id, stream => {
1275
- stream.resume();
1276
- return stream.promise();
1277
- }, {
1278
- ...safeArb[kCtorArgs][0]
1279
- });
1280
- }
1281
- }
1282
1246
  if (displayWarning && spinner$1) {
1283
1247
  spinner$1.stop(`(socket) ${formatter.hyperlink(id, socketUrl.getSocketDevPackageOverviewUrl(NPM, name, version))} contains risks:`);
1284
1248
  }
@@ -1324,23 +1288,23 @@ function getTranslations() {
1324
1288
  }
1325
1289
  return _translations;
1326
1290
  }
1327
- function packageAlertsToReport(alerts) {
1328
- let report = null;
1291
+ async function updateAdvisoryDependencies(arb, alerts) {
1292
+ let alertsByPkg;
1329
1293
  for (const alert of alerts) {
1330
- if (!isAlertFixableCve(alert.raw)) {
1294
+ if (!isArtifactAlertCveFixable(alert.raw)) {
1331
1295
  continue;
1332
1296
  }
1297
+ if (!alertsByPkg) {
1298
+ alertsByPkg = {};
1299
+ }
1333
1300
  const {
1334
1301
  name
1335
1302
  } = alert;
1336
- if (!report) {
1337
- report = {};
1338
- }
1339
- if (!report[name]) {
1340
- report[name] = [];
1303
+ if (!alertsByPkg[name]) {
1304
+ alertsByPkg[name] = [];
1341
1305
  }
1342
1306
  const props = alert.raw?.props;
1343
- report[name].push({
1307
+ alertsByPkg[name].push({
1344
1308
  id: -1,
1345
1309
  url: props?.url,
1346
1310
  title: props?.title,
@@ -1351,92 +1315,89 @@ function packageAlertsToReport(alerts) {
1351
1315
  name
1352
1316
  });
1353
1317
  }
1354
- return report;
1355
- }
1356
- async function updateAdvisoryDependencies(arb, alerts) {
1357
- const report = packageAlertsToReport(alerts);
1358
- if (!report) {
1318
+ if (!alertsByPkg) {
1359
1319
  // No advisories to process.
1360
1320
  return;
1361
1321
  }
1362
1322
  await arb.buildIdealTree();
1363
1323
  const tree = arb.idealTree;
1364
- for (const name of Object.keys(report)) {
1365
- const advisories = report[name];
1366
- const node = findPackage(tree, name);
1367
- if (!node) {
1368
- // Package not found in the tree.
1324
+ for (const name of Object.keys(alertsByPkg)) {
1325
+ const nodes = findPackageNodes(tree, name);
1326
+ if (!nodes.length) {
1369
1327
  continue;
1370
1328
  }
1371
- const {
1372
- version
1373
- } = node;
1374
- const majorVerNum = semver.major(version);
1375
-
1376
1329
  // Fetch packument to get available versions.
1377
1330
  // eslint-disable-next-line no-await-in-loop
1378
1331
  const packument = await packages.fetchPackagePackument(name);
1379
- const availableVersions = packument ? Object.keys(packument.versions) : [];
1380
- for (const advisory of advisories) {
1381
- const {
1382
- vulnerable_versions
1383
- } = advisory;
1384
- // Find the highest non-vulnerable version within the same major range
1385
- const targetVersion = findBestPatchVersion(name, availableVersions, majorVerNum, vulnerable_versions);
1386
- const targetPackument = targetVersion ? packument.versions[targetVersion] : undefined;
1387
- // Check !targetVersion to make TypeScript happy.
1388
- if (!targetVersion || !targetPackument) {
1389
- // No suitable patch version found.
1390
- continue;
1391
- }
1392
-
1393
- // Use Object.defineProperty to override the version.
1394
- Object.defineProperty(node, 'version', {
1395
- configurable: true,
1396
- enumerable: true,
1397
- get: () => targetVersion
1398
- });
1399
- node.package.version = targetVersion;
1400
- // Update resolved and clear integrity for the new version.
1401
- node.resolved = `${NPM_REGISTRY_URL}/${name}/-/${name}-${targetVersion}.tgz`;
1402
- if (node.integrity) {
1403
- delete node.integrity;
1404
- }
1405
- if ('deprecated' in targetPackument) {
1406
- node.package['deprecated'] = targetPackument.deprecated;
1407
- } else {
1408
- delete node.package['deprecated'];
1409
- }
1410
- const newDeps = {
1411
- ...targetPackument.dependencies
1412
- };
1332
+ for (const node of nodes) {
1413
1333
  const {
1414
- dependencies: oldDeps
1415
- } = node.package;
1416
- node.package.dependencies = newDeps;
1417
- if (oldDeps) {
1418
- for (const oldDepName of Object.keys(oldDeps)) {
1419
- if (!objects.hasOwn(newDeps, oldDepName)) {
1420
- node.edgesOut.get(oldDepName)?.detach();
1334
+ version
1335
+ } = node;
1336
+ const majorVerNum = semver.major(version);
1337
+ const availableVersions = packument ? Object.keys(packument.versions) : [];
1338
+ const pkgAlerts = alertsByPkg[name];
1339
+ for (const alert of pkgAlerts) {
1340
+ const {
1341
+ vulnerable_versions
1342
+ } = alert;
1343
+ // Find the highest non-vulnerable version within the same major range
1344
+ const targetVersion = findBestPatchVersion(name, availableVersions, majorVerNum, vulnerable_versions);
1345
+ const targetPackument = targetVersion ? packument.versions[targetVersion] : undefined;
1346
+ // Check !targetVersion to make TypeScript happy.
1347
+ if (!targetVersion || !targetPackument) {
1348
+ // No suitable patch version found.
1349
+ continue;
1350
+ }
1351
+ // Use Object.defineProperty to override the version.
1352
+ Object.defineProperty(node, 'version', {
1353
+ configurable: true,
1354
+ enumerable: true,
1355
+ get: () => targetVersion
1356
+ });
1357
+ node.package.version = targetVersion;
1358
+ // Update resolved and clear integrity for the new version.
1359
+ node.resolved = `${NPM_REGISTRY_URL}/${name}/-/${name}-${targetVersion}.tgz`;
1360
+ if (node.integrity) {
1361
+ delete node.integrity;
1362
+ }
1363
+ if ('deprecated' in targetPackument) {
1364
+ node.package['deprecated'] = targetPackument.deprecated;
1365
+ } else {
1366
+ delete node.package['deprecated'];
1367
+ }
1368
+ const newDeps = {
1369
+ ...targetPackument.dependencies
1370
+ };
1371
+ const {
1372
+ dependencies: oldDeps
1373
+ } = node.package;
1374
+ node.package.dependencies = newDeps;
1375
+ if (oldDeps) {
1376
+ for (const oldDepName of Object.keys(oldDeps)) {
1377
+ if (!objects.hasOwn(newDeps, oldDepName)) {
1378
+ node.edgesOut.get(oldDepName)?.detach();
1379
+ }
1421
1380
  }
1422
1381
  }
1423
- }
1424
- for (const newDepName of Object.keys(newDeps)) {
1425
- if (!objects.hasOwn(oldDeps, newDepName)) {
1426
- node.addEdgeOut(new Edge({
1427
- from: node,
1428
- name: newDepName,
1429
- spec: newDeps[newDepName],
1430
- type: 'prod'
1431
- }));
1382
+ for (const newDepName of Object.keys(newDeps)) {
1383
+ if (!objects.hasOwn(oldDeps, newDepName)) {
1384
+ node.addEdgeOut(new Edge({
1385
+ from: node,
1386
+ name: newDepName,
1387
+ spec: newDeps[newDepName],
1388
+ type: 'prod'
1389
+ }));
1390
+ }
1432
1391
  }
1433
1392
  }
1434
1393
  }
1435
1394
  }
1436
1395
  }
1437
1396
  async function reify(...args) {
1438
- const needInfoOn = await walk(this.diff);
1439
- if (!needInfoOn.length || needInfoOn.findIndex(c => c.repository_url === NPM_REGISTRY_URL) === -1) {
1397
+ // We are assuming `this[_diffTrees]()` has been called by `super.reify(...)`:
1398
+ // https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/arborist/reify.js#L141
1399
+ const needInfoOn = getPackagesToQueryFromDiff(this.diff);
1400
+ if (!needInfoOn.length) {
1440
1401
  // Nothing to check, hmmm already installed or all private?
1441
1402
  return await this[kRiskyReify](...args);
1442
1403
  }
@@ -1449,64 +1410,54 @@ async function reify(...args) {
1449
1410
  stderr: output,
1450
1411
  stdin: input
1451
1412
  } = process;
1452
- let alerts;
1453
- const proceed = bypassAlerts || (await (async () => {
1454
- alerts = await getPackagesAlerts(this, needInfoOn, {
1455
- output
1456
- });
1457
- if (bypassConfirms || !alerts.length) {
1413
+ let alerts = bypassAlerts ? [] : await getPackagesAlerts(needInfoOn, {
1414
+ output
1415
+ });
1416
+ if (alerts.length && !bypassConfirms && !(await prompts.confirm({
1417
+ message: 'Accept risks of installing these packages?',
1418
+ default: false
1419
+ }, {
1420
+ input,
1421
+ output,
1422
+ signal: abortSignal
1423
+ }))) {
1424
+ throw new Error('Socket npm exiting due to risks');
1425
+ }
1426
+ if (!alerts.length || !bypassConfirms && !(await prompts.confirm({
1427
+ message: 'Try to fix alerts?',
1428
+ default: true
1429
+ }, {
1430
+ input,
1431
+ output,
1432
+ signal: abortSignal
1433
+ }))) {
1434
+ return await this[kRiskyReify](...args);
1435
+ }
1436
+ const prev = new Set(alerts.map(a => a.key));
1437
+ let ret;
1438
+ /* eslint-disable no-await-in-loop */
1439
+ while (alerts.length > 0) {
1440
+ await updateAdvisoryDependencies(this, alerts);
1441
+ ret = await this[kRiskyReify](...args);
1442
+ await this.loadActual();
1443
+ await this.buildIdealTree();
1444
+ alerts = (await getPackagesAlerts(getPackagesToQueryFromDiff(this.diff, {
1445
+ includeUnchanged: true
1446
+ }), {
1447
+ includeExisting: true,
1448
+ includeUnfixable: true
1449
+ })).filter(({
1450
+ key
1451
+ }) => {
1452
+ if (prev.has(key)) {
1453
+ return false;
1454
+ }
1455
+ prev.add(key);
1458
1456
  return true;
1459
- }
1460
- return await prompts.confirm({
1461
- message: 'Accept risks of installing these packages?',
1462
- default: false
1463
- }, {
1464
- input,
1465
- output,
1466
- signal: abortSignal
1467
1457
  });
1468
- })());
1469
- if (proceed) {
1470
- const fix = !!alerts?.length && (bypassConfirms || (await prompts.confirm({
1471
- message: 'Try to fix alerts?',
1472
- default: true
1473
- }, {
1474
- input,
1475
- output,
1476
- signal: abortSignal
1477
- })));
1478
- if (fix) {
1479
- let ret;
1480
- const prev = new Set(alerts?.map(a => a.key));
1481
- /* eslint-disable no-await-in-loop */
1482
- while (alerts.length > 0) {
1483
- await updateAdvisoryDependencies(this, alerts);
1484
- ret = await this[kRiskyReify](...args);
1485
- await this.loadActual();
1486
- await this.buildIdealTree();
1487
- alerts = await getPackagesAlerts(this, await walk(this.diff, {
1488
- fix: true
1489
- }), {
1490
- fixable: true
1491
- });
1492
- alerts = alerts.filter(a => {
1493
- const {
1494
- key
1495
- } = a;
1496
- if (prev.has(key)) {
1497
- return false;
1498
- }
1499
- prev.add(key);
1500
- return true;
1501
- });
1502
- }
1503
- /* eslint-enable no-await-in-loop */
1504
- return ret;
1505
- }
1506
- return await this[kRiskyReify](...args);
1507
- } else {
1508
- throw new Error('Socket npm exiting due to risks');
1509
1458
  }
1459
+ /* eslint-enable no-await-in-loop */
1460
+ return ret;
1510
1461
  }
1511
1462
 
1512
1463
  const Arborist = require(arboristClassPath);
@@ -1556,8 +1507,6 @@ class SafeArborist extends Arborist {
1556
1507
  options.dryRun = true;
1557
1508
  options.save = false;
1558
1509
  options.saveBundle = false;
1559
- // TODO: Make this deal with any refactor to private fields by punching the
1560
- // class itself.
1561
1510
  await super.reify(...args);
1562
1511
  options.dryRun = old.dryRun;
1563
1512
  options.save = old.save;
@@ -1567,6 +1516,8 @@ class SafeArborist extends Arborist {
1567
1516
  }
1568
1517
 
1569
1518
  function installSafeArborist() {
1519
+ // Override '@npmcli/arborist' module exports with patched variants based on
1520
+ // https://github.com/npm/cli/pull/7025.
1570
1521
  const cache = require.cache;
1571
1522
  cache[arboristClassPath] = {
1572
1523
  exports: SafeArborist