@socketsecurity/cli 0.14.39 → 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.
- package/README.md +1 -1
- package/bin/cli.js +12 -6
- package/dist/{module-sync/constants.d.ts → constants.d.ts} +13 -2
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +24 -10
- package/dist/module-sync/cli.js +455 -404
- package/dist/module-sync/debug.d.ts +3 -0
- package/dist/module-sync/errors.d.ts +3 -1
- package/dist/module-sync/logging.d.ts +16 -0
- package/dist/module-sync/npm-injection.js +1119 -1095
- package/dist/module-sync/path-resolve.d.ts +1 -1
- package/dist/module-sync/path-resolve.js +50 -5
- package/dist/module-sync/settings.d.ts +6 -1
- package/dist/module-sync/shadow-bin.d.ts +2 -2
- package/dist/module-sync/shadow-bin.js +23 -40
- package/dist/module-sync/socket-url.d.ts +40 -0
- package/dist/module-sync/socket-url.js +301 -0
- package/dist/require/cli.js +454 -401
- package/dist/require/npm-injection.js +2 -1511
- package/dist/require/path-resolve.js +2 -200
- package/dist/require/shadow-bin.js +2 -102
- package/dist/require/socket-url.js +3 -0
- package/dist/require/vendor.js +53 -400
- package/package.json +39 -31
- package/dist/module-sync/color-or-markdown.d.ts +0 -23
- package/dist/module-sync/constants.d.ts.map +0 -1
- package/dist/module-sync/sdk.d.ts +0 -8
- package/dist/module-sync/sdk.js +0 -214
- package/dist/require/constants.d.ts.map +0 -1
- package/dist/require/sdk.js +0 -212
|
@@ -9,218 +9,165 @@ function _socketInterop(e) {
|
|
|
9
9
|
return c ? e.default : e
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
var events = require('node:events');
|
|
13
|
-
var fs = require('node:fs');
|
|
14
|
-
var https = require('node:https');
|
|
15
12
|
var path = require('node:path');
|
|
16
|
-
var
|
|
17
|
-
var promises = require('node:timers/promises');
|
|
18
|
-
var prompts = require('@socketsecurity/registry/lib/prompts');
|
|
19
|
-
var yoctoSpinner = require('@socketregistry/yocto-spinner');
|
|
20
|
-
var isInteractive = _socketInterop(require('is-interactive'));
|
|
21
|
-
var npa = _socketInterop(require('npm-package-arg'));
|
|
13
|
+
var process = require('node:process');
|
|
22
14
|
var semver = _socketInterop(require('semver'));
|
|
23
|
-
var
|
|
15
|
+
var registry = require('@socketsecurity/registry');
|
|
16
|
+
var arrays = require('@socketsecurity/registry/lib/arrays');
|
|
24
17
|
var objects = require('@socketsecurity/registry/lib/objects');
|
|
25
18
|
var packages = require('@socketsecurity/registry/lib/packages');
|
|
26
|
-
var
|
|
27
|
-
var
|
|
28
|
-
var node_stream = require('node:stream');
|
|
29
|
-
var sdk = require('./sdk.js');
|
|
19
|
+
var prompts = require('@socketsecurity/registry/lib/prompts');
|
|
20
|
+
var spinner = require('@socketsecurity/registry/lib/spinner');
|
|
30
21
|
var constants = require('./constants.js');
|
|
22
|
+
var events = require('node:events');
|
|
23
|
+
var https = require('node:https');
|
|
24
|
+
var readline = require('node:readline');
|
|
25
|
+
var socketUrl = require('./socket-url.js');
|
|
26
|
+
var promises = require('node:timers/promises');
|
|
31
27
|
var pathResolve = require('./path-resolve.js');
|
|
28
|
+
var fs = require('node:fs');
|
|
29
|
+
var npa = _socketInterop(require('npm-package-arg'));
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return await new Promise((resolve, reject) => {
|
|
44
|
-
const conn = net.createConnection({
|
|
45
|
-
path: TTY_IPC
|
|
46
|
-
}).on('error', reject);
|
|
47
|
-
let captured = false;
|
|
48
|
-
const buffs = [];
|
|
49
|
-
conn.on('data', function awaitCapture(chunk) {
|
|
50
|
-
buffs.push(chunk);
|
|
51
|
-
let lineBuff = Buffer.concat(buffs);
|
|
52
|
-
if (captured) return;
|
|
53
|
-
try {
|
|
54
|
-
const eolIndex = lineBuff.indexOf(NEWLINE_CHAR_CODE);
|
|
55
|
-
if (eolIndex !== -1) {
|
|
56
|
-
conn.removeListener('data', awaitCapture);
|
|
57
|
-
conn.push(lineBuff.slice(eolIndex + 1));
|
|
58
|
-
const {
|
|
59
|
-
capabilities: {
|
|
60
|
-
input: hasInput,
|
|
61
|
-
output: hasOutput
|
|
62
|
-
},
|
|
63
|
-
ipc_version: remote_ipc_version
|
|
64
|
-
} = JSON.parse(lineBuff.subarray(0, eolIndex).toString('utf8'));
|
|
65
|
-
lineBuff = null;
|
|
66
|
-
captured = true;
|
|
67
|
-
if (remote_ipc_version !== version) {
|
|
68
|
-
throw new Error('Mismatched STDIO tunnel IPC version, ensure you only have 1 version of socket CLI being called.');
|
|
69
|
-
}
|
|
70
|
-
const input = hasInput ? new node_stream.PassThrough() : null;
|
|
71
|
-
input?.pause();
|
|
72
|
-
if (input) conn.pipe(input);
|
|
73
|
-
const output = hasOutput ? new node_stream.PassThrough() : null;
|
|
74
|
-
if (output) {
|
|
75
|
-
output.pipe(conn)
|
|
76
|
-
// Make ora happy
|
|
77
|
-
;
|
|
78
|
-
output.isTTY = true;
|
|
79
|
-
output.cursorTo = function cursorTo(x, y, callback) {
|
|
80
|
-
readline.cursorTo(this, x, y, callback);
|
|
81
|
-
};
|
|
82
|
-
output.clearLine = function clearLine(dir, callback) {
|
|
83
|
-
readline.clearLine(this, dir, callback);
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
mutexFn(hasInput ? input : undefined, hasOutput ? output : undefined).then(resolve, reject).finally(() => {
|
|
87
|
-
conn.unref();
|
|
88
|
-
conn.end();
|
|
89
|
-
input?.end();
|
|
90
|
-
output?.end();
|
|
91
|
-
// process.exit(13)
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
} catch (e) {
|
|
95
|
-
reject(e);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
};
|
|
31
|
+
const {
|
|
32
|
+
LOOP_SENTINEL: LOOP_SENTINEL$2,
|
|
33
|
+
NPM_REGISTRY_URL: NPM_REGISTRY_URL$1,
|
|
34
|
+
SOCKET_CLI_FIX_PACKAGE_LOCK_FILE: SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1
|
|
35
|
+
} = constants;
|
|
36
|
+
function getUrlOrigin(input) {
|
|
37
|
+
try {
|
|
38
|
+
return URL.parse(input)?.origin ?? '';
|
|
39
|
+
} catch {}
|
|
40
|
+
return '';
|
|
101
41
|
}
|
|
102
|
-
function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
42
|
+
function getPackagesToQueryFromDiff(diff_, options) {
|
|
43
|
+
const {
|
|
44
|
+
// Lazily access constants.IPC.
|
|
45
|
+
includeUnchanged = constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE$1],
|
|
46
|
+
includeUnknownOrigin = false
|
|
47
|
+
} = {
|
|
48
|
+
__proto__: null,
|
|
49
|
+
...options
|
|
50
|
+
};
|
|
51
|
+
const details = [];
|
|
52
|
+
// `diff_` is `null` when `npm install --package-lock-only` is passed.
|
|
53
|
+
if (!diff_) {
|
|
54
|
+
return details;
|
|
55
|
+
}
|
|
56
|
+
const queue = [...diff_.children];
|
|
57
|
+
let pos = 0;
|
|
58
|
+
let {
|
|
59
|
+
length: queueLength
|
|
60
|
+
} = queue;
|
|
61
|
+
while (pos < queueLength) {
|
|
62
|
+
if (pos === LOOP_SENTINEL$2) {
|
|
63
|
+
throw new Error('Detected infinite loop while walking Arborist diff');
|
|
64
|
+
}
|
|
65
|
+
const diff = queue[pos++];
|
|
66
|
+
const {
|
|
67
|
+
action
|
|
68
|
+
} = diff;
|
|
69
|
+
if (action) {
|
|
70
|
+
// The `pkgNode`, i.e. the `ideal` node, will be `undefined` if the diff
|
|
71
|
+
// action is 'REMOVE'
|
|
72
|
+
// The `oldNode`, i.e. the `actual` node, will be `undefined` if the diff
|
|
73
|
+
// action is 'ADD'.
|
|
74
|
+
const {
|
|
75
|
+
actual: oldNode,
|
|
76
|
+
ideal: pkgNode
|
|
77
|
+
} = diff;
|
|
78
|
+
let existing;
|
|
79
|
+
let keep = false;
|
|
80
|
+
if (action === 'CHANGE') {
|
|
81
|
+
if (pkgNode?.package.version !== oldNode?.package.version) {
|
|
82
|
+
keep = true;
|
|
83
|
+
if (oldNode?.package.name && oldNode.package.name === pkgNode?.package.name) {
|
|
84
|
+
existing = oldNode;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
117
87
|
} else {
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
const wasProgressEnabled = npmlog.progressEnabled;
|
|
121
|
-
npmlog.pause();
|
|
122
|
-
if (wasProgressEnabled) {
|
|
123
|
-
npmlog.disableProgress();
|
|
88
|
+
keep = action !== 'REMOVE';
|
|
124
89
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
output.write(data);
|
|
134
|
-
}).on('error', e => {
|
|
135
|
-
output.write(`there was an error prompting from a sub shell (${e?.message}), socket npm closing`);
|
|
136
|
-
process.exit(1);
|
|
137
|
-
});
|
|
138
|
-
input.on('data', data => {
|
|
139
|
-
conn.write(data);
|
|
140
|
-
}).on('end', () => {
|
|
141
|
-
conn.unref();
|
|
142
|
-
conn.end();
|
|
143
|
-
if (wasProgressEnabled) {
|
|
144
|
-
npmlog.enableProgress();
|
|
90
|
+
if (keep && pkgNode?.resolved && (!oldNode || oldNode.resolved)) {
|
|
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
|
+
});
|
|
145
98
|
}
|
|
146
|
-
npmlog.resume();
|
|
147
|
-
captureState.nextCapture();
|
|
148
|
-
});
|
|
149
|
-
}).listen(sock, () => resolve(server)).on('error', reject).unref();
|
|
150
|
-
process.on('exit', () => {
|
|
151
|
-
server.close();
|
|
152
|
-
tryUnlinkSync(sock);
|
|
153
|
-
});
|
|
154
|
-
resolve(server);
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
function createStandardTTYServer(isInteractive, npmlog) {
|
|
158
|
-
const captureState = {
|
|
159
|
-
captured: false,
|
|
160
|
-
nextCapture: () => {
|
|
161
|
-
if (captureState.pendingCaptures.length > 0) {
|
|
162
|
-
const pendingCapture = captureState.pendingCaptures.shift();
|
|
163
|
-
pendingCapture?.resolve();
|
|
164
|
-
} else {
|
|
165
|
-
captureState.captured = false;
|
|
166
99
|
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const input = isInteractive ? process.stdin : undefined;
|
|
172
|
-
const output = process.stderr;
|
|
173
|
-
let ipcServerPromise;
|
|
174
|
-
if (input) {
|
|
175
|
-
ipcServerPromise = createIPCServer(captureState, npmlog);
|
|
100
|
+
}
|
|
101
|
+
for (const child of diff.children) {
|
|
102
|
+
queue[queueLength++] = child;
|
|
103
|
+
}
|
|
176
104
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
105
|
+
if (includeUnchanged) {
|
|
106
|
+
const {
|
|
107
|
+
unchanged
|
|
108
|
+
} = diff_;
|
|
109
|
+
for (let i = 0, {
|
|
110
|
+
length
|
|
111
|
+
} = unchanged; i < length; i += 1) {
|
|
112
|
+
const pkgNode = unchanged[i];
|
|
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
|
|
187
119
|
});
|
|
188
|
-
await captured;
|
|
189
|
-
} else {
|
|
190
|
-
captureState.captured = true;
|
|
191
|
-
}
|
|
192
|
-
const wasProgressEnabled = npmlog.progressEnabled;
|
|
193
|
-
try {
|
|
194
|
-
npmlog.pause();
|
|
195
|
-
if (wasProgressEnabled) {
|
|
196
|
-
npmlog.disableProgress();
|
|
197
|
-
}
|
|
198
|
-
return await mutexFn(input, output);
|
|
199
|
-
} finally {
|
|
200
|
-
if (wasProgressEnabled) {
|
|
201
|
-
npmlog.enableProgress();
|
|
202
|
-
}
|
|
203
|
-
npmlog.resume();
|
|
204
|
-
captureState.nextCapture();
|
|
205
120
|
}
|
|
206
121
|
}
|
|
207
|
-
}
|
|
122
|
+
}
|
|
123
|
+
return details;
|
|
208
124
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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);
|
|
216
152
|
}
|
|
217
153
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
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);
|
|
220
162
|
}
|
|
221
163
|
|
|
222
|
-
|
|
223
|
-
|
|
164
|
+
const {
|
|
165
|
+
abortSignal: abortSignal$1
|
|
166
|
+
} = constants;
|
|
167
|
+
const ERROR_UX = {
|
|
168
|
+
block: true,
|
|
169
|
+
display: true
|
|
170
|
+
};
|
|
224
171
|
const IGNORE_UX = {
|
|
225
172
|
block: false,
|
|
226
173
|
display: false
|
|
@@ -229,20 +176,12 @@ const WARN_UX = {
|
|
|
229
176
|
block: false,
|
|
230
177
|
display: true
|
|
231
178
|
};
|
|
232
|
-
const ERROR_UX = {
|
|
233
|
-
block: true,
|
|
234
|
-
display: true
|
|
235
|
-
};
|
|
236
|
-
//#endregion
|
|
237
|
-
//#region utils
|
|
238
179
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
* uses the defaultValue. Takes the value and converts into a UX workflow
|
|
243
|
-
*/
|
|
180
|
+
// Iterates over all entries with ordered issue rule for deferral. Iterates over
|
|
181
|
+
// all issue rules and finds the first defined value that does not defer otherwise
|
|
182
|
+
// uses the defaultValue. Takes the value and converts into a UX workflow.
|
|
244
183
|
function resolveAlertRuleUX(orderedRulesCollection, defaultValue) {
|
|
245
|
-
if (defaultValue === true || defaultValue
|
|
184
|
+
if (defaultValue === true || defaultValue === null || defaultValue === undefined) {
|
|
246
185
|
defaultValue = {
|
|
247
186
|
action: 'error'
|
|
248
187
|
};
|
|
@@ -279,13 +218,12 @@ function resolveAlertRuleUX(orderedRulesCollection, defaultValue) {
|
|
|
279
218
|
};
|
|
280
219
|
}
|
|
281
220
|
|
|
282
|
-
|
|
283
|
-
* Negative form because it is narrowing the type
|
|
284
|
-
*/
|
|
221
|
+
// Negative form because it is narrowing the type.
|
|
285
222
|
function ruleValueDoesNotDefer(rule) {
|
|
286
223
|
if (rule === undefined) {
|
|
287
224
|
return false;
|
|
288
|
-
}
|
|
225
|
+
}
|
|
226
|
+
if (objects.isObject(rule)) {
|
|
289
227
|
const {
|
|
290
228
|
action
|
|
291
229
|
} = rule;
|
|
@@ -296,9 +234,7 @@ function ruleValueDoesNotDefer(rule) {
|
|
|
296
234
|
return true;
|
|
297
235
|
}
|
|
298
236
|
|
|
299
|
-
|
|
300
|
-
* Handles booleans for backwards compatibility
|
|
301
|
-
*/
|
|
237
|
+
// Handles booleans for backwards compatibility.
|
|
302
238
|
function uxForDefinedNonDeferValue(ruleValue) {
|
|
303
239
|
if (typeof ruleValue === 'boolean') {
|
|
304
240
|
return ruleValue ? ERROR_UX : IGNORE_UX;
|
|
@@ -313,10 +249,6 @@ function uxForDefinedNonDeferValue(ruleValue) {
|
|
|
313
249
|
}
|
|
314
250
|
return ERROR_UX;
|
|
315
251
|
}
|
|
316
|
-
//#endregion
|
|
317
|
-
|
|
318
|
-
//#region exports
|
|
319
|
-
|
|
320
252
|
function createAlertUXLookup(settings) {
|
|
321
253
|
const cachedUX = new Map();
|
|
322
254
|
return context => {
|
|
@@ -362,22 +294,115 @@ function createAlertUXLookup(settings) {
|
|
|
362
294
|
return ux;
|
|
363
295
|
};
|
|
364
296
|
}
|
|
365
|
-
|
|
297
|
+
let _uxLookup;
|
|
298
|
+
async function uxLookup(settings) {
|
|
299
|
+
while (_uxLookup === undefined) {
|
|
300
|
+
// eslint-disable-next-line no-await-in-loop
|
|
301
|
+
await promises.setTimeout(1, {
|
|
302
|
+
signal: abortSignal$1
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
return _uxLookup(settings);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Start initializing the AlertUxLookupResult immediately.
|
|
309
|
+
void (async () => {
|
|
310
|
+
const {
|
|
311
|
+
orgs,
|
|
312
|
+
settings
|
|
313
|
+
} = await (async () => {
|
|
314
|
+
try {
|
|
315
|
+
const socketSdk = await socketUrl.setupSdk(socketUrl.getPublicToken());
|
|
316
|
+
const orgResult = await socketSdk.getOrganizations();
|
|
317
|
+
if (!orgResult.success) {
|
|
318
|
+
throw new Error(`Failed to fetch Socket organization info: ${orgResult.error.message}`);
|
|
319
|
+
}
|
|
320
|
+
const orgs = [];
|
|
321
|
+
for (const org of Object.values(orgResult.data.organizations)) {
|
|
322
|
+
if (org) {
|
|
323
|
+
orgs.push(org);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const result = await socketSdk.postSettings(orgs.map(org => ({
|
|
327
|
+
organization: org.id
|
|
328
|
+
})));
|
|
329
|
+
if (!result.success) {
|
|
330
|
+
throw new Error(`Failed to fetch API key settings: ${result.error.message}`);
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
orgs,
|
|
334
|
+
settings: result.data
|
|
335
|
+
};
|
|
336
|
+
} catch (e) {
|
|
337
|
+
const cause = objects.isObject(e) && 'cause' in e ? e.cause : undefined;
|
|
338
|
+
if (socketUrl.isErrnoException(cause) && (cause.code === 'ENOTFOUND' || cause.code === 'ECONNREFUSED')) {
|
|
339
|
+
throw new Error('Unable to connect to socket.dev, ensure internet connectivity before retrying', {
|
|
340
|
+
cause: e
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
throw e;
|
|
344
|
+
}
|
|
345
|
+
})();
|
|
346
|
+
|
|
347
|
+
// Remove any organizations not being enforced.
|
|
348
|
+
const enforcedOrgs = socketUrl.getSetting('enforcedOrgs') ?? [];
|
|
349
|
+
for (const {
|
|
350
|
+
0: i,
|
|
351
|
+
1: org
|
|
352
|
+
} of orgs.entries()) {
|
|
353
|
+
if (!enforcedOrgs.includes(org.id)) {
|
|
354
|
+
settings.entries.splice(i, 1);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const socketYml = socketUrl.findSocketYmlSync();
|
|
358
|
+
if (socketYml) {
|
|
359
|
+
settings.entries.push({
|
|
360
|
+
start: socketYml.path,
|
|
361
|
+
settings: {
|
|
362
|
+
[socketYml.path]: {
|
|
363
|
+
deferTo: null,
|
|
364
|
+
// TODO: TypeScript complains about the type not matching. We should
|
|
365
|
+
// figure out why are providing
|
|
366
|
+
// issueRules: { [issueName: string]: boolean }
|
|
367
|
+
// but expecting
|
|
368
|
+
// issueRules: { [issueName: string]: { action: 'defer' | 'error' | 'ignore' | 'monitor' | 'warn' } }
|
|
369
|
+
issueRules: socketYml.parsed.issueRules
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
_uxLookup = createAlertUXLookup(settings);
|
|
375
|
+
})();
|
|
366
376
|
|
|
367
377
|
const {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
LOOP_SENTINEL,
|
|
371
|
-
NPM_REGISTRY_URL,
|
|
372
|
-
SOCKET_CLI_ISSUES_URL,
|
|
373
|
-
SOCKET_PUBLIC_API_KEY,
|
|
374
|
-
UPDATE_SOCKET_OVERRIDES_IN_PACKAGE_LOCK_FILE,
|
|
375
|
-
abortSignal,
|
|
376
|
-
rootPath
|
|
378
|
+
NODE_MODULES,
|
|
379
|
+
SOCKET_CLI_ISSUES_URL
|
|
377
380
|
} = constants;
|
|
378
|
-
const
|
|
379
|
-
const npmEntrypoint = fs.realpathSync(process.argv[1]);
|
|
381
|
+
const npmEntrypoint = fs.realpathSync.native(process.argv[1]);
|
|
380
382
|
const npmRootPath = pathResolve.findRoot(path.dirname(npmEntrypoint));
|
|
383
|
+
if (npmRootPath === undefined) {
|
|
384
|
+
console.error(`Unable to find npm CLI install directory.
|
|
385
|
+
Searched parent directories of ${npmEntrypoint}.
|
|
386
|
+
|
|
387
|
+
This is may be a bug with socket-npm related to changes to the npm CLI.
|
|
388
|
+
Please report to ${SOCKET_CLI_ISSUES_URL}.`);
|
|
389
|
+
// The exit code 127 indicates that the command or binary being executed
|
|
390
|
+
// could not be found.
|
|
391
|
+
process.exit(127);
|
|
392
|
+
}
|
|
393
|
+
const npmNmPath = path.join(npmRootPath, NODE_MODULES);
|
|
394
|
+
const arboristPkgPath = path.join(npmNmPath, '@npmcli/arborist');
|
|
395
|
+
const arboristClassPath = path.join(arboristPkgPath, 'lib/arborist/index.js');
|
|
396
|
+
const arboristDepValidPath = path.join(arboristPkgPath, 'lib/dep-valid.js');
|
|
397
|
+
const arboristEdgeClassPath = path.join(arboristPkgPath, 'lib/edge.js');
|
|
398
|
+
const arboristNodeClassPath = path.join(arboristPkgPath, 'lib/node.js');
|
|
399
|
+
const arboristOverrideSetClassPath = path.join(arboristPkgPath, 'lib/override-set.js');
|
|
400
|
+
|
|
401
|
+
const depValid = require(arboristDepValidPath);
|
|
402
|
+
|
|
403
|
+
const {
|
|
404
|
+
UNDEFINED_TOKEN
|
|
405
|
+
} = constants;
|
|
381
406
|
function tryRequire(...ids) {
|
|
382
407
|
for (const data of ids) {
|
|
383
408
|
let id;
|
|
@@ -400,320 +425,437 @@ function tryRequire(...ids) {
|
|
|
400
425
|
}
|
|
401
426
|
return undefined;
|
|
402
427
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const arboristDepValidPath = path.join(arboristPkgPath, 'lib/dep-valid.js');
|
|
413
|
-
const arboristEdgeClassPath = path.join(arboristPkgPath, 'lib/edge.js');
|
|
414
|
-
const arboristNodeClassPath = path.join(arboristPkgPath, 'lib/node.js');
|
|
415
|
-
const arboristOverrideSetClassPatch = path.join(arboristPkgPath, 'lib/override-set.js');
|
|
416
|
-
const log = tryRequire([path.join(npmNmPath, 'proc-log/lib/index.js'),
|
|
417
|
-
// The proc-log DefinitelyTyped definition is incorrect. The type definition
|
|
418
|
-
// is really that of its export log.
|
|
419
|
-
mod => mod.log], path.join(npmNmPath, 'npmlog/lib/log.js'));
|
|
420
|
-
if (log === undefined) {
|
|
421
|
-
console.error(`Unable to integrate with npm CLI logging infrastructure.\n\n${POTENTIAL_BUG_ERROR_MESSAGE}.`);
|
|
422
|
-
// The exit code 127 indicates that the command or binary being executed
|
|
423
|
-
// could not be found.
|
|
424
|
-
process.exit(127);
|
|
428
|
+
let _log = UNDEFINED_TOKEN;
|
|
429
|
+
function getLogger() {
|
|
430
|
+
if (_log === UNDEFINED_TOKEN) {
|
|
431
|
+
_log = tryRequire([path.join(npmNmPath, 'proc-log/lib/index.js'),
|
|
432
|
+
// The proc-log DefinitelyTyped definition is incorrect. The type definition
|
|
433
|
+
// is really that of its export log.
|
|
434
|
+
mod => mod.log], path.join(npmNmPath, 'npmlog/lib/log.js'));
|
|
435
|
+
}
|
|
436
|
+
return _log;
|
|
425
437
|
}
|
|
426
|
-
|
|
438
|
+
|
|
427
439
|
const {
|
|
428
|
-
|
|
429
|
-
} =
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}), log);
|
|
443
|
-
let _uxLookup;
|
|
444
|
-
async function uxLookup(settings) {
|
|
445
|
-
while (_uxLookup === undefined) {
|
|
446
|
-
// eslint-disable-next-line no-await-in-loop
|
|
447
|
-
await promises.setTimeout(1, {
|
|
448
|
-
signal: abortSignal
|
|
449
|
-
});
|
|
440
|
+
LOOP_SENTINEL: LOOP_SENTINEL$1
|
|
441
|
+
} = constants;
|
|
442
|
+
const OverrideSet = require(arboristOverrideSetClassPath);
|
|
443
|
+
|
|
444
|
+
// Implementation code not related to patch https://github.com/npm/cli/pull/7025
|
|
445
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/override-set.js:
|
|
446
|
+
class SafeOverrideSet extends OverrideSet {
|
|
447
|
+
// Patch adding doOverrideSetsConflict is based on
|
|
448
|
+
// https://github.com/npm/cli/pull/7025.
|
|
449
|
+
static doOverrideSetsConflict(first, second) {
|
|
450
|
+
// If override sets contain one another then we can try to use the more specific
|
|
451
|
+
// one. However, if neither one is more specific, then we consider them to be
|
|
452
|
+
// in conflict.
|
|
453
|
+
return this.findSpecificOverrideSet(first, second) === undefined;
|
|
450
454
|
}
|
|
451
|
-
return _uxLookup(settings);
|
|
452
|
-
}
|
|
453
|
-
async function* batchScan(pkgIds) {
|
|
454
|
-
const req = https.request(`${API_V0_URL}/purl?alerts=true`, {
|
|
455
|
-
method: 'POST',
|
|
456
|
-
headers: {
|
|
457
|
-
Authorization: `Basic ${Buffer.from(`${pubToken}:`).toString('base64url')}`
|
|
458
|
-
},
|
|
459
|
-
signal: abortSignal
|
|
460
|
-
}).end(JSON.stringify({
|
|
461
|
-
components: pkgIds.map(id => ({
|
|
462
|
-
purl: `pkg:npm/${id}`
|
|
463
|
-
}))
|
|
464
|
-
}));
|
|
465
|
-
const {
|
|
466
|
-
0: res
|
|
467
|
-
} = await events.once(req, 'response');
|
|
468
|
-
const ok = res.statusCode >= 200 && res.statusCode <= 299;
|
|
469
|
-
if (!ok) {
|
|
470
|
-
throw new Error(`Socket API Error: ${res.statusCode}`);
|
|
471
|
-
}
|
|
472
|
-
const rli = readline.createInterface(res);
|
|
473
|
-
for await (const line of rli) {
|
|
474
|
-
yield JSON.parse(line);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
455
|
|
|
478
|
-
// Patch adding
|
|
479
|
-
// https://github.com/npm/cli/pull/7025.
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
function findSocketYmlSync() {
|
|
487
|
-
let prevDir = null;
|
|
488
|
-
let dir = process.cwd();
|
|
489
|
-
while (dir !== prevDir) {
|
|
490
|
-
let ymlPath = path.join(dir, 'socket.yml');
|
|
491
|
-
let yml = maybeReadfileSync(ymlPath);
|
|
492
|
-
if (yml === undefined) {
|
|
493
|
-
ymlPath = path.join(dir, 'socket.yaml');
|
|
494
|
-
yml = maybeReadfileSync(ymlPath);
|
|
495
|
-
}
|
|
496
|
-
if (typeof yml === 'string') {
|
|
497
|
-
try {
|
|
498
|
-
return {
|
|
499
|
-
path: ymlPath,
|
|
500
|
-
parsed: config.parseSocketConfig(yml)
|
|
501
|
-
};
|
|
502
|
-
} catch {
|
|
503
|
-
throw new Error(`Found file but was unable to parse ${ymlPath}`);
|
|
456
|
+
// Patch adding findSpecificOverrideSet is based on
|
|
457
|
+
// https://github.com/npm/cli/pull/7025.
|
|
458
|
+
static findSpecificOverrideSet(first, second) {
|
|
459
|
+
let overrideSet = second;
|
|
460
|
+
while (overrideSet) {
|
|
461
|
+
if (overrideSet.isEqual(first)) {
|
|
462
|
+
return second;
|
|
504
463
|
}
|
|
464
|
+
overrideSet = overrideSet.parent;
|
|
505
465
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// Patch adding findSpecificOverrideSet is based on
|
|
513
|
-
// https://github.com/npm/cli/pull/7025.
|
|
514
|
-
function findSpecificOverrideSet(first, second) {
|
|
515
|
-
let overrideSet = second;
|
|
516
|
-
while (overrideSet) {
|
|
517
|
-
if (overrideSet.isEqual(first)) {
|
|
518
|
-
return second;
|
|
519
|
-
}
|
|
520
|
-
overrideSet = overrideSet.parent;
|
|
521
|
-
}
|
|
522
|
-
overrideSet = first;
|
|
523
|
-
while (overrideSet) {
|
|
524
|
-
if (overrideSet.isEqual(second)) {
|
|
525
|
-
return first;
|
|
466
|
+
overrideSet = first;
|
|
467
|
+
while (overrideSet) {
|
|
468
|
+
if (overrideSet.isEqual(second)) {
|
|
469
|
+
return first;
|
|
470
|
+
}
|
|
471
|
+
overrideSet = overrideSet.parent;
|
|
526
472
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
return undefined;
|
|
532
|
-
}
|
|
533
|
-
function isAlertFixable(alert) {
|
|
534
|
-
const {
|
|
535
|
-
type
|
|
536
|
-
} = alert;
|
|
537
|
-
if (type === 'cve' || type === 'mediumCVE' || type === 'mildCVE' || type === 'criticalCVE') {
|
|
538
|
-
return !!alert.props?.['firstPatchedVersionIdentifier'];
|
|
539
|
-
}
|
|
540
|
-
return type === 'socketUpgradeAvailable';
|
|
541
|
-
}
|
|
542
|
-
function maybeReadfileSync(filepath) {
|
|
543
|
-
try {
|
|
544
|
-
return fs.readFileSync(filepath, 'utf8');
|
|
545
|
-
} catch {}
|
|
546
|
-
return undefined;
|
|
547
|
-
}
|
|
548
|
-
async function getPackagesAlerts(safeArb, _registry, pkgs, output) {
|
|
549
|
-
const spinner = yoctoSpinner({
|
|
550
|
-
stream: output
|
|
551
|
-
});
|
|
552
|
-
let {
|
|
553
|
-
length: remaining
|
|
554
|
-
} = pkgs;
|
|
555
|
-
const packageAlerts = [];
|
|
556
|
-
if (!remaining) {
|
|
557
|
-
spinner.success('No changes detected');
|
|
558
|
-
return packageAlerts;
|
|
473
|
+
// The override sets are incomparable. Neither one contains the other.
|
|
474
|
+
const log = getLogger();
|
|
475
|
+
log?.silly('Conflicting override sets', first, second);
|
|
476
|
+
return undefined;
|
|
559
477
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
478
|
+
|
|
479
|
+
// Patch adding childrenAreEqual is based on
|
|
480
|
+
// https://github.com/npm/cli/pull/7025.
|
|
481
|
+
childrenAreEqual(otherOverrideSet) {
|
|
482
|
+
const queue = [[this, otherOverrideSet]];
|
|
483
|
+
let pos = 0;
|
|
484
|
+
let {
|
|
485
|
+
length: queueLength
|
|
486
|
+
} = queue;
|
|
487
|
+
while (pos < queueLength) {
|
|
488
|
+
if (pos === LOOP_SENTINEL$1) {
|
|
489
|
+
throw new Error('Detected infinite loop while comparing override sets');
|
|
566
490
|
}
|
|
567
491
|
const {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
type: alert.type
|
|
584
|
-
}
|
|
585
|
-
});
|
|
586
|
-
if (ux.block) {
|
|
587
|
-
blocked = true;
|
|
588
|
-
}
|
|
589
|
-
if (ux.display) {
|
|
590
|
-
displayWarning = true;
|
|
492
|
+
0: currSet,
|
|
493
|
+
1: currOtherSet
|
|
494
|
+
} = queue[pos++];
|
|
495
|
+
const {
|
|
496
|
+
children
|
|
497
|
+
} = currSet;
|
|
498
|
+
const {
|
|
499
|
+
children: otherChildren
|
|
500
|
+
} = currOtherSet;
|
|
501
|
+
if (children.size !== otherChildren.size) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
for (const key of children.keys()) {
|
|
505
|
+
if (!otherChildren.has(key)) {
|
|
506
|
+
return false;
|
|
591
507
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
type: alert.type,
|
|
597
|
-
block: ux.block,
|
|
598
|
-
raw: alert,
|
|
599
|
-
fixable: isAlertFixable(alert)
|
|
600
|
-
});
|
|
601
|
-
// Before we ask about problematic issues, check to see if they
|
|
602
|
-
// already existed in the old version if they did, be quiet.
|
|
603
|
-
const existing = pkgs.find(p => p.existing?.startsWith(`${name}@`))?.existing;
|
|
604
|
-
if (existing) {
|
|
605
|
-
const oldArtifact =
|
|
606
|
-
// eslint-disable-next-line no-await-in-loop
|
|
607
|
-
(await batchScan([existing]).next()).value;
|
|
608
|
-
if (oldArtifact?.alerts?.length) {
|
|
609
|
-
alerts = alerts.filter(({
|
|
610
|
-
type
|
|
611
|
-
}) => !oldArtifact.alerts?.find(a => a.type === type));
|
|
612
|
-
}
|
|
613
|
-
}
|
|
508
|
+
const child = children.get(key);
|
|
509
|
+
const otherChild = otherChildren.get(key);
|
|
510
|
+
if (child.value !== otherChild.value) {
|
|
511
|
+
return false;
|
|
614
512
|
}
|
|
513
|
+
queue[queueLength++] = [child, otherChild];
|
|
615
514
|
}
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
...safeArb[kCtorArgs][0]
|
|
624
|
-
});
|
|
625
|
-
}
|
|
515
|
+
}
|
|
516
|
+
return true;
|
|
517
|
+
}
|
|
518
|
+
getEdgeRule(edge) {
|
|
519
|
+
for (const rule of this.ruleset.values()) {
|
|
520
|
+
if (rule.name !== edge.name) {
|
|
521
|
+
continue;
|
|
626
522
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
523
|
+
// If keySpec is * we found our override.
|
|
524
|
+
if (rule.keySpec === '*') {
|
|
525
|
+
return rule;
|
|
526
|
+
}
|
|
527
|
+
// Patch replacing
|
|
528
|
+
// let spec = npa(`${edge.name}@${edge.spec}`)
|
|
529
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
530
|
+
//
|
|
531
|
+
// We need to use the rawSpec here, because the spec has the overrides
|
|
532
|
+
// applied to it already.
|
|
533
|
+
let spec = npa(`${edge.name}@${edge.rawSpec}`);
|
|
534
|
+
if (spec.type === 'alias') {
|
|
535
|
+
spec = spec.subSpec;
|
|
536
|
+
}
|
|
537
|
+
if (spec.type === 'git') {
|
|
538
|
+
if (spec.gitRange && rule.keySpec && semver.intersects(spec.gitRange, rule.keySpec)) {
|
|
539
|
+
return rule;
|
|
641
540
|
}
|
|
642
|
-
|
|
643
|
-
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (spec.type === 'range' || spec.type === 'version') {
|
|
544
|
+
if (rule.keySpec && semver.intersects(spec.fetchSpec, rule.keySpec)) {
|
|
545
|
+
return rule;
|
|
644
546
|
}
|
|
645
|
-
|
|
547
|
+
continue;
|
|
646
548
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
549
|
+
// If we got this far, the spec type is one of tag, directory or file
|
|
550
|
+
// which means we have no real way to make version comparisons, so we
|
|
551
|
+
// just accept the override.
|
|
552
|
+
return rule;
|
|
650
553
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
554
|
+
return this;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Patch adding isEqual is based on
|
|
558
|
+
// https://github.com/npm/cli/pull/7025.
|
|
559
|
+
isEqual(otherOverrideSet) {
|
|
560
|
+
if (this === otherOverrideSet) {
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
if (!otherOverrideSet) {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
if (this.key !== otherOverrideSet.key || this.value !== otherOverrideSet.value) {
|
|
567
|
+
return false;
|
|
568
|
+
}
|
|
569
|
+
if (!this.childrenAreEqual(otherOverrideSet)) {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
if (!this.parent) {
|
|
573
|
+
return !otherOverrideSet.parent;
|
|
574
|
+
}
|
|
575
|
+
return this.parent.isEqual(otherOverrideSet.parent);
|
|
655
576
|
}
|
|
656
|
-
return packageAlerts;
|
|
657
|
-
}
|
|
658
|
-
function toRepoUrl(resolved) {
|
|
659
|
-
return resolved.replace(/#[\s\S]*$/, '').replace(/\?[\s\S]*$/, '').replace(/\/[^/]*\/-\/[\s\S]*$/, '');
|
|
660
577
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
578
|
+
|
|
579
|
+
const Node = require(arboristNodeClassPath);
|
|
580
|
+
|
|
581
|
+
// Implementation code not related to patch https://github.com/npm/cli/pull/7025
|
|
582
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/node.js:
|
|
583
|
+
class SafeNode extends Node {
|
|
584
|
+
// Return true if it's safe to remove this node, because anything that is
|
|
585
|
+
// depending on it would be fine with the thing that they would resolve to if
|
|
586
|
+
// it was removed, or nothing is depending on it in the first place.
|
|
587
|
+
canDedupe(preferDedupe = false) {
|
|
588
|
+
// Not allowed to mess with shrinkwraps or bundles.
|
|
589
|
+
if (this.inDepBundle || this.inShrinkwrap) {
|
|
590
|
+
return false;
|
|
670
591
|
}
|
|
671
|
-
|
|
672
|
-
if (!
|
|
673
|
-
|
|
592
|
+
// It's a top level pkg, or a dep of one.
|
|
593
|
+
if (!this.resolveParent?.resolveParent) {
|
|
594
|
+
return false;
|
|
674
595
|
}
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
596
|
+
// No one wants it, remove it.
|
|
597
|
+
if (this.edgesIn.size === 0) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
const other = this.resolveParent.resolveParent.resolve(this.name);
|
|
601
|
+
// Nothing else, need this one.
|
|
602
|
+
if (!other) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
// If it's the same thing, then always fine to remove.
|
|
606
|
+
if (other.matches(this)) {
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
// If the other thing can't replace this, then skip it.
|
|
610
|
+
if (!other.canReplace(this)) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
// Patch replacing
|
|
614
|
+
// if (preferDedupe || semver.gte(other.version, this.version)) {
|
|
615
|
+
// return true
|
|
616
|
+
// }
|
|
617
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
618
|
+
//
|
|
619
|
+
// If we prefer dedupe, or if the version is equal, take the other.
|
|
620
|
+
if (preferDedupe || semver.eq(other.version, this.version)) {
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
// If our current version isn't the result of an override, then prefer to
|
|
624
|
+
// take the greater version.
|
|
625
|
+
if (!this.overridden && semver.gt(other.version, this.version)) {
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Is it safe to replace one node with another? check the edges to
|
|
632
|
+
// make sure no one will get upset. Note that the node might end up
|
|
633
|
+
// having its own unmet dependencies, if the new node has new deps.
|
|
634
|
+
// Note that there are cases where Arborist will opt to insert a node
|
|
635
|
+
// into the tree even though this function returns false! This is
|
|
636
|
+
// necessary when a root dependency is added or updated, or when a
|
|
637
|
+
// root dependency brings peer deps along with it. In that case, we
|
|
638
|
+
// will go ahead and create the invalid state, and then try to resolve
|
|
639
|
+
// it with more tree construction, because it's a user request.
|
|
640
|
+
canReplaceWith(node, ignorePeers) {
|
|
641
|
+
if (this.name !== node.name || this.packageName !== node.packageName) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
// Patch replacing
|
|
645
|
+
// if (node.overrides !== this.overrides) {
|
|
646
|
+
// return false
|
|
647
|
+
// }
|
|
648
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
649
|
+
//
|
|
650
|
+
// If this node has no dependencies, then it's irrelevant to check the
|
|
651
|
+
// override rules of the replacement node.
|
|
652
|
+
if (this.edgesOut.size) {
|
|
653
|
+
// XXX need to check for two root nodes?
|
|
654
|
+
if (node.overrides) {
|
|
655
|
+
if (!node.overrides.isEqual(this.overrides)) {
|
|
656
|
+
return false;
|
|
691
657
|
}
|
|
692
658
|
} else {
|
|
693
|
-
|
|
659
|
+
if (this.overrides) {
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
694
662
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
663
|
+
}
|
|
664
|
+
// To satisfy the patch we ensure `node.overrides === this.overrides`
|
|
665
|
+
// so that the condition we want to replace,
|
|
666
|
+
// if (this.overrides !== node.overrides) {
|
|
667
|
+
// , is not hit.`
|
|
668
|
+
const oldOverrideSet = this.overrides;
|
|
669
|
+
let result = true;
|
|
670
|
+
if (oldOverrideSet !== node.overrides) {
|
|
671
|
+
this.overrides = node.overrides;
|
|
672
|
+
}
|
|
673
|
+
try {
|
|
674
|
+
result = super.canReplaceWith(node, ignorePeers);
|
|
675
|
+
this.overrides = oldOverrideSet;
|
|
676
|
+
} catch (e) {
|
|
677
|
+
this.overrides = oldOverrideSet;
|
|
678
|
+
throw e;
|
|
679
|
+
}
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// Patch adding deleteEdgeIn is based on https://github.com/npm/cli/pull/7025.
|
|
684
|
+
deleteEdgeIn(edge) {
|
|
685
|
+
this.edgesIn.delete(edge);
|
|
686
|
+
const {
|
|
687
|
+
overrides
|
|
688
|
+
} = edge;
|
|
689
|
+
if (overrides) {
|
|
690
|
+
this.updateOverridesEdgeInRemoved(overrides);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
addEdgeIn(edge) {
|
|
694
|
+
// Patch replacing
|
|
695
|
+
// if (edge.overrides) {
|
|
696
|
+
// this.overrides = edge.overrides
|
|
697
|
+
// }
|
|
698
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
699
|
+
//
|
|
700
|
+
// We need to handle the case where the new edge in has an overrides field
|
|
701
|
+
// which is different from the current value.
|
|
702
|
+
if (!this.overrides || !this.overrides.isEqual(edge.overrides)) {
|
|
703
|
+
this.updateOverridesEdgeInAdded(edge.overrides);
|
|
704
|
+
}
|
|
705
|
+
this.edgesIn.add(edge);
|
|
706
|
+
// Try to get metadata from the yarn.lock file.
|
|
707
|
+
this.root.meta?.addEdge(edge);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
711
|
+
get overridden() {
|
|
712
|
+
// Patch replacing
|
|
713
|
+
// return !!(this.overrides && this.overrides.value && this.overrides.name === this.name)
|
|
714
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
715
|
+
if (!this.overrides || !this.overrides.value || this.overrides.name !== this.name) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
// The overrides rule is for a package with this name, but some override rules
|
|
719
|
+
// only apply to specific versions. To make sure this package was actually
|
|
720
|
+
// overridden, we check whether any edge going in had the rule applied to it,
|
|
721
|
+
// in which case its overrides set is different than its source node.
|
|
722
|
+
for (const edge of this.edgesIn) {
|
|
723
|
+
if (edge.overrides && edge.overrides.name === this.name && edge.overrides.value === this.version) {
|
|
724
|
+
if (!edge.overrides?.isEqual(edge.from?.overrides)) {
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
701
727
|
}
|
|
702
728
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Patch adding recalculateOutEdgesOverrides is based on
|
|
733
|
+
// https://github.com/npm/cli/pull/7025.
|
|
734
|
+
recalculateOutEdgesOverrides() {
|
|
735
|
+
// For each edge out propagate the new overrides through.
|
|
736
|
+
for (const edge of this.edgesOut.values()) {
|
|
737
|
+
edge.reload(true);
|
|
738
|
+
if (edge.to) {
|
|
739
|
+
edge.to.updateOverridesEdgeInAdded(edge.overrides);
|
|
706
740
|
}
|
|
707
741
|
}
|
|
708
742
|
}
|
|
709
|
-
|
|
743
|
+
|
|
744
|
+
// @ts-ignore: Incorrectly typed to accept null.
|
|
745
|
+
set root(newRoot) {
|
|
746
|
+
// Patch removing
|
|
747
|
+
// if (!this.overrides && this.parent && this.parent.overrides) {
|
|
748
|
+
// this.overrides = this.parent.overrides.getNodeRule(this)
|
|
749
|
+
// }
|
|
750
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
751
|
+
//
|
|
752
|
+
// The "root" setter is a really large and complex function. To satisfy the
|
|
753
|
+
// patch we add a dummy value to `this.overrides` so that the condition we
|
|
754
|
+
// want to remove,
|
|
755
|
+
// if (!this.overrides && this.parent && this.parent.overrides) {
|
|
756
|
+
// , is not hit.
|
|
757
|
+
if (!this.overrides) {
|
|
758
|
+
this.overrides = new SafeOverrideSet({
|
|
759
|
+
overrides: ''
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
try {
|
|
763
|
+
super.root = newRoot;
|
|
764
|
+
this.overrides = undefined;
|
|
765
|
+
} catch (e) {
|
|
766
|
+
this.overrides = undefined;
|
|
767
|
+
throw e;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Patch adding updateOverridesEdgeInAdded is based on
|
|
772
|
+
// https://github.com/npm/cli/pull/7025.
|
|
773
|
+
//
|
|
774
|
+
// This logic isn't perfect either. When we have two edges in that have
|
|
775
|
+
// different override sets, then we have to decide which set is correct. This
|
|
776
|
+
// function assumes the more specific override set is applicable, so if we have
|
|
777
|
+
// dependencies A->B->C and A->C and an override set that specifies what happens
|
|
778
|
+
// for C under A->B, this will work even if the new A->C edge comes along and
|
|
779
|
+
// tries to change the override set. The strictly correct logic is not to allow
|
|
780
|
+
// two edges with different overrides to point to the same node, because even
|
|
781
|
+
// if this node can satisfy both, one of its dependencies might need to be
|
|
782
|
+
// different depending on the edge leading to it. However, this might cause a
|
|
783
|
+
// lot of duplication, because the conflict in the dependencies might never
|
|
784
|
+
// actually happen.
|
|
785
|
+
updateOverridesEdgeInAdded(otherOverrideSet) {
|
|
786
|
+
if (!otherOverrideSet) {
|
|
787
|
+
// Assuming there are any overrides at all, the overrides field is never
|
|
788
|
+
// undefined for any node at the end state of the tree. So if the new edge's
|
|
789
|
+
// overrides is undefined it will be updated later. So we can wait with
|
|
790
|
+
// updating the node's overrides field.
|
|
791
|
+
return false;
|
|
792
|
+
}
|
|
793
|
+
if (!this.overrides) {
|
|
794
|
+
this.overrides = otherOverrideSet;
|
|
795
|
+
this.recalculateOutEdgesOverrides();
|
|
796
|
+
return true;
|
|
797
|
+
}
|
|
798
|
+
if (this.overrides.isEqual(otherOverrideSet)) {
|
|
799
|
+
return false;
|
|
800
|
+
}
|
|
801
|
+
const newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(this.overrides, otherOverrideSet);
|
|
802
|
+
if (newOverrideSet) {
|
|
803
|
+
if (this.overrides.isEqual(newOverrideSet)) {
|
|
804
|
+
return false;
|
|
805
|
+
}
|
|
806
|
+
this.overrides = newOverrideSet;
|
|
807
|
+
this.recalculateOutEdgesOverrides();
|
|
808
|
+
return true;
|
|
809
|
+
}
|
|
810
|
+
// This is an error condition. We can only get here if the new override set
|
|
811
|
+
// is in conflict with the existing.
|
|
812
|
+
const log = getLogger();
|
|
813
|
+
log?.silly('Conflicting override sets', this.name);
|
|
814
|
+
return false;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Patch adding updateOverridesEdgeInRemoved is based on
|
|
818
|
+
// https://github.com/npm/cli/pull/7025.
|
|
819
|
+
updateOverridesEdgeInRemoved(otherOverrideSet) {
|
|
820
|
+
// If this edge's overrides isn't equal to this node's overrides,
|
|
821
|
+
// then removing it won't change newOverrideSet later.
|
|
822
|
+
if (!this.overrides || !this.overrides.isEqual(otherOverrideSet)) {
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
let newOverrideSet;
|
|
826
|
+
for (const edge of this.edgesIn) {
|
|
827
|
+
const {
|
|
828
|
+
overrides: edgeOverrides
|
|
829
|
+
} = edge;
|
|
830
|
+
if (newOverrideSet && edgeOverrides) {
|
|
831
|
+
newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(edgeOverrides, newOverrideSet);
|
|
832
|
+
} else {
|
|
833
|
+
newOverrideSet = edgeOverrides;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
if (this.overrides.isEqual(newOverrideSet)) {
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
this.overrides = newOverrideSet;
|
|
840
|
+
if (newOverrideSet) {
|
|
841
|
+
// Optimization: If there's any override set at all, then no non-extraneous
|
|
842
|
+
// node has an empty override set. So if we temporarily have no override set
|
|
843
|
+
// (for example, we removed all the edges in), there's no use updating all
|
|
844
|
+
// the edges out right now. Let's just wait until we have an actual override
|
|
845
|
+
// set later.
|
|
846
|
+
this.recalculateOutEdgesOverrides();
|
|
847
|
+
}
|
|
848
|
+
return true;
|
|
849
|
+
}
|
|
710
850
|
}
|
|
711
851
|
|
|
852
|
+
const Edge = require(arboristEdgeClassPath);
|
|
853
|
+
|
|
712
854
|
// The Edge class makes heavy use of private properties which subclasses do NOT
|
|
713
855
|
// have access to. So we have to recreate any functionality that relies on those
|
|
714
856
|
// private properties and use our own "safe" prefixed non-conflicting private
|
|
715
857
|
// properties. Implementation code not related to patch https://github.com/npm/cli/pull/7025
|
|
716
|
-
// is based on https://github.com/npm/cli/blob/
|
|
858
|
+
// is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/edge.js.
|
|
717
859
|
//
|
|
718
860
|
// The npm application
|
|
719
861
|
// Copyright (c) npm, Inc. and Contributors
|
|
@@ -721,6 +863,7 @@ function walk(diff_, needInfoOn = []) {
|
|
|
721
863
|
//
|
|
722
864
|
// An edge in the dependency graph.
|
|
723
865
|
// Represents a dependency relationship of some kind.
|
|
866
|
+
const initializedSafeEdges = new WeakSet();
|
|
724
867
|
class SafeEdge extends Edge {
|
|
725
868
|
#safeAccept;
|
|
726
869
|
#safeError;
|
|
@@ -739,11 +882,15 @@ class SafeEdge extends Edge {
|
|
|
739
882
|
if (accept !== undefined) {
|
|
740
883
|
this.#safeAccept = accept || '*';
|
|
741
884
|
}
|
|
885
|
+
if (from.constructor !== SafeNode) {
|
|
886
|
+
Reflect.setPrototypeOf(from, SafeNode.prototype);
|
|
887
|
+
}
|
|
742
888
|
this.#safeError = null;
|
|
743
889
|
this.#safeExplanation = null;
|
|
744
890
|
this.#safeFrom = from;
|
|
745
891
|
this.#safeName = name;
|
|
746
892
|
this.#safeTo = null;
|
|
893
|
+
initializedSafeEdges.add(this);
|
|
747
894
|
this.reload(true);
|
|
748
895
|
}
|
|
749
896
|
get accept() {
|
|
@@ -767,7 +914,7 @@ class SafeEdge extends Edge {
|
|
|
767
914
|
}
|
|
768
915
|
// Patch adding "else if" condition is based on
|
|
769
916
|
// https://github.com/npm/cli/pull/7025.
|
|
770
|
-
else if (this.overrides && this.#safeTo.edgesOut.size && doOverrideSetsConflict(this.overrides, this.#safeTo.overrides)) {
|
|
917
|
+
else if (this.overrides && this.#safeTo.edgesOut.size && SafeOverrideSet.doOverrideSetsConflict(this.overrides, this.#safeTo.overrides)) {
|
|
771
918
|
// Any inconsistency between the edge's override set and the target's
|
|
772
919
|
// override set is potentially problematic. But we only say the edge is
|
|
773
920
|
// in error if the override sets are plainly conflicting. Note that if
|
|
@@ -819,528 +966,509 @@ class SafeEdge extends Edge {
|
|
|
819
966
|
return pkg.peerDependencies[ref];
|
|
820
967
|
}
|
|
821
968
|
throw new Error(`Unable to resolve reference ${this.overrides.value}`);
|
|
822
|
-
}
|
|
823
|
-
return this.overrides.value;
|
|
824
|
-
}
|
|
825
|
-
return this.rawSpec;
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
829
|
-
get to() {
|
|
830
|
-
return this.#safeTo;
|
|
831
|
-
}
|
|
832
|
-
detach() {
|
|
833
|
-
this.#safeExplanation = null;
|
|
834
|
-
// Patch replacing
|
|
835
|
-
// if (this.#safeTo) {
|
|
836
|
-
// this.#safeTo.edgesIn.delete(this)
|
|
837
|
-
// }
|
|
838
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
839
|
-
this.#safeTo?.deleteEdgeIn(this);
|
|
840
|
-
this.#safeFrom?.edgesOut.delete(this.name);
|
|
841
|
-
this.#safeTo = null;
|
|
842
|
-
this.#safeError = 'DETACHED';
|
|
843
|
-
this.#safeFrom = null;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
// Return the edge data, and an explanation of how that edge came to be here.
|
|
847
|
-
// @ts-ignore: Edge#explain is defined with an unused `seen = []` param.
|
|
848
|
-
explain() {
|
|
849
|
-
if (!this.#safeExplanation) {
|
|
850
|
-
const explanation = {
|
|
851
|
-
type: this.type,
|
|
852
|
-
name: this.name,
|
|
853
|
-
spec: this.spec,
|
|
854
|
-
bundled: false,
|
|
855
|
-
overridden: false,
|
|
856
|
-
error: undefined,
|
|
857
|
-
from: undefined,
|
|
858
|
-
rawSpec: undefined
|
|
859
|
-
};
|
|
860
|
-
if (this.rawSpec !== this.spec) {
|
|
861
|
-
explanation.rawSpec = this.rawSpec;
|
|
862
|
-
explanation.overridden = true;
|
|
863
|
-
}
|
|
864
|
-
if (this.bundled) {
|
|
865
|
-
explanation.bundled = this.bundled;
|
|
866
|
-
}
|
|
867
|
-
if (this.error) {
|
|
868
|
-
explanation.error = this.error;
|
|
869
|
-
}
|
|
870
|
-
if (this.#safeFrom) {
|
|
871
|
-
explanation.from = this.#safeFrom.explain();
|
|
872
|
-
}
|
|
873
|
-
this.#safeExplanation = explanation;
|
|
874
|
-
}
|
|
875
|
-
return this.#safeExplanation;
|
|
876
|
-
}
|
|
877
|
-
reload(hard = false) {
|
|
878
|
-
this.#safeExplanation = null;
|
|
879
|
-
|
|
880
|
-
// Patch adding newOverrideSet and oldOverrideSet is based on
|
|
881
|
-
// https://github.com/npm/cli/pull/7025.
|
|
882
|
-
let newOverrideSet;
|
|
883
|
-
let oldOverrideSet;
|
|
884
|
-
if (this.#safeFrom?.overrides) {
|
|
885
|
-
// Patch replacing
|
|
886
|
-
// this.overrides = this.#safeFrom.overrides.getEdgeRule(this)
|
|
887
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
888
|
-
const newOverrideSet = this.#safeFrom.overrides.getEdgeRule(this);
|
|
889
|
-
if (newOverrideSet && !newOverrideSet.isEqual(this.overrides)) {
|
|
890
|
-
// If there's a new different override set we need to propagate it to
|
|
891
|
-
// the nodes. If we're deleting the override set then there's no point
|
|
892
|
-
// propagating it right now since it will be filled with another value
|
|
893
|
-
// later.
|
|
894
|
-
oldOverrideSet = this.overrides;
|
|
895
|
-
this.overrides = newOverrideSet;
|
|
896
|
-
}
|
|
897
|
-
} else {
|
|
898
|
-
this.overrides = undefined;
|
|
899
|
-
}
|
|
900
|
-
const newTo = this.#safeFrom?.resolve(this.name);
|
|
901
|
-
if (newTo !== this.#safeTo) {
|
|
902
|
-
if (this.#safeTo) {
|
|
903
|
-
// Patch replacing
|
|
904
|
-
// this.#safeTo.edgesIn.delete(this)
|
|
905
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
906
|
-
this.#safeTo.deleteEdgeIn(this);
|
|
907
|
-
}
|
|
908
|
-
this.#safeTo = newTo ?? null;
|
|
909
|
-
this.#safeError = null;
|
|
910
|
-
if (this.#safeTo) {
|
|
911
|
-
this.#safeTo.addEdgeIn(this);
|
|
912
|
-
}
|
|
913
|
-
} else if (hard) {
|
|
914
|
-
this.#safeError = null;
|
|
915
|
-
}
|
|
916
|
-
// Patch adding "else if" condition based on
|
|
917
|
-
// https://github.com/npm/cli/pull/7025
|
|
918
|
-
else if (oldOverrideSet) {
|
|
919
|
-
// Propagate the new override set to the target node.
|
|
920
|
-
this.#safeTo.updateOverridesEdgeInRemoved(oldOverrideSet);
|
|
921
|
-
this.#safeTo.updateOverridesEdgeInAdded(newOverrideSet);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
satisfiedBy(node) {
|
|
925
|
-
// Patch replacing
|
|
926
|
-
// if (node.name !== this.#name) {
|
|
927
|
-
// return false
|
|
928
|
-
// }
|
|
929
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
930
|
-
if (node.name !== this.#safeName || !this.#safeFrom) {
|
|
931
|
-
return false;
|
|
932
|
-
}
|
|
933
|
-
// NOTE: this condition means we explicitly do not support overriding
|
|
934
|
-
// bundled or shrinkwrapped dependencies
|
|
935
|
-
if (node.hasShrinkwrap || node.inShrinkwrap || node.inBundle) {
|
|
936
|
-
return depValid(node, this.rawSpec, this.#safeAccept, this.#safeFrom);
|
|
937
|
-
}
|
|
938
|
-
// Patch replacing
|
|
939
|
-
// return depValid(node, this.spec, this.#accept, this.#from)
|
|
940
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
941
|
-
//
|
|
942
|
-
// If there's no override we just use the spec.
|
|
943
|
-
if (!this.overrides?.keySpec) {
|
|
944
|
-
return depValid(node, this.spec, this.#safeAccept, this.#safeFrom);
|
|
945
|
-
}
|
|
946
|
-
// There's some override. If the target node satisfies the overriding spec
|
|
947
|
-
// then it's okay.
|
|
948
|
-
if (depValid(node, this.spec, this.#safeAccept, this.#safeFrom)) {
|
|
949
|
-
return true;
|
|
950
|
-
}
|
|
951
|
-
// If it doesn't, then it should at least satisfy the original spec.
|
|
952
|
-
if (!depValid(node, this.rawSpec, this.#safeAccept, this.#safeFrom)) {
|
|
953
|
-
return false;
|
|
954
|
-
}
|
|
955
|
-
// It satisfies the original spec, not the overriding spec. We need to make
|
|
956
|
-
// sure it doesn't use the overridden spec.
|
|
957
|
-
// For example, we might have an ^8.0.0 rawSpec, and an override that makes
|
|
958
|
-
// keySpec=8.23.0 and the override value spec=9.0.0.
|
|
959
|
-
// If the node is 9.0.0, then it's okay because it's consistent with spec.
|
|
960
|
-
// If the node is 8.24.0, then it's okay because it's consistent with the rawSpec.
|
|
961
|
-
// If the node is 8.23.0, then it's not okay because even though it's consistent
|
|
962
|
-
// with the rawSpec, it's also consistent with the keySpec.
|
|
963
|
-
// So we're looking for ^8.0.0 or 9.0.0 and not 8.23.0.
|
|
964
|
-
return !depValid(node, this.overrides.keySpec, this.#safeAccept, this.#safeFrom);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// Implementation code not related to patch https://github.com/npm/cli/pull/7025
|
|
969
|
-
// is based on https://github.com/npm/cli/blob/v10.9.0/workspaces/arborist/lib/node.js:
|
|
970
|
-
class SafeNode extends Node {
|
|
971
|
-
// Return true if it's safe to remove this node, because anything that is
|
|
972
|
-
// depending on it would be fine with the thing that they would resolve to if
|
|
973
|
-
// it was removed, or nothing is depending on it in the first place.
|
|
974
|
-
canDedupe(preferDedupe = false) {
|
|
975
|
-
// Not allowed to mess with shrinkwraps or bundles.
|
|
976
|
-
if (this.inDepBundle || this.inShrinkwrap) {
|
|
977
|
-
return false;
|
|
978
|
-
}
|
|
979
|
-
// It's a top level pkg, or a dep of one.
|
|
980
|
-
if (!this.resolveParent?.resolveParent) {
|
|
981
|
-
return false;
|
|
982
|
-
}
|
|
983
|
-
// No one wants it, remove it.
|
|
984
|
-
if (this.edgesIn.size === 0) {
|
|
985
|
-
return true;
|
|
986
|
-
}
|
|
987
|
-
const other = this.resolveParent.resolveParent.resolve(this.name);
|
|
988
|
-
// Nothing else, need this one.
|
|
989
|
-
if (!other) {
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
// If it's the same thing, then always fine to remove.
|
|
993
|
-
if (other.matches(this)) {
|
|
994
|
-
return true;
|
|
995
|
-
}
|
|
996
|
-
// If the other thing can't replace this, then skip it.
|
|
997
|
-
if (!other.canReplace(this)) {
|
|
998
|
-
return false;
|
|
999
|
-
}
|
|
1000
|
-
// Patch replacing
|
|
1001
|
-
// if (preferDedupe || semver.gte(other.version, this.version)) {
|
|
1002
|
-
// return true
|
|
1003
|
-
// }
|
|
1004
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
1005
|
-
//
|
|
1006
|
-
// If we prefer dedupe, or if the version is equal, take the other.
|
|
1007
|
-
if (preferDedupe || semver.eq(other.version, this.version)) {
|
|
1008
|
-
return true;
|
|
1009
|
-
}
|
|
1010
|
-
// If our current version isn't the result of an override, then prefer to
|
|
1011
|
-
// take the greater version.
|
|
1012
|
-
if (!this.overridden && semver.gt(other.version, this.version)) {
|
|
1013
|
-
return true;
|
|
1014
|
-
}
|
|
1015
|
-
return false;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
// Is it safe to replace one node with another? check the edges to
|
|
1019
|
-
// make sure no one will get upset. Note that the node might end up
|
|
1020
|
-
// having its own unmet dependencies, if the new node has new deps.
|
|
1021
|
-
// Note that there are cases where Arborist will opt to insert a node
|
|
1022
|
-
// into the tree even though this function returns false! This is
|
|
1023
|
-
// necessary when a root dependency is added or updated, or when a
|
|
1024
|
-
// root dependency brings peer deps along with it. In that case, we
|
|
1025
|
-
// will go ahead and create the invalid state, and then try to resolve
|
|
1026
|
-
// it with more tree construction, because it's a user request.
|
|
1027
|
-
canReplaceWith(node, ignorePeers) {
|
|
1028
|
-
if (this.name !== node.name || this.packageName !== node.packageName) {
|
|
1029
|
-
return false;
|
|
1030
|
-
}
|
|
1031
|
-
// Patch replacing
|
|
1032
|
-
// if (node.overrides !== this.overrides) {
|
|
1033
|
-
// return false
|
|
1034
|
-
// }
|
|
1035
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
1036
|
-
//
|
|
1037
|
-
// If this node has no dependencies, then it's irrelevant to check the
|
|
1038
|
-
// override rules of the replacement node.
|
|
1039
|
-
if (this.edgesOut.size) {
|
|
1040
|
-
// XXX need to check for two root nodes?
|
|
1041
|
-
if (node.overrides) {
|
|
1042
|
-
if (!node.overrides.isEqual(this.overrides)) {
|
|
1043
|
-
return false;
|
|
1044
|
-
}
|
|
1045
|
-
} else {
|
|
1046
|
-
if (this.overrides) {
|
|
1047
|
-
return false;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
// To satisfy the patch we ensure `node.overrides === this.overrides`
|
|
1052
|
-
// so that the condition we want to replace,
|
|
1053
|
-
// if (this.overrides !== node.overrides) {
|
|
1054
|
-
// , is not hit.`
|
|
1055
|
-
const oldOverrideSet = this.overrides;
|
|
1056
|
-
let result = true;
|
|
1057
|
-
if (oldOverrideSet !== node.overrides) {
|
|
1058
|
-
this.overrides = node.overrides;
|
|
1059
|
-
}
|
|
1060
|
-
try {
|
|
1061
|
-
result = super.canReplaceWith(node, ignorePeers);
|
|
1062
|
-
this.overrides = oldOverrideSet;
|
|
1063
|
-
} catch (e) {
|
|
1064
|
-
this.overrides = oldOverrideSet;
|
|
1065
|
-
throw e;
|
|
1066
|
-
}
|
|
1067
|
-
return result;
|
|
1068
|
-
}
|
|
1069
|
-
deleteEdgeIn(edge) {
|
|
1070
|
-
this.edgesIn.delete(edge);
|
|
1071
|
-
const {
|
|
1072
|
-
overrides
|
|
1073
|
-
} = edge;
|
|
1074
|
-
if (overrides) {
|
|
1075
|
-
this.updateOverridesEdgeInRemoved(overrides);
|
|
969
|
+
}
|
|
970
|
+
return this.overrides.value;
|
|
1076
971
|
}
|
|
972
|
+
return this.rawSpec;
|
|
1077
973
|
}
|
|
1078
|
-
|
|
974
|
+
|
|
975
|
+
// @ts-ignore: Incorrectly typed as a property instead of an accessor.
|
|
976
|
+
get to() {
|
|
977
|
+
return this.#safeTo;
|
|
978
|
+
}
|
|
979
|
+
detach() {
|
|
980
|
+
this.#safeExplanation = null;
|
|
1079
981
|
// Patch replacing
|
|
1080
|
-
// if (
|
|
1081
|
-
// this.
|
|
982
|
+
// if (this.#safeTo) {
|
|
983
|
+
// this.#safeTo.edgesIn.delete(this)
|
|
1082
984
|
// }
|
|
1083
985
|
// is based on https://github.com/npm/cli/pull/7025.
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
}
|
|
1090
|
-
this.edgesIn.add(edge);
|
|
1091
|
-
// Try to get metadata from the yarn.lock file.
|
|
1092
|
-
this.root.meta?.addEdge(edge);
|
|
986
|
+
this.#safeTo?.deleteEdgeIn(this);
|
|
987
|
+
this.#safeFrom?.edgesOut.delete(this.name);
|
|
988
|
+
this.#safeTo = null;
|
|
989
|
+
this.#safeError = 'DETACHED';
|
|
990
|
+
this.#safeFrom = null;
|
|
1093
991
|
}
|
|
1094
992
|
|
|
1095
|
-
//
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
993
|
+
// Return the edge data, and an explanation of how that edge came to be here.
|
|
994
|
+
// @ts-ignore: Edge#explain is defined with an unused `seen = []` param.
|
|
995
|
+
explain() {
|
|
996
|
+
if (!this.#safeExplanation) {
|
|
997
|
+
const explanation = {
|
|
998
|
+
type: this.type,
|
|
999
|
+
name: this.name,
|
|
1000
|
+
spec: this.spec,
|
|
1001
|
+
bundled: false,
|
|
1002
|
+
overridden: false,
|
|
1003
|
+
error: undefined,
|
|
1004
|
+
from: undefined,
|
|
1005
|
+
rawSpec: undefined
|
|
1006
|
+
};
|
|
1007
|
+
if (this.rawSpec !== this.spec) {
|
|
1008
|
+
explanation.rawSpec = this.rawSpec;
|
|
1009
|
+
explanation.overridden = true;
|
|
1010
|
+
}
|
|
1011
|
+
if (this.bundled) {
|
|
1012
|
+
explanation.bundled = this.bundled;
|
|
1013
|
+
}
|
|
1014
|
+
if (this.error) {
|
|
1015
|
+
explanation.error = this.error;
|
|
1016
|
+
}
|
|
1017
|
+
if (this.#safeFrom) {
|
|
1018
|
+
explanation.from = this.#safeFrom.explain();
|
|
1112
1019
|
}
|
|
1020
|
+
this.#safeExplanation = explanation;
|
|
1113
1021
|
}
|
|
1114
|
-
return
|
|
1022
|
+
return this.#safeExplanation;
|
|
1115
1023
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1024
|
+
reload(hard = false) {
|
|
1025
|
+
if (!initializedSafeEdges.has(this)) {
|
|
1026
|
+
// Skip if called during super constructor.
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
this.#safeExplanation = null;
|
|
1030
|
+
// Patch adding newOverrideSet and oldOverrideSet is based on
|
|
1031
|
+
// https://github.com/npm/cli/pull/7025.
|
|
1032
|
+
let newOverrideSet;
|
|
1033
|
+
let oldOverrideSet;
|
|
1034
|
+
if (this.#safeFrom?.overrides) {
|
|
1035
|
+
// Patch replacing
|
|
1036
|
+
// this.overrides = this.#safeFrom.overrides.getEdgeRule(this)
|
|
1037
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
1038
|
+
const newOverrideSet = this.#safeFrom.overrides.getEdgeRule(this);
|
|
1039
|
+
if (newOverrideSet && !newOverrideSet.isEqual(this.overrides)) {
|
|
1040
|
+
// If there's a new different override set we need to propagate it to
|
|
1041
|
+
// the nodes. If we're deleting the override set then there's no point
|
|
1042
|
+
// propagating it right now since it will be filled with another value
|
|
1043
|
+
// later.
|
|
1044
|
+
oldOverrideSet = this.overrides;
|
|
1045
|
+
this.overrides = newOverrideSet;
|
|
1125
1046
|
}
|
|
1047
|
+
} else {
|
|
1048
|
+
this.overrides = undefined;
|
|
1049
|
+
}
|
|
1050
|
+
const newTo = this.#safeFrom?.resolve(this.name);
|
|
1051
|
+
if (newTo !== this.#safeTo) {
|
|
1052
|
+
// Patch replacing
|
|
1053
|
+
// if (this.#safeTo) {
|
|
1054
|
+
// this.#safeTo.edgesIn.delete(this)
|
|
1055
|
+
// }
|
|
1056
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
1057
|
+
this.#safeTo?.deleteEdgeIn(this);
|
|
1058
|
+
this.#safeTo = newTo ?? null;
|
|
1059
|
+
this.#safeError = null;
|
|
1060
|
+
this.#safeTo?.addEdgeIn(this);
|
|
1061
|
+
} else if (hard) {
|
|
1062
|
+
this.#safeError = null;
|
|
1063
|
+
}
|
|
1064
|
+
// Patch adding "else if" condition based on
|
|
1065
|
+
// https://github.com/npm/cli/pull/7025.
|
|
1066
|
+
else if (oldOverrideSet) {
|
|
1067
|
+
// Propagate the new override set to the target node.
|
|
1068
|
+
this.#safeTo.updateOverridesEdgeInRemoved(oldOverrideSet);
|
|
1069
|
+
this.#safeTo.updateOverridesEdgeInAdded(newOverrideSet);
|
|
1126
1070
|
}
|
|
1127
1071
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
//
|
|
1132
|
-
// if (!this.overrides && this.parent && this.parent.overrides) {
|
|
1133
|
-
// this.overrides = this.parent.overrides.getNodeRule(this)
|
|
1072
|
+
satisfiedBy(node) {
|
|
1073
|
+
// Patch replacing
|
|
1074
|
+
// if (node.name !== this.#name) {
|
|
1075
|
+
// return false
|
|
1134
1076
|
// }
|
|
1135
1077
|
// is based on https://github.com/npm/cli/pull/7025.
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
// patch we add a dummy value to `this.overrides` so that the condition we
|
|
1139
|
-
// want to remove,
|
|
1140
|
-
// if (!this.overrides && this.parent && this.parent.overrides) {
|
|
1141
|
-
// , is not hit.
|
|
1142
|
-
if (!this.overrides) {
|
|
1143
|
-
this.overrides = new OverrideSet({
|
|
1144
|
-
overrides: ''
|
|
1145
|
-
});
|
|
1078
|
+
if (node.name !== this.#safeName || !this.#safeFrom) {
|
|
1079
|
+
return false;
|
|
1146
1080
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
this.overrides = undefined;
|
|
1152
|
-
throw e;
|
|
1081
|
+
// NOTE: this condition means we explicitly do not support overriding
|
|
1082
|
+
// bundled or shrinkwrapped dependencies
|
|
1083
|
+
if (node.hasShrinkwrap || node.inShrinkwrap || node.inBundle) {
|
|
1084
|
+
return depValid(node, this.rawSpec, this.#safeAccept, this.#safeFrom);
|
|
1153
1085
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
// function assumes the more specific override set is applicable, so if we have
|
|
1162
|
-
// dependencies A->B->C and A->C and an override set that specifies what happens
|
|
1163
|
-
// for C under A->B, this will work even if the new A->C edge comes along and
|
|
1164
|
-
// tries to change the override set. The strictly correct logic is not to allow
|
|
1165
|
-
// two edges with different overrides to point to the same node, because even
|
|
1166
|
-
// if this node can satisfy both, one of its dependencies might need to be
|
|
1167
|
-
// different depending on the edge leading to it. However, this might cause a
|
|
1168
|
-
// lot of duplication, because the conflict in the dependencies might never
|
|
1169
|
-
// actually happen.
|
|
1170
|
-
updateOverridesEdgeInAdded(otherOverrideSet) {
|
|
1171
|
-
if (!otherOverrideSet) {
|
|
1172
|
-
// Assuming there are any overrides at all, the overrides field is never
|
|
1173
|
-
// undefined for any node at the end state of the tree. So if the new edge's
|
|
1174
|
-
// overrides is undefined it will be updated later. So we can wait with
|
|
1175
|
-
// updating the node's overrides field.
|
|
1176
|
-
return false;
|
|
1086
|
+
// Patch replacing
|
|
1087
|
+
// return depValid(node, this.spec, this.#accept, this.#from)
|
|
1088
|
+
// is based on https://github.com/npm/cli/pull/7025.
|
|
1089
|
+
//
|
|
1090
|
+
// If there's no override we just use the spec.
|
|
1091
|
+
if (!this.overrides?.keySpec) {
|
|
1092
|
+
return depValid(node, this.spec, this.#safeAccept, this.#safeFrom);
|
|
1177
1093
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1094
|
+
// There's some override. If the target node satisfies the overriding spec
|
|
1095
|
+
// then it's okay.
|
|
1096
|
+
if (depValid(node, this.spec, this.#safeAccept, this.#safeFrom)) {
|
|
1181
1097
|
return true;
|
|
1182
1098
|
}
|
|
1183
|
-
|
|
1099
|
+
// If it doesn't, then it should at least satisfy the original spec.
|
|
1100
|
+
if (!depValid(node, this.rawSpec, this.#safeAccept, this.#safeFrom)) {
|
|
1184
1101
|
return false;
|
|
1185
1102
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
// is in conflict with the existing.
|
|
1197
|
-
log.silly('Conflicting override sets', this.name);
|
|
1198
|
-
return false;
|
|
1103
|
+
// It satisfies the original spec, not the overriding spec. We need to make
|
|
1104
|
+
// sure it doesn't use the overridden spec.
|
|
1105
|
+
// For example, we might have an ^8.0.0 rawSpec, and an override that makes
|
|
1106
|
+
// keySpec=8.23.0 and the override value spec=9.0.0.
|
|
1107
|
+
// If the node is 9.0.0, then it's okay because it's consistent with spec.
|
|
1108
|
+
// If the node is 8.24.0, then it's okay because it's consistent with the rawSpec.
|
|
1109
|
+
// If the node is 8.23.0, then it's not okay because even though it's consistent
|
|
1110
|
+
// with the rawSpec, it's also consistent with the keySpec.
|
|
1111
|
+
// So we're looking for ^8.0.0 or 9.0.0 and not 8.23.0.
|
|
1112
|
+
return !depValid(node, this.overrides.keySpec, this.#safeAccept, this.#safeFrom);
|
|
1199
1113
|
}
|
|
1114
|
+
}
|
|
1200
1115
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
}
|
|
1116
|
+
const {
|
|
1117
|
+
LOOP_SENTINEL,
|
|
1118
|
+
NPM,
|
|
1119
|
+
NPM_REGISTRY_URL,
|
|
1120
|
+
SOCKET_CLI_FIX_PACKAGE_LOCK_FILE,
|
|
1121
|
+
SOCKET_CLI_UPDATE_OVERRIDES_IN_PACKAGE_LOCK_FILE,
|
|
1122
|
+
abortSignal
|
|
1123
|
+
} = constants;
|
|
1124
|
+
const formatter = new socketUrl.ColorOrMarkdown(false);
|
|
1125
|
+
function findBestPatchVersion(name, availableVersions, currentMajorVersion, vulnerableRange) {
|
|
1126
|
+
const manifestVersion = registry.getManifestData(NPM, name)?.version;
|
|
1127
|
+
// Filter versions that are within the current major version and are not in the vulnerable range
|
|
1128
|
+
const eligibleVersions = availableVersions.filter(version => {
|
|
1129
|
+
const isSameMajor = semver.major(version) === currentMajorVersion;
|
|
1130
|
+
const isNotVulnerable = !semver.satisfies(version, vulnerableRange);
|
|
1131
|
+
if (isSameMajor && isNotVulnerable) {
|
|
1132
|
+
return true;
|
|
1219
1133
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1134
|
+
return !!manifestVersion;
|
|
1135
|
+
});
|
|
1136
|
+
if (eligibleVersions.length === 0) {
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
// Use semver to find the max satisfying version.
|
|
1140
|
+
return semver.maxSatisfying(eligibleVersions, '*');
|
|
1141
|
+
}
|
|
1142
|
+
function findPackageNodes(tree, packageName) {
|
|
1143
|
+
const queue = [{
|
|
1144
|
+
node: tree
|
|
1145
|
+
}];
|
|
1146
|
+
const matches = [];
|
|
1147
|
+
let sentinel = 0;
|
|
1148
|
+
while (queue.length) {
|
|
1149
|
+
if (sentinel++ === LOOP_SENTINEL) {
|
|
1150
|
+
throw new Error('Detected infinite loop in findPackageNodes');
|
|
1222
1151
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1152
|
+
const {
|
|
1153
|
+
node: currentNode
|
|
1154
|
+
} = queue.pop();
|
|
1155
|
+
const node = currentNode.children.get(packageName);
|
|
1156
|
+
if (node) {
|
|
1157
|
+
matches.push(node);
|
|
1158
|
+
}
|
|
1159
|
+
const children = [...currentNode.children.values()];
|
|
1160
|
+
for (let i = children.length - 1; i >= 0; i -= 1) {
|
|
1161
|
+
queue.push({
|
|
1162
|
+
node: children[i]
|
|
1163
|
+
});
|
|
1231
1164
|
}
|
|
1232
|
-
return true;
|
|
1233
1165
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1166
|
+
return matches;
|
|
1167
|
+
}
|
|
1168
|
+
async function getPackagesAlerts(details, options) {
|
|
1169
|
+
let {
|
|
1170
|
+
length: remaining
|
|
1171
|
+
} = details;
|
|
1172
|
+
const packageAlerts = [];
|
|
1173
|
+
if (!remaining) {
|
|
1174
|
+
return packageAlerts;
|
|
1175
|
+
}
|
|
1176
|
+
const {
|
|
1177
|
+
includeExisting = false,
|
|
1178
|
+
includeUnfixable = true,
|
|
1179
|
+
output
|
|
1180
|
+
} = {
|
|
1181
|
+
__proto__: null,
|
|
1182
|
+
...options
|
|
1183
|
+
};
|
|
1184
|
+
const spinner$1 = output ? new spinner.Spinner({
|
|
1185
|
+
stream: output
|
|
1186
|
+
}) : undefined;
|
|
1187
|
+
const getText = spinner$1 ? () => `Looking up data for ${remaining} packages` : () => '';
|
|
1188
|
+
spinner$1?.start(getText());
|
|
1189
|
+
try {
|
|
1190
|
+
for await (const artifact of batchScan(arrays.arrayUnique(details.map(d => d.node.pkgid)))) {
|
|
1191
|
+
if (!artifact.name || !artifact.version || !artifact.alerts?.length) {
|
|
1192
|
+
continue;
|
|
1250
1193
|
}
|
|
1251
1194
|
const {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
const {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1195
|
+
version
|
|
1196
|
+
} = artifact;
|
|
1197
|
+
const name = packages.resolvePackageName(artifact);
|
|
1198
|
+
const id = `${name}@${artifact.version}`;
|
|
1199
|
+
let displayWarning = false;
|
|
1200
|
+
let alerts = [];
|
|
1201
|
+
for (const alert of artifact.alerts) {
|
|
1202
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1203
|
+
const ux = await uxLookup({
|
|
1204
|
+
package: {
|
|
1205
|
+
name,
|
|
1206
|
+
version
|
|
1207
|
+
},
|
|
1208
|
+
alert: {
|
|
1209
|
+
type: alert.type
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
if (ux.display && output) {
|
|
1213
|
+
displayWarning = true;
|
|
1267
1214
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1215
|
+
if (ux.block || ux.display) {
|
|
1216
|
+
const fixable = isArtifactAlertFixable(alert);
|
|
1217
|
+
if (includeUnfixable || fixable) {
|
|
1218
|
+
alerts.push({
|
|
1219
|
+
name,
|
|
1220
|
+
version,
|
|
1221
|
+
key: alert.key,
|
|
1222
|
+
type: alert.type,
|
|
1223
|
+
block: ux.block,
|
|
1224
|
+
raw: alert,
|
|
1225
|
+
fixable
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
// Lazily access constants.IPC.
|
|
1229
|
+
if (includeExisting && !constants.IPC[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE]) {
|
|
1230
|
+
// Before we ask about problematic issues, check to see if they
|
|
1231
|
+
// already existed in the old version if they did, be quiet.
|
|
1232
|
+
const existing = details.find(d => d.existing?.pkgid.startsWith(`${name}@`))?.existing;
|
|
1233
|
+
if (existing) {
|
|
1234
|
+
const oldArtifact =
|
|
1235
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1236
|
+
(await batchScan([existing.pkgid]).next()).value;
|
|
1237
|
+
if (oldArtifact?.alerts?.length) {
|
|
1238
|
+
alerts = alerts.filter(({
|
|
1239
|
+
type
|
|
1240
|
+
}) => !oldArtifact.alerts.find(a => a.type === type));
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1272
1244
|
}
|
|
1273
|
-
queue[queueLength++] = [child, otherChild];
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
return true;
|
|
1277
|
-
}
|
|
1278
|
-
getEdgeRule(edge) {
|
|
1279
|
-
for (const rule of this.ruleset.values()) {
|
|
1280
|
-
if (rule.name !== edge.name) {
|
|
1281
|
-
continue;
|
|
1282
|
-
}
|
|
1283
|
-
// If keySpec is * we found our override.
|
|
1284
|
-
if (rule.keySpec === '*') {
|
|
1285
|
-
return rule;
|
|
1286
1245
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
// is based on https://github.com/npm/cli/pull/7025.
|
|
1290
|
-
//
|
|
1291
|
-
// We need to use the rawSpec here, because the spec has the overrides
|
|
1292
|
-
// applied to it already.
|
|
1293
|
-
let spec = npa(`${edge.name}@${edge.rawSpec}`);
|
|
1294
|
-
if (spec.type === 'alias') {
|
|
1295
|
-
spec = spec.subSpec;
|
|
1246
|
+
if (displayWarning && spinner$1) {
|
|
1247
|
+
spinner$1.stop(`(socket) ${formatter.hyperlink(id, socketUrl.getSocketDevPackageOverviewUrl(NPM, name, version))} contains risks:`);
|
|
1296
1248
|
}
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1249
|
+
alerts.sort((a, b) => a.type < b.type ? -1 : 1);
|
|
1250
|
+
if (output) {
|
|
1251
|
+
const lines = new Set();
|
|
1252
|
+
const translations = getTranslations();
|
|
1253
|
+
for (const alert of alerts) {
|
|
1254
|
+
const attributes = [...(alert.fixable ? ['fixable'] : []), ...(alert.block ? [] : ['non-blocking'])];
|
|
1255
|
+
const maybeAttributes = attributes.length ? ` (${attributes.join('; ')})` : '';
|
|
1256
|
+
// Based data from { pageProps: { alertTypes } } of:
|
|
1257
|
+
// https://socket.dev/_next/data/94666139314b6437ee4491a0864e72b264547585/en-US.json
|
|
1258
|
+
const info = translations.alerts[alert.type];
|
|
1259
|
+
const title = info?.title ?? alert.type;
|
|
1260
|
+
const maybeDesc = info?.description ? ` - ${info.description}` : '';
|
|
1261
|
+
// TODO: emoji seems to mis-align terminals sometimes
|
|
1262
|
+
lines.add(` ${title}${maybeAttributes}${maybeDesc}\n`);
|
|
1300
1263
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
if (spec.type === 'range' || spec.type === 'version') {
|
|
1304
|
-
if (rule.keySpec && semver.intersects(spec.fetchSpec, rule.keySpec)) {
|
|
1305
|
-
return rule;
|
|
1264
|
+
for (const line of lines) {
|
|
1265
|
+
output?.write(line);
|
|
1306
1266
|
}
|
|
1307
|
-
continue;
|
|
1308
1267
|
}
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1268
|
+
spinner$1?.start();
|
|
1269
|
+
remaining -= 1;
|
|
1270
|
+
if (spinner$1) {
|
|
1271
|
+
spinner$1.text = remaining > 0 ? getText() : '';
|
|
1272
|
+
}
|
|
1273
|
+
packageAlerts.push(...alerts);
|
|
1313
1274
|
}
|
|
1314
|
-
|
|
1275
|
+
} catch (e) {
|
|
1276
|
+
pathResolve.debugLog(e);
|
|
1277
|
+
} finally {
|
|
1278
|
+
spinner$1?.stop();
|
|
1315
1279
|
}
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1280
|
+
return packageAlerts;
|
|
1281
|
+
}
|
|
1282
|
+
let _translations;
|
|
1283
|
+
function getTranslations() {
|
|
1284
|
+
if (_translations === undefined) {
|
|
1285
|
+
_translations = require(
|
|
1286
|
+
// Lazily access constants.rootPath.
|
|
1287
|
+
path.join(constants.rootPath, 'translations.json'));
|
|
1288
|
+
}
|
|
1289
|
+
return _translations;
|
|
1290
|
+
}
|
|
1291
|
+
async function updateAdvisoryDependencies(arb, alerts) {
|
|
1292
|
+
let alertsByPkg;
|
|
1293
|
+
for (const alert of alerts) {
|
|
1294
|
+
if (!isArtifactAlertCveFixable(alert.raw)) {
|
|
1295
|
+
continue;
|
|
1325
1296
|
}
|
|
1326
|
-
if (
|
|
1327
|
-
|
|
1297
|
+
if (!alertsByPkg) {
|
|
1298
|
+
alertsByPkg = {};
|
|
1328
1299
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1300
|
+
const {
|
|
1301
|
+
name
|
|
1302
|
+
} = alert;
|
|
1303
|
+
if (!alertsByPkg[name]) {
|
|
1304
|
+
alertsByPkg[name] = [];
|
|
1305
|
+
}
|
|
1306
|
+
const props = alert.raw?.props;
|
|
1307
|
+
alertsByPkg[name].push({
|
|
1308
|
+
id: -1,
|
|
1309
|
+
url: props?.url,
|
|
1310
|
+
title: props?.title,
|
|
1311
|
+
severity: alert.raw?.severity?.toLowerCase(),
|
|
1312
|
+
vulnerable_versions: props?.vulnerableVersionRange,
|
|
1313
|
+
cwe: props?.cwes,
|
|
1314
|
+
cvss: props?.csvs,
|
|
1315
|
+
name
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
if (!alertsByPkg) {
|
|
1319
|
+
// No advisories to process.
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
await arb.buildIdealTree();
|
|
1323
|
+
const tree = arb.idealTree;
|
|
1324
|
+
for (const name of Object.keys(alertsByPkg)) {
|
|
1325
|
+
const nodes = findPackageNodes(tree, name);
|
|
1326
|
+
if (!nodes.length) {
|
|
1327
|
+
continue;
|
|
1331
1328
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1329
|
+
// Fetch packument to get available versions.
|
|
1330
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1331
|
+
const packument = await packages.fetchPackagePackument(name);
|
|
1332
|
+
for (const node of nodes) {
|
|
1333
|
+
const {
|
|
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
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
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
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1334
1393
|
}
|
|
1335
|
-
return this.parent.isEqual(otherOverrideSet.parent);
|
|
1336
1394
|
}
|
|
1337
1395
|
}
|
|
1396
|
+
async function reify(...args) {
|
|
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) {
|
|
1401
|
+
// Nothing to check, hmmm already installed or all private?
|
|
1402
|
+
return await this[kRiskyReify](...args);
|
|
1403
|
+
}
|
|
1404
|
+
// Lazily access constants.IPC.
|
|
1405
|
+
const {
|
|
1406
|
+
[SOCKET_CLI_FIX_PACKAGE_LOCK_FILE]: bypassConfirms,
|
|
1407
|
+
[SOCKET_CLI_UPDATE_OVERRIDES_IN_PACKAGE_LOCK_FILE]: bypassAlerts
|
|
1408
|
+
} = constants.IPC;
|
|
1409
|
+
const {
|
|
1410
|
+
stderr: output,
|
|
1411
|
+
stdin: input
|
|
1412
|
+
} = process;
|
|
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);
|
|
1456
|
+
return true;
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
/* eslint-enable no-await-in-loop */
|
|
1460
|
+
return ret;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
const Arborist = require(arboristClassPath);
|
|
1464
|
+
const kCtorArgs = Symbol('ctorArgs');
|
|
1465
|
+
const kRiskyReify = Symbol('riskyReify');
|
|
1338
1466
|
|
|
1339
1467
|
// Implementation code not related to our custom behavior is based on
|
|
1340
|
-
// https://github.com/npm/cli/blob/
|
|
1468
|
+
// https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/arborist/index.js:
|
|
1341
1469
|
class SafeArborist extends Arborist {
|
|
1342
1470
|
constructor(...ctorArgs) {
|
|
1343
|
-
|
|
1471
|
+
super({
|
|
1344
1472
|
...ctorArgs[0],
|
|
1345
1473
|
audit: true,
|
|
1346
1474
|
dryRun: true,
|
|
@@ -1349,13 +1477,13 @@ class SafeArborist extends Arborist {
|
|
|
1349
1477
|
saveBundle: false,
|
|
1350
1478
|
// progress: false,
|
|
1351
1479
|
fund: false
|
|
1352
|
-
}, ctorArgs.slice(1)
|
|
1353
|
-
super(...mutedArguments);
|
|
1480
|
+
}, ...ctorArgs.slice(1));
|
|
1354
1481
|
this[kCtorArgs] = ctorArgs;
|
|
1355
1482
|
}
|
|
1356
1483
|
async [kRiskyReify](...args) {
|
|
1357
1484
|
// SafeArborist has suffered side effects and must be rebuilt from scratch.
|
|
1358
1485
|
const arb = new Arborist(...this[kCtorArgs]);
|
|
1486
|
+
arb.idealTree = this.idealTree;
|
|
1359
1487
|
const ret = await arb.reify(...args);
|
|
1360
1488
|
Object.assign(this, arb);
|
|
1361
1489
|
return ret;
|
|
@@ -1372,54 +1500,24 @@ class SafeArborist extends Arborist {
|
|
|
1372
1500
|
const old = {
|
|
1373
1501
|
...options,
|
|
1374
1502
|
dryRun: false,
|
|
1375
|
-
save: Boolean(options
|
|
1376
|
-
saveBundle: Boolean(options
|
|
1503
|
+
save: Boolean(options.save ?? true),
|
|
1504
|
+
saveBundle: Boolean(options.saveBundle ?? false)
|
|
1377
1505
|
};
|
|
1378
1506
|
args[0] = options;
|
|
1379
1507
|
options.dryRun = true;
|
|
1380
|
-
options
|
|
1381
|
-
options
|
|
1382
|
-
// TODO: Make this deal w/ any refactor to private fields by punching the
|
|
1383
|
-
// class itself.
|
|
1508
|
+
options.save = false;
|
|
1509
|
+
options.saveBundle = false;
|
|
1384
1510
|
await super.reify(...args);
|
|
1385
|
-
const diff = walk(this['diff']);
|
|
1386
1511
|
options.dryRun = old.dryRun;
|
|
1387
|
-
options
|
|
1388
|
-
options
|
|
1389
|
-
|
|
1390
|
-
if (diff.findIndex(c => c.repository_url === NPM_REGISTRY_URL) === -1) {
|
|
1391
|
-
return await this[kRiskyReify](...args);
|
|
1392
|
-
}
|
|
1393
|
-
let proceed = ENV[UPDATE_SOCKET_OVERRIDES_IN_PACKAGE_LOCK_FILE];
|
|
1394
|
-
if (!proceed) {
|
|
1395
|
-
proceed = await ttyServer.captureTTY(async (input, output) => {
|
|
1396
|
-
if (input && output) {
|
|
1397
|
-
const alerts = await getPackagesAlerts(this, this['registry'], diff, output);
|
|
1398
|
-
if (!alerts.length) {
|
|
1399
|
-
return true;
|
|
1400
|
-
}
|
|
1401
|
-
return await prompts.confirm({
|
|
1402
|
-
message: 'Accept risks of installing these packages?',
|
|
1403
|
-
default: false
|
|
1404
|
-
}, {
|
|
1405
|
-
input,
|
|
1406
|
-
output,
|
|
1407
|
-
signal: abortSignal
|
|
1408
|
-
});
|
|
1409
|
-
} else if ((await getPackagesAlerts(this, this['registry'], diff, output)).length > 0) {
|
|
1410
|
-
throw new Error('Socket npm Unable to prompt to accept risk, need TTY to do so');
|
|
1411
|
-
}
|
|
1412
|
-
return true;
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
if (proceed) {
|
|
1416
|
-
return await this[kRiskyReify](...args);
|
|
1417
|
-
} else {
|
|
1418
|
-
throw new Error('Socket npm exiting due to risks');
|
|
1419
|
-
}
|
|
1512
|
+
options.save = old.save;
|
|
1513
|
+
options.saveBundle = old.saveBundle;
|
|
1514
|
+
return await Reflect.apply(reify, this, args);
|
|
1420
1515
|
}
|
|
1421
1516
|
}
|
|
1517
|
+
|
|
1422
1518
|
function installSafeArborist() {
|
|
1519
|
+
// Override '@npmcli/arborist' module exports with patched variants based on
|
|
1520
|
+
// https://github.com/npm/cli/pull/7025.
|
|
1423
1521
|
const cache = require.cache;
|
|
1424
1522
|
cache[arboristClassPath] = {
|
|
1425
1523
|
exports: SafeArborist
|
|
@@ -1430,83 +1528,9 @@ function installSafeArborist() {
|
|
|
1430
1528
|
cache[arboristNodeClassPath] = {
|
|
1431
1529
|
exports: SafeNode
|
|
1432
1530
|
};
|
|
1433
|
-
cache[
|
|
1531
|
+
cache[arboristOverrideSetClassPath] = {
|
|
1434
1532
|
exports: SafeOverrideSet
|
|
1435
1533
|
};
|
|
1436
1534
|
}
|
|
1437
|
-
void (async () => {
|
|
1438
|
-
const remoteSettings = await (async () => {
|
|
1439
|
-
try {
|
|
1440
|
-
const socketSdk = await sdk.setupSdk(pubToken);
|
|
1441
|
-
const orgResult = await socketSdk.getOrganizations();
|
|
1442
|
-
if (!orgResult.success) {
|
|
1443
|
-
throw new Error(`Failed to fetch Socket organization info: ${orgResult.error.message}`);
|
|
1444
|
-
}
|
|
1445
|
-
const orgs = [];
|
|
1446
|
-
for (const org of Object.values(orgResult.data.organizations)) {
|
|
1447
|
-
if (org) {
|
|
1448
|
-
orgs.push(org);
|
|
1449
|
-
}
|
|
1450
|
-
}
|
|
1451
|
-
const result = await socketSdk.postSettings(orgs.map(org => ({
|
|
1452
|
-
organization: org.id
|
|
1453
|
-
})));
|
|
1454
|
-
if (!result.success) {
|
|
1455
|
-
throw new Error(`Failed to fetch API key settings: ${result.error.message}`);
|
|
1456
|
-
}
|
|
1457
|
-
return {
|
|
1458
|
-
orgs,
|
|
1459
|
-
settings: result.data
|
|
1460
|
-
};
|
|
1461
|
-
} catch (e) {
|
|
1462
|
-
if (objects.isObject(e) && 'cause' in e) {
|
|
1463
|
-
const {
|
|
1464
|
-
cause
|
|
1465
|
-
} = e;
|
|
1466
|
-
if (sdk.isErrnoException(cause)) {
|
|
1467
|
-
if (cause.code === 'ENOTFOUND' || cause.code === 'ECONNREFUSED') {
|
|
1468
|
-
throw new Error('Unable to connect to socket.dev, ensure internet connectivity before retrying', {
|
|
1469
|
-
cause: e
|
|
1470
|
-
});
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
throw e;
|
|
1475
|
-
}
|
|
1476
|
-
})();
|
|
1477
|
-
const {
|
|
1478
|
-
orgs,
|
|
1479
|
-
settings
|
|
1480
|
-
} = remoteSettings;
|
|
1481
|
-
const enforcedOrgs = sdk.getSetting('enforcedOrgs') ?? [];
|
|
1482
|
-
|
|
1483
|
-
// Remove any organizations not being enforced.
|
|
1484
|
-
for (const {
|
|
1485
|
-
0: i,
|
|
1486
|
-
1: org
|
|
1487
|
-
} of orgs.entries()) {
|
|
1488
|
-
if (!enforcedOrgs.includes(org.id)) {
|
|
1489
|
-
settings.entries.splice(i, 1);
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
const socketYml = findSocketYmlSync();
|
|
1493
|
-
if (socketYml) {
|
|
1494
|
-
settings.entries.push({
|
|
1495
|
-
start: socketYml.path,
|
|
1496
|
-
settings: {
|
|
1497
|
-
[socketYml.path]: {
|
|
1498
|
-
deferTo: null,
|
|
1499
|
-
// TODO: TypeScript complains about the type not matching. We should
|
|
1500
|
-
// figure out why are providing
|
|
1501
|
-
// issueRules: { [issueName: string]: boolean }
|
|
1502
|
-
// but expecting
|
|
1503
|
-
// issueRules: { [issueName: string]: { action: 'defer' | 'error' | 'ignore' | 'monitor' | 'warn' } }
|
|
1504
|
-
issueRules: socketYml.parsed.issueRules
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
_uxLookup = createAlertUXLookup(settings);
|
|
1510
|
-
})();
|
|
1511
1535
|
|
|
1512
1536
|
installSafeArborist();
|