@socketsecurity/cli-with-sentry 0.14.129 → 0.14.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/bin/cli.js +37 -44
  2. package/bin/npx-cli.js +1 -3
  3. package/dist/{module-sync/cli.js → cli.js} +336 -338
  4. package/dist/cli.js.map +1 -0
  5. package/dist/constants.js +8 -25
  6. package/dist/constants.js.map +1 -1
  7. package/dist/instrument-with-sentry.js +3 -14
  8. package/dist/instrument-with-sentry.js.map +1 -1
  9. package/dist/{module-sync/shadow-bin.js → shadow-bin.js} +52 -1
  10. package/dist/shadow-bin.js.map +1 -0
  11. package/dist/{module-sync/shadow-npm-inject.js → shadow-npm-inject.js} +67 -48
  12. package/dist/shadow-npm-inject.js.map +1 -0
  13. package/dist/shadow-npm-paths.js.map +1 -0
  14. package/dist/{module-sync/vendor.js → vendor.js} +10320 -4778
  15. package/dist/vendor.js.map +1 -0
  16. package/package.json +16 -26
  17. package/dist/constants.d.ts +0 -285
  18. package/dist/instrument-with-sentry.d.ts +0 -1
  19. package/dist/module-sync/arborist-helpers.d.ts +0 -69
  20. package/dist/module-sync/artifact.d.ts +0 -63
  21. package/dist/module-sync/cli.d.ts +0 -2
  22. package/dist/module-sync/cli.js.map +0 -1
  23. package/dist/module-sync/cmd.d.ts +0 -4
  24. package/dist/module-sync/config.d.ts +0 -44
  25. package/dist/module-sync/constants.js +0 -3
  26. package/dist/module-sync/edge.d.ts +0 -78
  27. package/dist/module-sync/errors.d.ts +0 -29
  28. package/dist/module-sync/fs.d.ts +0 -63
  29. package/dist/module-sync/index.d.ts +0 -34
  30. package/dist/module-sync/node.d.ts +0 -121
  31. package/dist/module-sync/override-set.d.ts +0 -43
  32. package/dist/module-sync/package-environment.d.ts +0 -83
  33. package/dist/module-sync/path-resolve.d.ts +0 -15
  34. package/dist/module-sync/sdk.d.ts +0 -9
  35. package/dist/module-sync/semver.d.ts +0 -17
  36. package/dist/module-sync/shadow-bin.d.ts +0 -5
  37. package/dist/module-sync/shadow-bin.js.map +0 -1
  38. package/dist/module-sync/shadow-npm-inject.d.ts +0 -1
  39. package/dist/module-sync/shadow-npm-inject.js.map +0 -1
  40. package/dist/module-sync/shadow-npm-paths.d.ts +0 -27
  41. package/dist/module-sync/shadow-npm-paths.js.map +0 -1
  42. package/dist/module-sync/socket-package-alert.d.ts +0 -104
  43. package/dist/module-sync/vendor.d.ts +0 -0
  44. package/dist/module-sync/vendor.js.map +0 -1
  45. package/dist/require/cli.d.ts +0 -2
  46. package/dist/require/cli.js +0 -12361
  47. package/dist/require/cli.js.map +0 -1
  48. package/dist/require/constants.js +0 -3
  49. package/dist/require/shadow-bin.d.ts +0 -5
  50. package/dist/require/shadow-bin.js +0 -110
  51. package/dist/require/shadow-bin.js.map +0 -1
  52. package/dist/require/shadow-npm-inject.d.ts +0 -1
  53. package/dist/require/shadow-npm-inject.js +0 -2616
  54. package/dist/require/shadow-npm-inject.js.map +0 -1
  55. package/dist/require/shadow-npm-paths.d.ts +0 -27
  56. package/dist/require/shadow-npm-paths.js +0 -292
  57. package/dist/require/shadow-npm-paths.js.map +0 -1
  58. package/dist/require/vendor.js +0 -3
  59. /package/dist/{module-sync/shadow-npm-paths.js → shadow-npm-paths.js} +0 -0
@@ -1,2616 +0,0 @@
1
- 'use strict'
2
-
3
- const shadowNpmPaths = require('./shadow-npm-paths.js')
4
- const process$1 = require('node:process')
5
- const vendor = require('./vendor.js')
6
- const logger = require('@socketsecurity/registry/lib/logger')
7
- const constants = require('./constants.js')
8
- const arrays = require('@socketsecurity/registry/lib/arrays')
9
- const packageurlJs = require('@socketregistry/packageurl-js')
10
- const registry = require('@socketsecurity/registry')
11
- const debug = require('@socketsecurity/registry/lib/debug')
12
- const objects = require('@socketsecurity/registry/lib/objects')
13
- const isInteractive = require('@socketregistry/is-interactive/index.cjs')
14
- const registryConstants = require('@socketsecurity/registry/lib/constants')
15
- const prompts = require('@socketsecurity/registry/lib/prompts')
16
- const strings = require('@socketsecurity/registry/lib/strings')
17
- const sdk = require('@socketsecurity/sdk')
18
- const fs = require('node:fs')
19
- const os = require('node:os')
20
- const path = require('node:path')
21
- const fs$1 = require('@socketsecurity/registry/lib/fs')
22
- const packages = require('@socketsecurity/registry/lib/packages')
23
- const promises = require('node:timers/promises')
24
- const sorts = require('@socketsecurity/registry/lib/sorts')
25
- const indentString = require('@socketregistry/indent-string/index.cjs')
26
-
27
- const { NPM: NPM$3, PNPM } = constants
28
- const PNPM_WORKSPACE = `${PNPM}-workspace`
29
- const ignoredDirs = [
30
- // Taken from ignore-by-default:
31
- // https://github.com/novemberborn/ignore-by-default/blob/v2.1.0/index.js
32
- '.git',
33
- // Git repository files, see <https://git-scm.com/>
34
- '.log',
35
- // Log files emitted by tools such as `tsserver`, see <https://github.com/Microsoft/TypeScript/wiki/Standalone-Server-%28tsserver%29>
36
- '.nyc_output',
37
- // Temporary directory where nyc stores coverage data, see <https://github.com/bcoe/nyc>
38
- '.sass-cache',
39
- // Cache folder for node-sass, see <https://github.com/sass/node-sass>
40
- '.yarn',
41
- // Where node modules are installed when using Yarn, see <https://yarnpkg.com/>
42
- 'bower_components',
43
- // Where Bower packages are installed, see <http://bower.io/>
44
- 'coverage',
45
- // Standard output directory for code coverage reports, see <https://github.com/gotwarlost/istanbul>
46
- 'node_modules',
47
- // Where Node modules are installed, see <https://nodejs.org/>
48
- // Taken from globby:
49
- // https://github.com/sindresorhus/globby/blob/v14.0.2/ignore.js#L11-L16
50
- 'flow-typed'
51
- ]
52
- const ignoredDirPatterns = ignoredDirs.map(i => `**/${i}`)
53
- async function getWorkspaceGlobs(agent, cwd = process$1.cwd()) {
54
- let workspacePatterns
55
- if (agent === PNPM) {
56
- for (const workspacePath of [
57
- path.join(cwd, `${PNPM_WORKSPACE}.yaml`),
58
- path.join(cwd, `${PNPM_WORKSPACE}.yml`)
59
- ]) {
60
- // eslint-disable-next-line no-await-in-loop
61
- const yml = await safeReadFile(workspacePath)
62
- if (yml) {
63
- try {
64
- workspacePatterns = vendor.distExports$1.parse(yml)?.packages
65
- } catch {}
66
- if (workspacePatterns) {
67
- break
68
- }
69
- }
70
- }
71
- } else {
72
- workspacePatterns = (
73
- await packages.readPackageJson(cwd, {
74
- throws: false
75
- })
76
- )?.['workspaces']
77
- }
78
- return Array.isArray(workspacePatterns)
79
- ? workspacePatterns
80
- .filter(strings.isNonEmptyString)
81
- .map(workspacePatternToGlobPattern)
82
- : []
83
- }
84
- function ignoreFileLinesToGlobPatterns(lines, filepath, cwd) {
85
- const base = path.relative(cwd, path.dirname(filepath)).replace(/\\/g, '/')
86
- const patterns = []
87
- for (let i = 0, { length } = lines; i < length; i += 1) {
88
- const pattern = lines[i].trim()
89
- if (pattern.length > 0 && pattern.charCodeAt(0) !== 35 /*'#'*/) {
90
- patterns.push(
91
- ignorePatternToMinimatch(
92
- pattern.length && pattern.charCodeAt(0) === 33 /*'!'*/
93
- ? `!${path.posix.join(base, pattern.slice(1))}`
94
- : path.posix.join(base, pattern)
95
- )
96
- )
97
- }
98
- }
99
- return patterns
100
- }
101
- function ignoreFileToGlobPatterns(content, filepath, cwd) {
102
- return ignoreFileLinesToGlobPatterns(content.split(/\r?\n/), filepath, cwd)
103
- }
104
-
105
- // Based on `@eslint/compat` convertIgnorePatternToMinimatch.
106
- // Apache v2.0 licensed
107
- // Copyright Nicholas C. Zakas
108
- // https://github.com/eslint/rewrite/blob/compat-v1.2.1/packages/compat/src/ignore-file.js#L28
109
- function ignorePatternToMinimatch(pattern) {
110
- const isNegated = pattern.startsWith('!')
111
- const negatedPrefix = isNegated ? '!' : ''
112
- const patternToTest = (isNegated ? pattern.slice(1) : pattern).trimEnd()
113
- // Special cases.
114
- if (
115
- patternToTest === '' ||
116
- patternToTest === '**' ||
117
- patternToTest === '/**' ||
118
- patternToTest === '**'
119
- ) {
120
- return `${negatedPrefix}${patternToTest}`
121
- }
122
- const firstIndexOfSlash = patternToTest.indexOf('/')
123
- const matchEverywherePrefix =
124
- firstIndexOfSlash === -1 || firstIndexOfSlash === patternToTest.length - 1
125
- ? '**/'
126
- : ''
127
- const patternWithoutLeadingSlash =
128
- firstIndexOfSlash === 0 ? patternToTest.slice(1) : patternToTest
129
- // Escape `{` and `(` because in gitignore patterns they are just
130
- // literal characters without any specific syntactic meaning,
131
- // while in minimatch patterns they can form brace expansion or extglob syntax.
132
- //
133
- // For example, gitignore pattern `src/{a,b}.js` ignores file `src/{a,b}.js`.
134
- // But, the same minimatch pattern `src/{a,b}.js` ignores files `src/a.js` and `src/b.js`.
135
- // Minimatch pattern `src/\{a,b}.js` is equivalent to gitignore pattern `src/{a,b}.js`.
136
- const escapedPatternWithoutLeadingSlash =
137
- patternWithoutLeadingSlash.replaceAll(
138
- /(?=((?:\\.|[^{(])*))\1([{(])/guy,
139
- '$1\\$2'
140
- )
141
- const matchInsideSuffix = patternToTest.endsWith('/**') ? '/*' : ''
142
- return `${negatedPrefix}${matchEverywherePrefix}${escapedPatternWithoutLeadingSlash}${matchInsideSuffix}`
143
- }
144
- function workspacePatternToGlobPattern(workspace) {
145
- const { length } = workspace
146
- if (!length) {
147
- return ''
148
- }
149
- // If the workspace ends with "/"
150
- if (workspace.charCodeAt(length - 1) === 47 /*'/'*/) {
151
- return `${workspace}/*/package.json`
152
- }
153
- // If the workspace ends with "/**"
154
- if (
155
- workspace.charCodeAt(length - 1) === 42 /*'*'*/ &&
156
- workspace.charCodeAt(length - 2) === 42 /*'*'*/ &&
157
- workspace.charCodeAt(length - 3) === 47 /*'/'*/
158
- ) {
159
- return `${workspace}/*/**/package.json`
160
- }
161
- // Things like "packages/a" or "packages/*"
162
- return `${workspace}/package.json`
163
- }
164
- async function filterGlobResultToSupportedFiles(entries, supportedFiles) {
165
- const patterns = ['golang', NPM$3, 'maven', 'pypi', 'gem', 'nuget'].reduce(
166
- (r, n) => {
167
- const supported = supportedFiles[n]
168
- r.push(
169
- ...(supported
170
- ? Object.values(supported).map(p => `**/${p.pattern}`)
171
- : [])
172
- )
173
- return r
174
- },
175
- []
176
- )
177
- return entries.filter(p => vendor.micromatchExports.some(p, patterns))
178
- }
179
- async function globWithGitIgnore(patterns, options) {
180
- const {
181
- cwd = process$1.cwd(),
182
- socketConfig,
183
- ...additionalOptions
184
- } = {
185
- __proto__: null,
186
- ...options
187
- }
188
- const projectIgnorePaths = socketConfig?.projectIgnorePaths
189
- const ignoreFiles = await vendor.distExports.glob(['**/.gitignore'], {
190
- absolute: true,
191
- cwd,
192
- expandDirectories: true
193
- })
194
- const ignores = [
195
- ...ignoredDirPatterns,
196
- ...(Array.isArray(projectIgnorePaths)
197
- ? ignoreFileLinesToGlobPatterns(
198
- projectIgnorePaths,
199
- path.join(cwd, '.gitignore'),
200
- cwd
201
- )
202
- : []),
203
- ...(
204
- await Promise.all(
205
- ignoreFiles.map(async filepath =>
206
- ignoreFileToGlobPatterns(
207
- await fs.promises.readFile(filepath, 'utf8'),
208
- filepath,
209
- cwd
210
- )
211
- )
212
- )
213
- ).flat()
214
- ]
215
- const hasNegatedPattern = ignores.some(p => p.charCodeAt(0) === 33 /*'!'*/)
216
- const globOptions = {
217
- absolute: true,
218
- cwd,
219
- expandDirectories: false,
220
- ignore: hasNegatedPattern ? [] : ignores,
221
- ...additionalOptions
222
- }
223
- const result = await vendor.distExports.glob(patterns, globOptions)
224
- if (!hasNegatedPattern) {
225
- return result
226
- }
227
- const { absolute } = globOptions
228
-
229
- // Note: the input files must be INSIDE the cwd. If you get strange looking
230
- // relative path errors here, most likely your path is outside the given cwd.
231
- const filtered = vendor
232
- .ignoreExports()
233
- .add(ignores)
234
- .filter(absolute ? result.map(p => path.relative(cwd, p)) : result)
235
- return absolute ? filtered.map(p => path.resolve(cwd, p)) : filtered
236
- }
237
- async function globNodeModules(cwd = process$1.cwd()) {
238
- return await vendor.distExports.glob('**/node_modules/**', {
239
- absolute: true,
240
- cwd
241
- })
242
- }
243
- async function globWorkspace(agent, cwd = process$1.cwd()) {
244
- const workspaceGlobs = await getWorkspaceGlobs(agent, cwd)
245
- return workspaceGlobs.length
246
- ? await vendor.distExports.glob(workspaceGlobs, {
247
- absolute: true,
248
- cwd,
249
- ignore: ['**/node_modules/**', '**/bower_components/**']
250
- })
251
- : []
252
- }
253
- function pathsToGlobPatterns(paths) {
254
- // TODO: Does not support `~/` paths.
255
- return paths.map(p => (p === '.' || p === './' ? '**/*' : p))
256
- }
257
-
258
- const { abortSignal } = constants
259
- async function removeNodeModules(cwd = process$1.cwd()) {
260
- const nodeModulesPaths = await globNodeModules(cwd)
261
- await Promise.all(nodeModulesPaths.map(p => fs$1.remove(p)))
262
- }
263
- async function findUp(name, { cwd = process$1.cwd(), signal = abortSignal }) {
264
- let dir = path.resolve(cwd)
265
- const { root } = path.parse(dir)
266
- const names = [name].flat()
267
- while (dir && dir !== root) {
268
- for (const name of names) {
269
- if (signal?.aborted) {
270
- return undefined
271
- }
272
- const filePath = path.join(dir, name)
273
- try {
274
- // eslint-disable-next-line no-await-in-loop
275
- const stats = await fs.promises.stat(filePath)
276
- if (stats.isFile()) {
277
- return filePath
278
- }
279
- } catch {}
280
- }
281
- dir = path.dirname(dir)
282
- }
283
- return undefined
284
- }
285
- async function readFileBinary(filepath, options) {
286
- return await fs.promises.readFile(filepath, {
287
- signal: abortSignal,
288
- ...options,
289
- encoding: 'binary'
290
- })
291
- }
292
- async function readFileUtf8(filepath, options) {
293
- return await fs.promises.readFile(filepath, {
294
- signal: abortSignal,
295
- ...options,
296
- encoding: 'utf8'
297
- })
298
- }
299
- async function safeReadFile(filepath, options) {
300
- try {
301
- return await fs.promises.readFile(filepath, {
302
- encoding: 'utf8',
303
- signal: abortSignal,
304
- ...(typeof options === 'string'
305
- ? {
306
- encoding: options
307
- }
308
- : options)
309
- })
310
- } catch {}
311
- return undefined
312
- }
313
- function safeReadFileSync(filepath, options) {
314
- try {
315
- return fs.readFileSync(filepath, {
316
- encoding: 'utf8',
317
- ...(typeof options === 'string'
318
- ? {
319
- encoding: options
320
- }
321
- : options)
322
- })
323
- } catch {}
324
- return undefined
325
- }
326
-
327
- const { LOCALAPPDATA, SOCKET_APP_DIR, XDG_DATA_HOME } = constants
328
- const supportedConfigKeys = new Map([
329
- ['apiBaseUrl', 'Base URL of the API endpoint'],
330
- ['apiProxy', 'A proxy through which to access the API'],
331
- ['apiToken', 'The API token required to access most API endpoints'],
332
- [
333
- 'defaultOrg',
334
- 'The default org slug to use; usually the org your API token has access to. When set, all orgSlug arguments are implied to be this value.'
335
- ],
336
- [
337
- 'enforcedOrgs',
338
- 'Orgs in this list have their security policies enforced on this machine'
339
- ]
340
- ])
341
- const sensitiveConfigKeys = new Set(['apiToken'])
342
- let _cachedConfig
343
- // When using --config or SOCKET_CLI_CONFIG, do not persist the config.
344
- let _readOnlyConfig = false
345
- function overrideCachedConfig(jsonConfig) {
346
- debug.debugLog('Overriding entire config, marking config as read-only')
347
- let config
348
- try {
349
- config = JSON.parse(String(jsonConfig))
350
- if (!config || typeof config !== 'object') {
351
- // Just throw to reuse the error message. `null` is valid json,
352
- // so are primitive values. They're not valid config objects :)
353
- throw new Error()
354
- }
355
- } catch {
356
- return {
357
- ok: false,
358
- message:
359
- "Could not JSON parse the config override. Make sure it's a proper JSON object (double-quoted keys and strings, no unquoted `undefined`) and try again."
360
- }
361
- }
362
-
363
- // @ts-ignore Override an illegal object.
364
- _cachedConfig = config
365
- _readOnlyConfig = true
366
-
367
- // Normalize apiKey to apiToken.
368
- if (_cachedConfig['apiKey']) {
369
- if (_cachedConfig['apiToken']) {
370
- logger.logger.warn(
371
- 'Note: The config override had both apiToken and apiKey. Using the apiToken value. Remove the apiKey to get rid of this message.'
372
- )
373
- }
374
- _cachedConfig['apiToken'] = _cachedConfig['apiKey']
375
- delete _cachedConfig['apiKey']
376
- }
377
- return {
378
- ok: true,
379
- message: undefined
380
- }
381
- }
382
- function overrideConfigApiToken(apiToken) {
383
- debug.debugLog('Overriding API token, marking config as read-only')
384
- // Set token to the local cached config and mark it read-only so it doesn't persist
385
- _cachedConfig = {
386
- ...vendor.configExports,
387
- ...(apiToken === undefined
388
- ? {}
389
- : {
390
- apiToken: String(apiToken)
391
- })
392
- }
393
- _readOnlyConfig = true
394
- }
395
- function getConfigValues() {
396
- if (_cachedConfig === undefined) {
397
- _cachedConfig = {}
398
- // Order: env var > --config flag > file
399
- const configPath = getConfigPath()
400
- if (configPath) {
401
- const raw = safeReadFileSync(configPath)
402
- if (raw) {
403
- try {
404
- Object.assign(
405
- _cachedConfig,
406
- JSON.parse(Buffer.from(raw, 'base64').toString())
407
- )
408
- } catch {
409
- logger.logger.warn(`Failed to parse config at ${configPath}`)
410
- }
411
- // Normalize apiKey to apiToken and persist it.
412
- // This is a one time migration per user.
413
- if (_cachedConfig['apiKey']) {
414
- const token = _cachedConfig['apiKey']
415
- delete _cachedConfig['apiKey']
416
- updateConfigValue('apiToken', token)
417
- }
418
- } else {
419
- fs.mkdirSync(path.dirname(configPath), {
420
- recursive: true
421
- })
422
- }
423
- }
424
- }
425
- return _cachedConfig
426
- }
427
- let _configPath
428
- let _warnedConfigPathWin32Missing = false
429
- function getConfigPath() {
430
- // Get the OS app data folder:
431
- // - Win: %LOCALAPPDATA% or fail?
432
- // - Mac: %XDG_DATA_HOME% or fallback to "~/Library/Application Support/"
433
- // - Linux: %XDG_DATA_HOME% or fallback to "~/.local/share/"
434
- // Note: LOCALAPPDATA is typically: C:\Users\USERNAME\AppData
435
- // Note: XDG stands for "X Desktop Group", nowadays "freedesktop.org"
436
- // On most systems that path is: $HOME/.local/share
437
- // Then append `socket/settings`, so:
438
- // - Win: %LOCALAPPDATA%\socket\settings or return undefined
439
- // - Mac: %XDG_DATA_HOME%/socket/settings or "~/Library/Application Support/socket/settings"
440
- // - Linux: %XDG_DATA_HOME%/socket/settings or "~/.local/share/socket/settings"
441
-
442
- if (_configPath === undefined) {
443
- // Lazily access constants.WIN32.
444
- const { WIN32 } = constants
445
- let dataHome = WIN32
446
- ? // Lazily access constants.ENV[LOCALAPPDATA]
447
- constants.ENV[LOCALAPPDATA]
448
- : // Lazily access constants.ENV[XDG_DATA_HOME]
449
- constants.ENV[XDG_DATA_HOME]
450
- if (!dataHome) {
451
- if (WIN32) {
452
- if (!_warnedConfigPathWin32Missing) {
453
- _warnedConfigPathWin32Missing = true
454
- logger.logger.warn(`Missing %${LOCALAPPDATA}%`)
455
- }
456
- } else {
457
- dataHome = path.join(
458
- os.homedir(),
459
- ...(process$1.platform === 'darwin'
460
- ? ['Library', 'Application Support']
461
- : ['.local', 'share'])
462
- )
463
- }
464
- }
465
- _configPath = dataHome ? path.join(dataHome, SOCKET_APP_DIR) : undefined
466
- }
467
- return _configPath
468
- }
469
- function normalizeConfigKey(key) {
470
- // Note: apiKey was the old name of the token. When we load a config with
471
- // property apiKey, we'll copy that to apiToken and delete the old property.
472
- const normalizedKey = key === 'apiKey' ? 'apiToken' : key
473
- if (!supportedConfigKeys.has(normalizedKey)) {
474
- throw new Error(`Invalid config key: ${normalizedKey}`)
475
- }
476
- return normalizedKey
477
- }
478
- function findSocketYmlSync(dir = process$1.cwd()) {
479
- let prevDir = null
480
- while (dir !== prevDir) {
481
- let ymlPath = path.join(dir, 'socket.yml')
482
- let yml = safeReadFileSync(ymlPath)
483
- if (yml === undefined) {
484
- ymlPath = path.join(dir, 'socket.yaml')
485
- yml = safeReadFileSync(ymlPath)
486
- }
487
- if (typeof yml === 'string') {
488
- try {
489
- return {
490
- path: ymlPath,
491
- parsed: vendor.configExports.parseSocketConfig(yml)
492
- }
493
- } catch {
494
- throw new Error(`Found file but was unable to parse ${ymlPath}`)
495
- }
496
- }
497
- prevDir = dir
498
- dir = path.join(dir, '..')
499
- }
500
- return null
501
- }
502
- function getConfigValue(key) {
503
- const localConfig = getConfigValues()
504
- return localConfig[normalizeConfigKey(key)]
505
- }
506
- function isReadOnlyConfig() {
507
- return _readOnlyConfig
508
- }
509
- let _pendingSave = false
510
- function updateConfigValue(key, value) {
511
- const localConfig = getConfigValues()
512
- localConfig[normalizeConfigKey(key)] = value
513
- if (_readOnlyConfig) {
514
- logger.logger.warn(
515
- 'Not persisting config change; current config overridden through env var or flag'
516
- )
517
- } else if (!_pendingSave) {
518
- _pendingSave = true
519
- process$1.nextTick(() => {
520
- _pendingSave = false
521
- const configPath = getConfigPath()
522
- if (configPath) {
523
- fs.writeFileSync(
524
- configPath,
525
- Buffer.from(JSON.stringify(localConfig)).toString('base64')
526
- )
527
- }
528
- })
529
- }
530
- }
531
-
532
- const {
533
- kInternalsSymbol: kInternalsSymbol$1,
534
- [kInternalsSymbol$1]: { getSentry }
535
- } = constants
536
- class AuthError extends Error {}
537
- class InputError extends Error {
538
- constructor(message, body) {
539
- super(message)
540
- this.body = body
541
- }
542
- }
543
- async function captureException(exception, hint) {
544
- const result = captureExceptionSync(exception, hint)
545
- // "Sleep" for a second, just in case, hopefully enough time to initiate fetch.
546
- await promises.setTimeout(1000)
547
- return result
548
- }
549
- function captureExceptionSync(exception, hint) {
550
- const Sentry = getSentry()
551
- if (!Sentry) {
552
- return ''
553
- }
554
- debug.debugLog('captureException: Sending exception to Sentry')
555
- return Sentry.captureException(exception, hint)
556
- }
557
-
558
- const {
559
- SOCKET_CLI_NO_API_TOKEN,
560
- SOCKET_SECURITY_API_BASE_URL,
561
- SOCKET_SECURITY_API_PROXY,
562
- SOCKET_SECURITY_API_TOKEN
563
- } = constants
564
-
565
- // The API server that should be used for operations.
566
- function getDefaultApiBaseUrl() {
567
- const baseUrl =
568
- // Lazily access constants.ENV[SOCKET_SECURITY_API_BASE_URL].
569
- constants.ENV[SOCKET_SECURITY_API_BASE_URL] || getConfigValue('apiBaseUrl')
570
- return strings.isNonEmptyString(baseUrl) ? baseUrl : undefined
571
- }
572
-
573
- // The API server that should be used for operations.
574
- function getDefaultHttpProxy() {
575
- const apiProxy =
576
- // Lazily access constants.ENV[SOCKET_SECURITY_API_PROXY].
577
- constants.ENV[SOCKET_SECURITY_API_PROXY] || getConfigValue('apiProxy')
578
- return strings.isNonEmptyString(apiProxy) ? apiProxy : undefined
579
- }
580
-
581
- // This API key should be stored globally for the duration of the CLI execution.
582
- let _defaultToken
583
- function getDefaultToken() {
584
- // Lazily access constants.ENV[SOCKET_CLI_NO_API_TOKEN].
585
- if (constants.ENV[SOCKET_CLI_NO_API_TOKEN]) {
586
- _defaultToken = undefined
587
- } else {
588
- const key =
589
- // Lazily access constants.ENV[SOCKET_SECURITY_API_TOKEN].
590
- constants.ENV[SOCKET_SECURITY_API_TOKEN] ||
591
- getConfigValue('apiToken') ||
592
- _defaultToken
593
- _defaultToken = strings.isNonEmptyString(key) ? key : undefined
594
- }
595
- return _defaultToken
596
- }
597
- function getPublicToken() {
598
- return (
599
- // Lazily access constants.ENV[SOCKET_SECURITY_API_TOKEN].
600
- (constants.ENV[SOCKET_SECURITY_API_TOKEN] || getDefaultToken()) ??
601
- registryConstants.SOCKET_PUBLIC_API_TOKEN
602
- )
603
- }
604
- async function setupSdk(
605
- apiToken = getDefaultToken(),
606
- apiBaseUrl = getDefaultApiBaseUrl(),
607
- proxy = getDefaultHttpProxy()
608
- ) {
609
- if (typeof apiToken !== 'string' && isInteractive()) {
610
- apiToken = await prompts.password({
611
- message:
612
- 'Enter your Socket.dev API key (not saved, use socket login to persist)'
613
- })
614
- _defaultToken = apiToken
615
- }
616
- if (!apiToken) {
617
- throw new AuthError('You need to provide an API key')
618
- }
619
- return new sdk.SocketSdk(apiToken, {
620
- agent: proxy
621
- ? new vendor.HttpsProxyAgent({
622
- proxy
623
- })
624
- : undefined,
625
- baseUrl: apiBaseUrl,
626
- userAgent: sdk.createUserAgentFromPkgJson({
627
- // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_NAME']".
628
- name: '@socketsecurity/cli',
629
- // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_VERSION']".
630
- version: '0.14.129',
631
- // The '@rollup/plugin-replace' will replace "process.env['INLINED_SOCKET_CLI_HOMEPAGE']".
632
- homepage: 'https://github.com/SocketDev/socket-cli'
633
- })
634
- })
635
- }
636
-
637
- const RangeStyles = ['caret', 'gt', 'lt', 'pin', 'preserve', 'tilde']
638
- function applyRange(refRange, version, style = 'preserve') {
639
- switch (style) {
640
- case 'caret':
641
- return `^${version}`
642
- case 'gt':
643
- return `>${version}`
644
- case 'gte':
645
- return `>=${version}`
646
- case 'lt':
647
- return `<${version}`
648
- case 'lte':
649
- return `<=${version}`
650
- case 'preserve': {
651
- const comparators = [
652
- ...new vendor.semverExports.Range(refRange).set
653
- ].flat()
654
- const { length } = comparators
655
- return !length || length > 1
656
- ? version
657
- : `${comparators[0].operator}${version}`
658
- }
659
- case 'tilde':
660
- return `~${version}`
661
- case 'pin':
662
- default:
663
- return version
664
- }
665
- }
666
- function getMajor(version) {
667
- const coerced = vendor.semverExports.coerce(version)
668
- if (coerced) {
669
- try {
670
- return vendor.semverExports.major(coerced)
671
- } catch (e) {
672
- debug.debugLog(`Error parsing '${version}'`, e)
673
- }
674
- }
675
- return null
676
- }
677
-
678
- const DiffAction = /*#__PURE__*/ (function (DiffAction) {
679
- DiffAction['add'] = 'ADD'
680
- DiffAction['change'] = 'CHANGE'
681
- DiffAction['remove'] = 'REMOVE'
682
- return DiffAction
683
- })({})
684
-
685
- const depValid = require(shadowNpmPaths.getArboristDepValidPath())
686
-
687
- const { UNDEFINED_TOKEN } = constants
688
- function tryRequire(req, ...ids) {
689
- for (const data of ids) {
690
- let id
691
- let transformer
692
- if (Array.isArray(data)) {
693
- id = data[0]
694
- transformer = data[1]
695
- } else {
696
- id = data
697
- transformer = mod => mod
698
- }
699
- try {
700
- // Check that the transformed value isn't `undefined` because older
701
- // versions of packages like 'proc-log' may not export a `log` method.
702
- const exported = transformer(req(id))
703
- if (exported !== undefined) {
704
- return exported
705
- }
706
- } catch {}
707
- }
708
- return undefined
709
- }
710
- let _log = UNDEFINED_TOKEN
711
- function getLogger() {
712
- if (_log === UNDEFINED_TOKEN) {
713
- _log = tryRequire(
714
- shadowNpmPaths.getNpmRequire(),
715
- [
716
- 'proc-log/lib/index.js',
717
- // The proc-log DefinitelyTyped definition is incorrect. The type definition
718
- // is really that of its export log.
719
- mod => mod.log
720
- ],
721
- 'npmlog/lib/log.js'
722
- )
723
- }
724
- return _log
725
- }
726
-
727
- const OverrideSet = require(shadowNpmPaths.getArboristOverrideSetClassPath())
728
-
729
- // Implementation code not related to patch https://github.com/npm/cli/pull/8089
730
- // is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/override-set.js:
731
- class SafeOverrideSet extends OverrideSet {
732
- // Patch adding doOverrideSetsConflict is based on
733
- // https://github.com/npm/cli/pull/8089.
734
- static doOverrideSetsConflict(first, second) {
735
- // If override sets contain one another then we can try to use the more
736
- // specific one. If neither one is more specific, then we consider them to
737
- // be in conflict.
738
- return this.findSpecificOverrideSet(first, second) === undefined
739
- }
740
-
741
- // Patch adding findSpecificOverrideSet is based on
742
- // https://github.com/npm/cli/pull/8089.
743
- static findSpecificOverrideSet(first, second) {
744
- for (
745
- let overrideSet = second;
746
- overrideSet;
747
- overrideSet = overrideSet.parent
748
- ) {
749
- if (overrideSet.isEqual(first)) {
750
- return second
751
- }
752
- }
753
- for (
754
- let overrideSet = first;
755
- overrideSet;
756
- overrideSet = overrideSet.parent
757
- ) {
758
- if (overrideSet.isEqual(second)) {
759
- return first
760
- }
761
- }
762
- // The override sets are incomparable. Neither one contains the other.
763
- const log = getLogger()
764
- log?.silly('Conflicting override sets', first, second)
765
- return undefined
766
- }
767
-
768
- // Patch adding childrenAreEqual is based on
769
- // https://github.com/npm/cli/pull/8089.
770
- childrenAreEqual(otherOverrideSet) {
771
- if (this.children.size !== otherOverrideSet.children.size) {
772
- return false
773
- }
774
- for (const { 0: key, 1: childOverrideSet } of this.children) {
775
- const otherChildOverrideSet = otherOverrideSet.children.get(key)
776
- if (!otherChildOverrideSet) {
777
- return false
778
- }
779
- if (childOverrideSet.value !== otherChildOverrideSet.value) {
780
- return false
781
- }
782
- if (!childOverrideSet.childrenAreEqual(otherChildOverrideSet)) {
783
- return false
784
- }
785
- }
786
- return true
787
- }
788
- getEdgeRule(edge) {
789
- for (const rule of this.ruleset.values()) {
790
- if (rule.name !== edge.name) {
791
- continue
792
- }
793
- // If keySpec is * we found our override.
794
- if (rule.keySpec === '*') {
795
- return rule
796
- }
797
- // Patch replacing
798
- // let spec = npa(`${edge.name}@${edge.spec}`)
799
- // is based on https://github.com/npm/cli/pull/8089.
800
- //
801
- // We need to use the rawSpec here, because the spec has the overrides
802
- // applied to it already. The rawSpec can be undefined, so we need to use
803
- // the fallback value of spec if it is.
804
- let spec = vendor.npaExports(`${edge.name}@${edge.rawSpec || edge.spec}`)
805
- if (spec.type === 'alias') {
806
- spec = spec.subSpec
807
- }
808
- if (spec.type === 'git') {
809
- if (
810
- spec.gitRange &&
811
- vendor.semverExports.intersects(spec.gitRange, rule.keySpec)
812
- ) {
813
- return rule
814
- }
815
- continue
816
- }
817
- if (spec.type === 'range' || spec.type === 'version') {
818
- if (vendor.semverExports.intersects(spec.fetchSpec, rule.keySpec)) {
819
- return rule
820
- }
821
- continue
822
- }
823
- // If we got this far, the spec type is one of tag, directory or file
824
- // which means we have no real way to make version comparisons, so we
825
- // just accept the override.
826
- return rule
827
- }
828
- return this
829
- }
830
-
831
- // Patch adding isEqual is based on
832
- // https://github.com/npm/cli/pull/8089.
833
- isEqual(otherOverrideSet) {
834
- if (this === otherOverrideSet) {
835
- return true
836
- }
837
- if (!otherOverrideSet) {
838
- return false
839
- }
840
- if (
841
- this.key !== otherOverrideSet.key ||
842
- this.value !== otherOverrideSet.value
843
- ) {
844
- return false
845
- }
846
- if (!this.childrenAreEqual(otherOverrideSet)) {
847
- return false
848
- }
849
- if (!this.parent) {
850
- return !otherOverrideSet.parent
851
- }
852
- return this.parent.isEqual(otherOverrideSet.parent)
853
- }
854
- }
855
-
856
- const Node = require(shadowNpmPaths.getArboristNodeClassPath())
857
-
858
- // Implementation code not related to patch https://github.com/npm/cli/pull/8089
859
- // is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/node.js:
860
- class SafeNode extends Node {
861
- // Return true if it's safe to remove this node, because anything that is
862
- // depending on it would be fine with the thing that they would resolve to if
863
- // it was removed, or nothing is depending on it in the first place.
864
- canDedupe(preferDedupe = false) {
865
- // Not allowed to mess with shrinkwraps or bundles.
866
- if (this.inDepBundle || this.inShrinkwrap) {
867
- return false
868
- }
869
- // It's a top level pkg, or a dep of one.
870
- if (!this.resolveParent?.resolveParent) {
871
- return false
872
- }
873
- // No one wants it, remove it.
874
- if (this.edgesIn.size === 0) {
875
- return true
876
- }
877
- const other = this.resolveParent.resolveParent.resolve(this.name)
878
- // Nothing else, need this one.
879
- if (!other) {
880
- return false
881
- }
882
- // If it's the same thing, then always fine to remove.
883
- if (other.matches(this)) {
884
- return true
885
- }
886
- // If the other thing can't replace this, then skip it.
887
- if (!other.canReplace(this)) {
888
- return false
889
- }
890
- // Patch replacing
891
- // if (preferDedupe || semver.gte(other.version, this.version)) {
892
- // return true
893
- // }
894
- // is based on https://github.com/npm/cli/pull/8089.
895
- //
896
- // If we prefer dedupe, or if the version is equal, take the other.
897
- if (preferDedupe || vendor.semverExports.eq(other.version, this.version)) {
898
- return true
899
- }
900
- // If our current version isn't the result of an override, then prefer to
901
- // take the greater version.
902
- if (
903
- !this.overridden &&
904
- vendor.semverExports.gt(other.version, this.version)
905
- ) {
906
- return true
907
- }
908
- return false
909
- }
910
-
911
- // Is it safe to replace one node with another? check the edges to
912
- // make sure no one will get upset. Note that the node might end up
913
- // having its own unmet dependencies, if the new node has new deps.
914
- // Note that there are cases where Arborist will opt to insert a node
915
- // into the tree even though this function returns false! This is
916
- // necessary when a root dependency is added or updated, or when a
917
- // root dependency brings peer deps along with it. In that case, we
918
- // will go ahead and create the invalid state, and then try to resolve
919
- // it with more tree construction, because it's a user request.
920
- canReplaceWith(node, ignorePeers) {
921
- if (this.name !== node.name || this.packageName !== node.packageName) {
922
- return false
923
- }
924
- // Patch replacing
925
- // if (node.overrides !== this.overrides) {
926
- // return false
927
- // }
928
- // is based on https://github.com/npm/cli/pull/8089.
929
- //
930
- // If this node has no dependencies, then it's irrelevant to check the
931
- // override rules of the replacement node.
932
- if (this.edgesOut.size) {
933
- // XXX need to check for two root nodes?
934
- if (node.overrides) {
935
- if (!node.overrides.isEqual(this.overrides)) {
936
- return false
937
- }
938
- } else {
939
- if (this.overrides) {
940
- return false
941
- }
942
- }
943
- }
944
- // To satisfy the patch we ensure `node.overrides === this.overrides`
945
- // so that the condition we want to replace,
946
- // if (this.overrides !== node.overrides) {
947
- // , is not hit.`
948
- const oldOverrideSet = this.overrides
949
- let result = true
950
- if (oldOverrideSet !== node.overrides) {
951
- this.overrides = node.overrides
952
- }
953
- try {
954
- result = super.canReplaceWith(node, ignorePeers)
955
- this.overrides = oldOverrideSet
956
- } catch (e) {
957
- this.overrides = oldOverrideSet
958
- throw e
959
- }
960
- return result
961
- }
962
-
963
- // Patch adding deleteEdgeIn is based on https://github.com/npm/cli/pull/8089.
964
- deleteEdgeIn(edge) {
965
- this.edgesIn.delete(edge)
966
- const { overrides } = edge
967
- if (overrides) {
968
- this.updateOverridesEdgeInRemoved(overrides)
969
- }
970
- }
971
- addEdgeIn(edge) {
972
- // Patch replacing
973
- // if (edge.overrides) {
974
- // this.overrides = edge.overrides
975
- // }
976
- // is based on https://github.com/npm/cli/pull/8089.
977
- //
978
- // We need to handle the case where the new edge in has an overrides field
979
- // which is different from the current value.
980
- if (!this.overrides || !this.overrides.isEqual(edge.overrides)) {
981
- this.updateOverridesEdgeInAdded(edge.overrides)
982
- }
983
- this.edgesIn.add(edge)
984
- // Try to get metadata from the yarn.lock file.
985
- this.root.meta?.addEdge(edge)
986
- }
987
-
988
- // @ts-ignore: Incorrectly typed as a property instead of an accessor.
989
- get overridden() {
990
- // Patch replacing
991
- // return !!(this.overrides && this.overrides.value && this.overrides.name === this.name)
992
- // is based on https://github.com/npm/cli/pull/8089.
993
- if (
994
- !this.overrides ||
995
- !this.overrides.value ||
996
- this.overrides.name !== this.name
997
- ) {
998
- return false
999
- }
1000
- // The overrides rule is for a package with this name, but some override
1001
- // rules only apply to specific versions. To make sure this package was
1002
- // actually overridden, we check whether any edge going in had the rule
1003
- // applied to it, in which case its overrides set is different than its
1004
- // source node.
1005
- for (const edge of this.edgesIn) {
1006
- if (
1007
- edge.overrides &&
1008
- edge.overrides.name === this.name &&
1009
- edge.overrides.value === this.version
1010
- ) {
1011
- if (!edge.overrides.isEqual(edge.from?.overrides)) {
1012
- return true
1013
- }
1014
- }
1015
- }
1016
- return false
1017
- }
1018
- set parent(newParent) {
1019
- // Patch removing
1020
- // if (parent.overrides) {
1021
- // this.overrides = parent.overrides.getNodeRule(this)
1022
- // }
1023
- // is based on https://github.com/npm/cli/pull/8089.
1024
- //
1025
- // The "parent" setter is a really large and complex function. To satisfy
1026
- // the patch we hold on to the old overrides value and set `this.overrides`
1027
- // to `undefined` so that the condition we want to remove is not hit.
1028
- const { overrides } = this
1029
- if (overrides) {
1030
- this.overrides = undefined
1031
- }
1032
- try {
1033
- super.parent = newParent
1034
- this.overrides = overrides
1035
- } catch (e) {
1036
- this.overrides = overrides
1037
- throw e
1038
- }
1039
- }
1040
-
1041
- // Patch adding recalculateOutEdgesOverrides is based on
1042
- // https://github.com/npm/cli/pull/8089.
1043
- recalculateOutEdgesOverrides() {
1044
- // For each edge out propagate the new overrides through.
1045
- for (const edge of this.edgesOut.values()) {
1046
- edge.reload(true)
1047
- if (edge.to) {
1048
- edge.to.updateOverridesEdgeInAdded(edge.overrides)
1049
- }
1050
- }
1051
- }
1052
-
1053
- // @ts-ignore: Incorrectly typed to accept null.
1054
- set root(newRoot) {
1055
- // Patch removing
1056
- // if (!this.overrides && this.parent && this.parent.overrides) {
1057
- // this.overrides = this.parent.overrides.getNodeRule(this)
1058
- // }
1059
- // is based on https://github.com/npm/cli/pull/8089.
1060
- //
1061
- // The "root" setter is a really large and complex function. To satisfy the
1062
- // patch we add a dummy value to `this.overrides` so that the condition we
1063
- // want to remove is not hit.
1064
- if (!this.overrides) {
1065
- this.overrides = new SafeOverrideSet({
1066
- overrides: ''
1067
- })
1068
- }
1069
- try {
1070
- super.root = newRoot
1071
- this.overrides = undefined
1072
- } catch (e) {
1073
- this.overrides = undefined
1074
- throw e
1075
- }
1076
- }
1077
-
1078
- // Patch adding updateOverridesEdgeInAdded is based on
1079
- // https://github.com/npm/cli/pull/7025.
1080
- //
1081
- // This logic isn't perfect either. When we have two edges in that have
1082
- // different override sets, then we have to decide which set is correct. This
1083
- // function assumes the more specific override set is applicable, so if we have
1084
- // dependencies A->B->C and A->C and an override set that specifies what happens
1085
- // for C under A->B, this will work even if the new A->C edge comes along and
1086
- // tries to change the override set. The strictly correct logic is not to allow
1087
- // two edges with different overrides to point to the same node, because even
1088
- // if this node can satisfy both, one of its dependencies might need to be
1089
- // different depending on the edge leading to it. However, this might cause a
1090
- // lot of duplication, because the conflict in the dependencies might never
1091
- // actually happen.
1092
- updateOverridesEdgeInAdded(otherOverrideSet) {
1093
- if (!otherOverrideSet) {
1094
- // Assuming there are any overrides at all, the overrides field is never
1095
- // undefined for any node at the end state of the tree. So if the new edge's
1096
- // overrides is undefined it will be updated later. So we can wait with
1097
- // updating the node's overrides field.
1098
- return false
1099
- }
1100
- if (!this.overrides) {
1101
- this.overrides = otherOverrideSet
1102
- this.recalculateOutEdgesOverrides()
1103
- return true
1104
- }
1105
- if (this.overrides.isEqual(otherOverrideSet)) {
1106
- return false
1107
- }
1108
- const newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(
1109
- this.overrides,
1110
- otherOverrideSet
1111
- )
1112
- if (newOverrideSet) {
1113
- if (this.overrides.isEqual(newOverrideSet)) {
1114
- return false
1115
- }
1116
- this.overrides = newOverrideSet
1117
- this.recalculateOutEdgesOverrides()
1118
- return true
1119
- }
1120
- // This is an error condition. We can only get here if the new override set
1121
- // is in conflict with the existing.
1122
- const log = getLogger()
1123
- log?.silly('Conflicting override sets', this.name)
1124
- return false
1125
- }
1126
-
1127
- // Patch adding updateOverridesEdgeInRemoved is based on
1128
- // https://github.com/npm/cli/pull/7025.
1129
- updateOverridesEdgeInRemoved(otherOverrideSet) {
1130
- // If this edge's overrides isn't equal to this node's overrides,
1131
- // then removing it won't change newOverrideSet later.
1132
- if (!this.overrides || !this.overrides.isEqual(otherOverrideSet)) {
1133
- return false
1134
- }
1135
- let newOverrideSet
1136
- for (const edge of this.edgesIn) {
1137
- const { overrides: edgeOverrides } = edge
1138
- if (newOverrideSet && edgeOverrides) {
1139
- newOverrideSet = SafeOverrideSet.findSpecificOverrideSet(
1140
- edgeOverrides,
1141
- newOverrideSet
1142
- )
1143
- } else {
1144
- newOverrideSet = edgeOverrides
1145
- }
1146
- }
1147
- if (this.overrides.isEqual(newOverrideSet)) {
1148
- return false
1149
- }
1150
- this.overrides = newOverrideSet
1151
- if (newOverrideSet) {
1152
- // Optimization: If there's any override set at all, then no non-extraneous
1153
- // node has an empty override set. So if we temporarily have no override set
1154
- // (for example, we removed all the edges in), there's no use updating all
1155
- // the edges out right now. Let's just wait until we have an actual override
1156
- // set later.
1157
- this.recalculateOutEdgesOverrides()
1158
- }
1159
- return true
1160
- }
1161
- }
1162
-
1163
- const Edge = require(shadowNpmPaths.getArboristEdgeClassPath())
1164
-
1165
- // The Edge class makes heavy use of private properties which subclasses do NOT
1166
- // have access to. So we have to recreate any functionality that relies on those
1167
- // private properties and use our own "safe" prefixed non-conflicting private
1168
- // properties. Implementation code not related to patch https://github.com/npm/cli/pull/8089
1169
- // is based on https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/edge.js.
1170
- //
1171
- // The npm application
1172
- // Copyright (c) npm, Inc. and Contributors
1173
- // Licensed on the terms of The Artistic License 2.0
1174
- //
1175
- // An edge in the dependency graph.
1176
- // Represents a dependency relationship of some kind.
1177
- class SafeEdge extends Edge {
1178
- #safeError
1179
- #safeExplanation
1180
- #safeFrom
1181
- #safeTo
1182
- constructor(options) {
1183
- const { from } = options
1184
- // Defer to supper to validate options and assign non-private values.
1185
- super(options)
1186
- if (from.constructor !== SafeNode) {
1187
- Reflect.setPrototypeOf(from, SafeNode.prototype)
1188
- }
1189
- this.#safeError = null
1190
- this.#safeExplanation = null
1191
- this.#safeFrom = from
1192
- this.#safeTo = null
1193
- this.reload(true)
1194
- }
1195
- get bundled() {
1196
- return !!this.#safeFrom?.package?.bundleDependencies?.includes(this.name)
1197
- }
1198
- get error() {
1199
- if (!this.#safeError) {
1200
- if (!this.#safeTo) {
1201
- if (this.optional) {
1202
- this.#safeError = null
1203
- } else {
1204
- this.#safeError = 'MISSING'
1205
- }
1206
- } else if (
1207
- this.peer &&
1208
- this.#safeFrom === this.#safeTo.parent &&
1209
- // Patch adding "?." use based on
1210
- // https://github.com/npm/cli/pull/8089.
1211
- !this.#safeFrom?.isTop
1212
- ) {
1213
- this.#safeError = 'PEER LOCAL'
1214
- } else if (!this.satisfiedBy(this.#safeTo)) {
1215
- this.#safeError = 'INVALID'
1216
- }
1217
- // Patch adding "else if" condition is based on
1218
- // https://github.com/npm/cli/pull/8089.
1219
- else if (
1220
- this.overrides &&
1221
- this.#safeTo.edgesOut.size &&
1222
- SafeOverrideSet.doOverrideSetsConflict(
1223
- this.overrides,
1224
- this.#safeTo.overrides
1225
- )
1226
- ) {
1227
- // Any inconsistency between the edge's override set and the target's
1228
- // override set is potentially problematic. But we only say the edge is
1229
- // in error if the override sets are plainly conflicting. Note that if
1230
- // the target doesn't have any dependencies of their own, then this
1231
- // inconsistency is irrelevant.
1232
- this.#safeError = 'INVALID'
1233
- } else {
1234
- this.#safeError = 'OK'
1235
- }
1236
- }
1237
- if (this.#safeError === 'OK') {
1238
- return null
1239
- }
1240
- return this.#safeError
1241
- }
1242
-
1243
- // @ts-ignore: Incorrectly typed as a property instead of an accessor.
1244
- get from() {
1245
- return this.#safeFrom
1246
- }
1247
-
1248
- // @ts-ignore: Incorrectly typed as a property instead of an accessor.
1249
- get spec() {
1250
- if (
1251
- this.overrides?.value &&
1252
- this.overrides.value !== '*' &&
1253
- this.overrides.name === this.name
1254
- ) {
1255
- if (this.overrides.value.startsWith('$')) {
1256
- const ref = this.overrides.value.slice(1)
1257
- // We may be a virtual root, if we are we want to resolve reference
1258
- // overrides from the real root, not the virtual one.
1259
- //
1260
- // Patch adding "?." use based on
1261
- // https://github.com/npm/cli/pull/8089.
1262
- const pkg = this.#safeFrom?.sourceReference
1263
- ? this.#safeFrom?.sourceReference.root.package
1264
- : this.#safeFrom?.root?.package
1265
- if (pkg?.devDependencies?.[ref]) {
1266
- return pkg.devDependencies[ref]
1267
- }
1268
- if (pkg?.optionalDependencies?.[ref]) {
1269
- return pkg.optionalDependencies[ref]
1270
- }
1271
- if (pkg?.dependencies?.[ref]) {
1272
- return pkg.dependencies[ref]
1273
- }
1274
- if (pkg?.peerDependencies?.[ref]) {
1275
- return pkg.peerDependencies[ref]
1276
- }
1277
- throw new Error(`Unable to resolve reference ${this.overrides.value}`)
1278
- }
1279
- return this.overrides.value
1280
- }
1281
- return this.rawSpec
1282
- }
1283
-
1284
- // @ts-ignore: Incorrectly typed as a property instead of an accessor.
1285
- get to() {
1286
- return this.#safeTo
1287
- }
1288
- detach() {
1289
- this.#safeExplanation = null
1290
- // Patch replacing
1291
- // if (this.#to) {
1292
- // this.#to.edgesIn.delete(this)
1293
- // }
1294
- // this.#from.edgesOut.delete(this.#name)
1295
- // is based on https://github.com/npm/cli/pull/8089.
1296
- this.#safeTo?.deleteEdgeIn(this)
1297
- this.#safeFrom?.edgesOut.delete(this.name)
1298
- this.#safeTo = null
1299
- this.#safeError = 'DETACHED'
1300
- this.#safeFrom = null
1301
- }
1302
-
1303
- // Return the edge data, and an explanation of how that edge came to be here.
1304
- // @ts-ignore: Edge#explain is defined with an unused `seen = []` param.
1305
- explain() {
1306
- if (!this.#safeExplanation) {
1307
- const explanation = {
1308
- type: this.type,
1309
- name: this.name,
1310
- spec: this.spec,
1311
- bundled: false,
1312
- overridden: false,
1313
- error: undefined,
1314
- from: undefined,
1315
- rawSpec: undefined
1316
- }
1317
- if (this.rawSpec !== this.spec) {
1318
- explanation.rawSpec = this.rawSpec
1319
- explanation.overridden = true
1320
- }
1321
- if (this.bundled) {
1322
- explanation.bundled = this.bundled
1323
- }
1324
- if (this.error) {
1325
- explanation.error = this.error
1326
- }
1327
- if (this.#safeFrom) {
1328
- explanation.from = this.#safeFrom.explain()
1329
- }
1330
- this.#safeExplanation = explanation
1331
- }
1332
- return this.#safeExplanation
1333
- }
1334
- reload(hard = false) {
1335
- this.#safeExplanation = null
1336
- // Patch replacing
1337
- // if (this.#from.overrides) {
1338
- // is based on https://github.com/npm/cli/pull/8089.
1339
- let needToUpdateOverrideSet = false
1340
- let newOverrideSet
1341
- let oldOverrideSet
1342
- if (this.#safeFrom?.overrides) {
1343
- newOverrideSet = this.#safeFrom.overrides.getEdgeRule(this)
1344
- if (newOverrideSet && !newOverrideSet.isEqual(this.overrides)) {
1345
- // If there's a new different override set we need to propagate it to
1346
- // the nodes. If we're deleting the override set then there's no point
1347
- // propagating it right now since it will be filled with another value
1348
- // later.
1349
- needToUpdateOverrideSet = true
1350
- oldOverrideSet = this.overrides
1351
- this.overrides = newOverrideSet
1352
- }
1353
- } else {
1354
- this.overrides = undefined
1355
- }
1356
- // Patch adding "?." use based on
1357
- // https://github.com/npm/cli/pull/8089.
1358
- const newTo = this.#safeFrom?.resolve(this.name)
1359
- if (newTo !== this.#safeTo) {
1360
- // Patch replacing
1361
- // this.#to.edgesIn.delete(this)
1362
- // is based on https://github.com/npm/cli/pull/8089.
1363
- this.#safeTo?.deleteEdgeIn(this)
1364
- this.#safeTo = newTo ?? null
1365
- this.#safeError = null
1366
- this.#safeTo?.addEdgeIn(this)
1367
- } else if (hard) {
1368
- this.#safeError = null
1369
- }
1370
- // Patch adding "else if" condition based on
1371
- // https://github.com/npm/cli/pull/8089.
1372
- else if (needToUpdateOverrideSet && this.#safeTo) {
1373
- // Propagate the new override set to the target node.
1374
- this.#safeTo.updateOverridesEdgeInRemoved(oldOverrideSet)
1375
- this.#safeTo.updateOverridesEdgeInAdded(newOverrideSet)
1376
- }
1377
- }
1378
- satisfiedBy(node) {
1379
- // Patch replacing
1380
- // if (node.name !== this.#name) {
1381
- // return false
1382
- // }
1383
- // is based on https://github.com/npm/cli/pull/8089.
1384
- if (node.name !== this.name || !this.#safeFrom) {
1385
- return false
1386
- }
1387
- // NOTE: this condition means we explicitly do not support overriding
1388
- // bundled or shrinkwrapped dependencies
1389
- if (node.hasShrinkwrap || node.inShrinkwrap || node.inBundle) {
1390
- return depValid(node, this.rawSpec, this.accept, this.#safeFrom)
1391
- }
1392
- // Patch replacing
1393
- // return depValid(node, this.spec, this.#accept, this.#from)
1394
- // is based on https://github.com/npm/cli/pull/8089.
1395
- //
1396
- // If there's no override we just use the spec.
1397
- if (!this.overrides?.keySpec) {
1398
- return depValid(node, this.spec, this.accept, this.#safeFrom)
1399
- }
1400
- // There's some override. If the target node satisfies the overriding spec
1401
- // then it's okay.
1402
- if (depValid(node, this.spec, this.accept, this.#safeFrom)) {
1403
- return true
1404
- }
1405
- // If it doesn't, then it should at least satisfy the original spec.
1406
- if (!depValid(node, this.rawSpec, this.accept, this.#safeFrom)) {
1407
- return false
1408
- }
1409
- // It satisfies the original spec, not the overriding spec. We need to make
1410
- // sure it doesn't use the overridden spec.
1411
- // For example:
1412
- // we might have an ^8.0.0 rawSpec, and an override that makes
1413
- // keySpec=8.23.0 and the override value spec=9.0.0.
1414
- // If the node is 9.0.0, then it's okay because it's consistent with spec.
1415
- // If the node is 8.24.0, then it's okay because it's consistent with the rawSpec.
1416
- // If the node is 8.23.0, then it's not okay because even though it's consistent
1417
- // with the rawSpec, it's also consistent with the keySpec.
1418
- // So we're looking for ^8.0.0 or 9.0.0 and not 8.23.0.
1419
- return !depValid(node, this.overrides.keySpec, this.accept, this.#safeFrom)
1420
- }
1421
- }
1422
-
1423
- const { LOOP_SENTINEL, NPM: NPM$2, NPM_REGISTRY_URL } = constants
1424
- function getUrlOrigin(input) {
1425
- try {
1426
- // TODO: URL.parse is available in Node 22.1.0. We can use it when we drop Node 18.
1427
- // https://nodejs.org/docs/latest-v22.x/api/url.html#urlparseinput-base
1428
- // return URL.parse(input)?.origin ?? ''
1429
- return new URL(input).origin ?? ''
1430
- } catch {}
1431
- return ''
1432
- }
1433
- function findBestPatchVersion(
1434
- node,
1435
- availableVersions,
1436
- vulnerableVersionRange,
1437
- _firstPatchedVersionIdentifier
1438
- ) {
1439
- const manifestData = registry.getManifestData(NPM$2, node.name)
1440
- let eligibleVersions
1441
- if (manifestData && manifestData.name === manifestData.package) {
1442
- const major = getMajor(manifestData.version)
1443
- if (typeof major !== 'number') {
1444
- return null
1445
- }
1446
- eligibleVersions = availableVersions.filter(v => getMajor(v) === major)
1447
- } else {
1448
- const major = getMajor(node.version)
1449
- if (typeof major !== 'number') {
1450
- return null
1451
- }
1452
- eligibleVersions = availableVersions.filter(
1453
- v =>
1454
- // Filter for versions that are within the current major version and
1455
- // are NOT in the vulnerable range.
1456
- getMajor(v) === major &&
1457
- (!vulnerableVersionRange ||
1458
- !vendor.semverExports.satisfies(v, vulnerableVersionRange))
1459
- )
1460
- }
1461
- return eligibleVersions
1462
- ? vendor.semverExports.maxSatisfying(eligibleVersions, '*')
1463
- : null
1464
- }
1465
- function findPackageNode(tree, name, version) {
1466
- const queue = [tree]
1467
- let sentinel = 0
1468
- while (queue.length) {
1469
- if (sentinel++ === LOOP_SENTINEL) {
1470
- throw new Error('Detected infinite loop in findPackageNodes')
1471
- }
1472
- const currentNode = queue.pop()
1473
- const node = currentNode.children.get(name)
1474
- if (node && (typeof version !== 'string' || node.version === version)) {
1475
- return node
1476
- }
1477
- const children = [...currentNode.children.values()]
1478
- for (let i = children.length - 1; i >= 0; i -= 1) {
1479
- queue.push(children[i])
1480
- }
1481
- }
1482
- }
1483
- function findPackageNodes(tree, name, version) {
1484
- const queue = [tree]
1485
- const matches = []
1486
- let sentinel = 0
1487
- while (queue.length) {
1488
- if (sentinel++ === LOOP_SENTINEL) {
1489
- throw new Error('Detected infinite loop in findPackageNodes')
1490
- }
1491
- const currentNode = queue.pop()
1492
- const node = currentNode.children.get(name)
1493
- if (node && 'undefined' !== 'string') {
1494
- matches.push(node)
1495
- }
1496
- const children = [...currentNode.children.values()]
1497
- for (let i = children.length - 1; i >= 0; i -= 1) {
1498
- queue.push(children[i])
1499
- }
1500
- }
1501
- return matches
1502
- }
1503
- function getDetailsFromDiff(diff_, options) {
1504
- const details = []
1505
- // `diff_` is `null` when `npm install --package-lock-only` is passed.
1506
- if (!diff_) {
1507
- return details
1508
- }
1509
- const include = {
1510
- __proto__: null,
1511
- unchanged: false,
1512
- unknownOrigin: false,
1513
- ...{
1514
- __proto__: null,
1515
- ...options
1516
- }.include
1517
- }
1518
- const queue = [...diff_.children]
1519
- let pos = 0
1520
- let { length: queueLength } = queue
1521
- while (pos < queueLength) {
1522
- if (pos === LOOP_SENTINEL) {
1523
- throw new Error('Detected infinite loop while walking Arborist diff')
1524
- }
1525
- const diff = queue[pos++]
1526
- const { action } = diff
1527
- if (action) {
1528
- // The `pkgNode`, i.e. the `ideal` node, will be `undefined` if the diff
1529
- // action is 'REMOVE'
1530
- // The `oldNode`, i.e. the `actual` node, will be `undefined` if the diff
1531
- // action is 'ADD'.
1532
- const { actual: oldNode, ideal: pkgNode } = diff
1533
- let existing
1534
- let keep = false
1535
- if (action === DiffAction.change) {
1536
- if (pkgNode?.package.version !== oldNode?.package.version) {
1537
- keep = true
1538
- if (
1539
- oldNode?.package.name &&
1540
- oldNode.package.name === pkgNode?.package.name
1541
- ) {
1542
- existing = oldNode
1543
- }
1544
- } else {
1545
- debug.debugLog('SKIPPING META CHANGE ON\n', diff)
1546
- }
1547
- } else {
1548
- keep = action !== DiffAction.remove
1549
- }
1550
- if (keep && pkgNode?.resolved && (!oldNode || oldNode.resolved)) {
1551
- if (
1552
- include.unknownOrigin ||
1553
- getUrlOrigin(pkgNode.resolved) === NPM_REGISTRY_URL
1554
- ) {
1555
- details.push({
1556
- node: pkgNode,
1557
- existing
1558
- })
1559
- }
1560
- }
1561
- }
1562
- for (const child of diff.children) {
1563
- queue[queueLength++] = child
1564
- }
1565
- }
1566
- if (include.unchanged) {
1567
- const { unchanged } = diff_
1568
- for (let i = 0, { length } = unchanged; i < length; i += 1) {
1569
- const pkgNode = unchanged[i]
1570
- if (
1571
- include.unknownOrigin ||
1572
- getUrlOrigin(pkgNode.resolved) === NPM_REGISTRY_URL
1573
- ) {
1574
- details.push({
1575
- node: pkgNode,
1576
- existing: pkgNode
1577
- })
1578
- }
1579
- }
1580
- }
1581
- return details
1582
- }
1583
- function isTopLevel(tree, node) {
1584
- return tree.children.get(node.name) === node
1585
- }
1586
- function updateNode(
1587
- node,
1588
- packument,
1589
- vulnerableVersionRange,
1590
- firstPatchedVersionIdentifier
1591
- ) {
1592
- const availableVersions = Object.keys(packument.versions)
1593
- // Find the highest non-vulnerable version within the same major range
1594
- const targetVersion = findBestPatchVersion(
1595
- node,
1596
- availableVersions,
1597
- vulnerableVersionRange
1598
- )
1599
- const targetPackument = targetVersion
1600
- ? packument.versions[targetVersion]
1601
- : undefined
1602
- // Check !targetVersion to make TypeScript happy.
1603
- if (!targetVersion || !targetPackument) {
1604
- // No suitable patch version found.
1605
- return false
1606
- }
1607
- // Object.defineProperty is needed to set the version property and replace
1608
- // the old value with targetVersion.
1609
- Object.defineProperty(node, 'version', {
1610
- configurable: true,
1611
- enumerable: true,
1612
- get: () => targetVersion
1613
- })
1614
- // Update package.version associated with the node.
1615
- node.package.version = targetVersion
1616
- // Update node.resolved.
1617
- const purlObj = packageurlJs.PackageURL.fromString(`pkg:npm/${node.name}`)
1618
- node.resolved = `${NPM_REGISTRY_URL}/${node.name}/-/${purlObj.name}-${targetVersion}.tgz`
1619
- // Update node.integrity with the targetPackument.dist.integrity value if available
1620
- // else delete node.integrity so a new value is resolved for the target version.
1621
- const { integrity } = targetPackument.dist
1622
- if (integrity) {
1623
- node.integrity = integrity
1624
- } else {
1625
- delete node.integrity
1626
- }
1627
- // Update node.package.deprecated based on targetPackument.deprecated.
1628
- if (objects.hasOwn(targetPackument, 'deprecated')) {
1629
- node.package['deprecated'] = targetPackument.deprecated
1630
- } else {
1631
- delete node.package['deprecated']
1632
- }
1633
- // Update node.package.dependencies.
1634
- const newDeps = {
1635
- ...targetPackument.dependencies
1636
- }
1637
- const { dependencies: oldDeps } = node.package
1638
- node.package.dependencies = newDeps
1639
- if (oldDeps) {
1640
- for (const oldDepName of Object.keys(oldDeps)) {
1641
- if (!objects.hasOwn(newDeps, oldDepName)) {
1642
- // Detach old edges for dependencies that don't exist on the updated
1643
- // node.package.dependencies.
1644
- node.edgesOut.get(oldDepName)?.detach()
1645
- }
1646
- }
1647
- }
1648
- for (const newDepName of Object.keys(newDeps)) {
1649
- if (!objects.hasOwn(oldDeps, newDepName)) {
1650
- // Add new edges for dependencies that don't exist on the old
1651
- // node.package.dependencies.
1652
- node.addEdgeOut(
1653
- new Edge({
1654
- from: node,
1655
- name: newDepName,
1656
- spec: newDeps[newDepName],
1657
- type: 'prod'
1658
- })
1659
- )
1660
- }
1661
- }
1662
- return true
1663
- }
1664
- function updatePackageJsonFromNode(
1665
- editablePkgJson,
1666
- tree,
1667
- node,
1668
- targetVersion,
1669
- rangeStyle
1670
- ) {
1671
- let result = false
1672
- if (!isTopLevel(tree, node)) {
1673
- return result
1674
- }
1675
- const { name } = node
1676
- for (const depField of [
1677
- 'dependencies',
1678
- 'optionalDependencies',
1679
- 'peerDependencies'
1680
- ]) {
1681
- const depObject = editablePkgJson.content[depField]
1682
- if (depObject) {
1683
- const oldRange = depObject[name]
1684
- if (oldRange) {
1685
- const newRange = applyRange(oldRange, targetVersion, rangeStyle)
1686
- if (oldRange !== newRange) {
1687
- result = true
1688
- editablePkgJson.update({
1689
- [depField]: {
1690
- ...depObject,
1691
- [name]: newRange
1692
- }
1693
- })
1694
- }
1695
- }
1696
- }
1697
- }
1698
- return result
1699
- }
1700
-
1701
- const {
1702
- ALERT_TYPE_CRITICAL_CVE,
1703
- ALERT_TYPE_CVE,
1704
- ALERT_TYPE_MEDIUM_CVE,
1705
- ALERT_TYPE_MILD_CVE
1706
- } = constants
1707
- function isArtifactAlertCve(alert) {
1708
- const { type } = alert
1709
- return (
1710
- type === ALERT_TYPE_CVE ||
1711
- type === ALERT_TYPE_MEDIUM_CVE ||
1712
- type === ALERT_TYPE_MILD_CVE ||
1713
- type === ALERT_TYPE_CRITICAL_CVE
1714
- )
1715
- }
1716
-
1717
- const ALERT_FIX_TYPE = /*#__PURE__*/ (function (ALERT_FIX_TYPE) {
1718
- ALERT_FIX_TYPE['cve'] = 'cve'
1719
- ALERT_FIX_TYPE['upgrade'] = 'upgrade'
1720
- return ALERT_FIX_TYPE
1721
- })({})
1722
-
1723
- function pick(input, keys) {
1724
- const result = {}
1725
- for (const key of keys) {
1726
- result[key] = input[key]
1727
- }
1728
- return result
1729
- }
1730
-
1731
- function stringJoinWithSeparateFinalSeparator(list, separator = ' and ') {
1732
- const values = list.filter(Boolean)
1733
- const { length } = values
1734
- if (!length) {
1735
- return ''
1736
- }
1737
- if (length === 1) {
1738
- return values[0]
1739
- }
1740
- const finalValue = values.pop()
1741
- return `${values.join(', ')}${separator}${finalValue}`
1742
- }
1743
-
1744
- const ALERT_SEVERITY = /*#__PURE__*/ (function (ALERT_SEVERITY) {
1745
- ALERT_SEVERITY['critical'] = 'critical'
1746
- ALERT_SEVERITY['high'] = 'high'
1747
- ALERT_SEVERITY['middle'] = 'middle'
1748
- ALERT_SEVERITY['low'] = 'low'
1749
- return ALERT_SEVERITY
1750
- })({})
1751
- // Ordered from most severe to least.
1752
- const ALERT_SEVERITIES_SORTED = Object.freeze([
1753
- 'critical',
1754
- 'high',
1755
- 'middle',
1756
- 'low'
1757
- ])
1758
- function getDesiredSeverities(lowestToInclude) {
1759
- const result = []
1760
- for (const severity of ALERT_SEVERITIES_SORTED) {
1761
- result.push(severity)
1762
- if (severity === lowestToInclude) {
1763
- break
1764
- }
1765
- }
1766
- return result
1767
- }
1768
- function formatSeverityCount(severityCount) {
1769
- const summary = []
1770
- for (const severity of ALERT_SEVERITIES_SORTED) {
1771
- if (severityCount[severity]) {
1772
- summary.push(`${severityCount[severity]} ${severity}`)
1773
- }
1774
- }
1775
- return stringJoinWithSeparateFinalSeparator(summary)
1776
- }
1777
- function getSeverityCount(issues, lowestToInclude) {
1778
- const severityCount = pick(
1779
- {
1780
- low: 0,
1781
- middle: 0,
1782
- high: 0,
1783
- critical: 0
1784
- },
1785
- getDesiredSeverities(lowestToInclude)
1786
- )
1787
- for (const issue of issues) {
1788
- const { value } = issue
1789
- if (!value) {
1790
- continue
1791
- }
1792
- const { severity } = value
1793
- if (severityCount[severity] !== undefined) {
1794
- severityCount[severity] += 1
1795
- }
1796
- }
1797
- return severityCount
1798
- }
1799
-
1800
- class ColorOrMarkdown {
1801
- constructor(useMarkdown) {
1802
- this.useMarkdown = !!useMarkdown
1803
- }
1804
- bold(text) {
1805
- return this.useMarkdown
1806
- ? `**${text}**`
1807
- : vendor.yoctocolorsCjsExports.bold(`${text}`)
1808
- }
1809
- header(text, level = 1) {
1810
- return this.useMarkdown
1811
- ? `\n${''.padStart(level, '#')} ${text}\n`
1812
- : vendor.yoctocolorsCjsExports.underline(
1813
- `\n${level === 1 ? vendor.yoctocolorsCjsExports.bold(text) : text}\n`
1814
- )
1815
- }
1816
- hyperlink(text, url, { fallback = true, fallbackToUrl } = {}) {
1817
- if (url) {
1818
- return this.useMarkdown
1819
- ? `[${text}](${url})`
1820
- : vendor.terminalLinkExports(text, url, {
1821
- fallback: fallbackToUrl ? (_text, url) => url : fallback
1822
- })
1823
- }
1824
- return text
1825
- }
1826
- indent(...args) {
1827
- return indentString(...args)
1828
- }
1829
- italic(text) {
1830
- return this.useMarkdown
1831
- ? `_${text}_`
1832
- : vendor.yoctocolorsCjsExports.italic(`${text}`)
1833
- }
1834
- json(value) {
1835
- return this.useMarkdown
1836
- ? '```json\n' + JSON.stringify(value) + '\n```'
1837
- : JSON.stringify(value)
1838
- }
1839
- list(items) {
1840
- const indentedContent = items.map(item => this.indent(item).trimStart())
1841
- return this.useMarkdown
1842
- ? `* ${indentedContent.join('\n* ')}\n`
1843
- : `${indentedContent.join('\n')}\n`
1844
- }
1845
- }
1846
-
1847
- function getSocketDevAlertUrl(alertType) {
1848
- return `https://socket.dev/alerts/${alertType}`
1849
- }
1850
- function getSocketDevPackageOverviewUrl(eco, name, version) {
1851
- return `https://socket.dev/${eco}/package/${name}${version ? `/overview/${version}` : ''}`
1852
- }
1853
-
1854
- let _translations
1855
- function getTranslations() {
1856
- if (_translations === undefined) {
1857
- _translations = require(
1858
- // Lazily access constants.rootPath.
1859
- path.join(constants.rootPath, 'translations.json')
1860
- )
1861
- }
1862
- return _translations
1863
- }
1864
-
1865
- const ALERT_SEVERITY_COLOR = /*#__PURE__*/ (function (ALERT_SEVERITY_COLOR) {
1866
- ALERT_SEVERITY_COLOR['critical'] = 'magenta'
1867
- ALERT_SEVERITY_COLOR['high'] = 'red'
1868
- ALERT_SEVERITY_COLOR['middle'] = 'yellow'
1869
- ALERT_SEVERITY_COLOR['low'] = 'white'
1870
- return ALERT_SEVERITY_COLOR
1871
- })({})
1872
- const ALERT_SEVERITY_ORDER = /*#__PURE__*/ (function (ALERT_SEVERITY_ORDER) {
1873
- ALERT_SEVERITY_ORDER[(ALERT_SEVERITY_ORDER['critical'] = 0)] = 'critical'
1874
- ALERT_SEVERITY_ORDER[(ALERT_SEVERITY_ORDER['high'] = 1)] = 'high'
1875
- ALERT_SEVERITY_ORDER[(ALERT_SEVERITY_ORDER['middle'] = 2)] = 'middle'
1876
- ALERT_SEVERITY_ORDER[(ALERT_SEVERITY_ORDER['low'] = 3)] = 'low'
1877
- ALERT_SEVERITY_ORDER[(ALERT_SEVERITY_ORDER['none'] = 4)] = 'none'
1878
- return ALERT_SEVERITY_ORDER
1879
- })({})
1880
- const { CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER, NPM: NPM$1 } =
1881
- constants
1882
- const MIN_ABOVE_THE_FOLD_COUNT = 3
1883
- const MIN_ABOVE_THE_FOLD_ALERT_COUNT = 1
1884
- const format = new ColorOrMarkdown(false)
1885
- function alertsHaveBlocked(alerts) {
1886
- return alerts.find(a => a.blocked) !== undefined
1887
- }
1888
- function alertsHaveSeverity(alerts, severity) {
1889
- return alerts.find(a => a.raw.severity === severity) !== undefined
1890
- }
1891
- function alertSeverityComparator(a, b) {
1892
- return getAlertSeverityOrder(a) - getAlertSeverityOrder(b)
1893
- }
1894
- function getAlertSeverityOrder(alert) {
1895
- const { severity } = alert.raw
1896
- return severity === ALERT_SEVERITY.critical
1897
- ? 0
1898
- : severity === ALERT_SEVERITY.high
1899
- ? 1
1900
- : severity === ALERT_SEVERITY.middle
1901
- ? 2
1902
- : severity === ALERT_SEVERITY.low
1903
- ? 3
1904
- : 4
1905
- }
1906
- function getAlertsSeverityOrder(alerts) {
1907
- return alertsHaveBlocked(alerts) ||
1908
- alertsHaveSeverity(alerts, ALERT_SEVERITY.critical)
1909
- ? 0
1910
- : alertsHaveSeverity(alerts, ALERT_SEVERITY.high)
1911
- ? 1
1912
- : alertsHaveSeverity(alerts, ALERT_SEVERITY.middle)
1913
- ? 2
1914
- : alertsHaveSeverity(alerts, ALERT_SEVERITY.low)
1915
- ? 3
1916
- : 4
1917
- }
1918
- function getHiddenRiskCounts(hiddenAlerts) {
1919
- const riskCounts = {
1920
- critical: 0,
1921
- high: 0,
1922
- middle: 0,
1923
- low: 0
1924
- }
1925
- for (const alert of hiddenAlerts) {
1926
- switch (getAlertSeverityOrder(alert)) {
1927
- case ALERT_SEVERITY_ORDER.critical:
1928
- riskCounts.critical += 1
1929
- break
1930
- case ALERT_SEVERITY_ORDER.high:
1931
- riskCounts.high += 1
1932
- break
1933
- case ALERT_SEVERITY_ORDER.middle:
1934
- riskCounts.middle += 1
1935
- break
1936
- case ALERT_SEVERITY_ORDER.low:
1937
- riskCounts.low += 1
1938
- break
1939
- }
1940
- }
1941
- return riskCounts
1942
- }
1943
- function getHiddenRisksDescription(riskCounts) {
1944
- const descriptions = []
1945
- if (riskCounts.critical) {
1946
- descriptions.push(`${riskCounts.critical} ${getSeverityLabel('critical')}`)
1947
- }
1948
- if (riskCounts.high) {
1949
- descriptions.push(`${riskCounts.high} ${getSeverityLabel('high')}`)
1950
- }
1951
- if (riskCounts.middle) {
1952
- descriptions.push(`${riskCounts.middle} ${getSeverityLabel('middle')}`)
1953
- }
1954
- if (riskCounts.low) {
1955
- descriptions.push(`${riskCounts.low} ${getSeverityLabel('low')}`)
1956
- }
1957
- return `(${descriptions.join('; ')})`
1958
- }
1959
- function getSeverityLabel(severity) {
1960
- return severity === 'middle' ? 'moderate' : severity
1961
- }
1962
- async function addArtifactToAlertsMap(artifact, alertsByPkgId, options) {
1963
- // Make TypeScript happy.
1964
- if (!artifact.name || !artifact.version || !artifact.alerts?.length) {
1965
- return alertsByPkgId
1966
- }
1967
- const {
1968
- consolidate = false,
1969
- include: _include,
1970
- overrides
1971
- } = {
1972
- __proto__: null,
1973
- ...options
1974
- }
1975
- const include = {
1976
- __proto__: null,
1977
- blocked: true,
1978
- critical: true,
1979
- cve: true,
1980
- unfixable: true,
1981
- upgradable: false,
1982
- ..._include
1983
- }
1984
- const name = packages.resolvePackageName(artifact)
1985
- const { version } = artifact
1986
- const pkgId = `${name}@${version}`
1987
- const major = vendor.semverExports.major(version)
1988
- const socketYml = findSocketYmlSync()
1989
- const enabledState = {
1990
- __proto__: null,
1991
- ...socketYml?.parsed.issueRules
1992
- }
1993
- let sockPkgAlerts = []
1994
- for (const alert of artifact.alerts) {
1995
- const action = alert.action ?? ''
1996
- const enabledFlag = enabledState[alert.type]
1997
- if (
1998
- (action === 'ignore' && enabledFlag !== true) ||
1999
- enabledFlag === false
2000
- ) {
2001
- continue
2002
- }
2003
- const blocked = action === 'error'
2004
- const critical = alert.severity === ALERT_SEVERITY.critical
2005
- const cve = isArtifactAlertCve(alert)
2006
- const fixType = alert.fix?.type ?? ''
2007
- const fixableCve = fixType === ALERT_FIX_TYPE.cve
2008
- const fixableUpgrade = fixType === ALERT_FIX_TYPE.upgrade
2009
- const fixable = fixableCve || fixableUpgrade
2010
- const upgradable = fixableUpgrade && !objects.hasOwn(overrides, name)
2011
- if (
2012
- (include.blocked && blocked) ||
2013
- (include.critical && critical) ||
2014
- (include.cve && cve) ||
2015
- (include.unfixable && !fixable) ||
2016
- (include.upgradable && upgradable)
2017
- ) {
2018
- sockPkgAlerts.push({
2019
- name,
2020
- version,
2021
- key: alert.key,
2022
- type: alert.type,
2023
- blocked,
2024
- critical,
2025
- fixable,
2026
- raw: alert,
2027
- upgradable
2028
- })
2029
- }
2030
- }
2031
- if (!sockPkgAlerts.length) {
2032
- return alertsByPkgId
2033
- }
2034
- if (consolidate) {
2035
- const highestForCve = new Map()
2036
- const highestForUpgrade = new Map()
2037
- const unfixableAlerts = []
2038
- for (const sockPkgAlert of sockPkgAlerts) {
2039
- const alert = sockPkgAlert.raw
2040
- const fixType = alert.fix?.type ?? ''
2041
- if (fixType === ALERT_FIX_TYPE.cve) {
2042
- const patchedVersion =
2043
- alert.props[CVE_ALERT_PROPS_FIRST_PATCHED_VERSION_IDENTIFIER]
2044
- const patchedMajor = vendor.semverExports.major(patchedVersion)
2045
- const oldHighest = highestForCve.get(patchedMajor)
2046
- const highest = oldHighest?.version ?? '0.0.0'
2047
- if (vendor.semverExports.gt(patchedVersion, highest)) {
2048
- highestForCve.set(patchedMajor, {
2049
- alert: sockPkgAlert,
2050
- version: patchedVersion
2051
- })
2052
- }
2053
- } else if (fixType === ALERT_FIX_TYPE.upgrade) {
2054
- const oldHighest = highestForUpgrade.get(major)
2055
- const highest = oldHighest?.version ?? '0.0.0'
2056
- if (vendor.semverExports.gt(version, highest)) {
2057
- highestForUpgrade.set(major, {
2058
- alert: sockPkgAlert,
2059
- version
2060
- })
2061
- }
2062
- } else {
2063
- unfixableAlerts.push(sockPkgAlert)
2064
- }
2065
- }
2066
- sockPkgAlerts = [
2067
- ...unfixableAlerts,
2068
- ...[...highestForCve.values()].map(d => d.alert),
2069
- ...[...highestForUpgrade.values()].map(d => d.alert)
2070
- ]
2071
- }
2072
- if (sockPkgAlerts.length) {
2073
- sockPkgAlerts.sort((a, b) => sorts.naturalCompare(a.type, b.type))
2074
- alertsByPkgId.set(pkgId, sockPkgAlerts)
2075
- }
2076
- return alertsByPkgId
2077
- }
2078
- function getCveInfoByAlertsMap(alertsMap, options) {
2079
- const exclude = {
2080
- upgradable: true,
2081
- ...{
2082
- __proto__: null,
2083
- ...options
2084
- }.exclude
2085
- }
2086
- let infoByPkg = null
2087
- for (const [pkgId, sockPkgAlerts] of alertsMap) {
2088
- const purlObj = packageurlJs.PackageURL.fromString(`pkg:npm/${pkgId}`)
2089
- const name = packages.resolvePackageName(purlObj)
2090
- for (const sockPkgAlert of sockPkgAlerts) {
2091
- const alert = sockPkgAlert.raw
2092
- if (
2093
- alert.fix?.type !== ALERT_FIX_TYPE.cve ||
2094
- (exclude.upgradable && registry.getManifestData(NPM$1, name))
2095
- ) {
2096
- continue
2097
- }
2098
- if (!infoByPkg) {
2099
- infoByPkg = new Map()
2100
- }
2101
- let infos = infoByPkg.get(name)
2102
- if (!infos) {
2103
- infos = []
2104
- infoByPkg.set(name, infos)
2105
- }
2106
- const { firstPatchedVersionIdentifier, vulnerableVersionRange } =
2107
- alert.props
2108
- infos.push({
2109
- firstPatchedVersionIdentifier,
2110
- vulnerableVersionRange: new vendor.semverExports.Range(
2111
- vulnerableVersionRange
2112
- ).format()
2113
- })
2114
- }
2115
- }
2116
- return infoByPkg
2117
- }
2118
- function logAlertsMap(alertsMap, options) {
2119
- const { hideAt = 'middle', output = process.stderr } = {
2120
- __proto__: null,
2121
- ...options
2122
- }
2123
- const translations = getTranslations()
2124
- const sortedEntries = [...alertsMap.entries()].sort(
2125
- (a, b) => getAlertsSeverityOrder(a[1]) - getAlertsSeverityOrder(b[1])
2126
- )
2127
- const aboveTheFoldPkgIds = new Set()
2128
- const viewableAlertsByPkgId = new Map()
2129
- const hiddenAlertsByPkgId = new Map()
2130
- for (let i = 0, { length } = sortedEntries; i < length; i += 1) {
2131
- const { 0: pkgId, 1: alerts } = sortedEntries[i]
2132
- const hiddenAlerts = []
2133
- const viewableAlerts = alerts.filter(a => {
2134
- const keep =
2135
- a.blocked || getAlertSeverityOrder(a) < ALERT_SEVERITY_ORDER[hideAt]
2136
- if (!keep) {
2137
- hiddenAlerts.push(a)
2138
- }
2139
- return keep
2140
- })
2141
- if (hiddenAlerts.length) {
2142
- hiddenAlertsByPkgId.set(pkgId, hiddenAlerts.sort(alertSeverityComparator))
2143
- }
2144
- if (!viewableAlerts.length) {
2145
- continue
2146
- }
2147
- viewableAlerts.sort(alertSeverityComparator)
2148
- viewableAlertsByPkgId.set(pkgId, viewableAlerts)
2149
- if (
2150
- viewableAlerts.find(
2151
- a => a.blocked || getAlertSeverityOrder(a) < ALERT_SEVERITY_ORDER.middle
2152
- )
2153
- ) {
2154
- aboveTheFoldPkgIds.add(pkgId)
2155
- }
2156
- }
2157
-
2158
- // If MIN_ABOVE_THE_FOLD_COUNT is NOT met add more from viewable pkg ids.
2159
- for (const { 0: pkgId } of viewableAlertsByPkgId.entries()) {
2160
- if (aboveTheFoldPkgIds.size >= MIN_ABOVE_THE_FOLD_COUNT) {
2161
- break
2162
- }
2163
- aboveTheFoldPkgIds.add(pkgId)
2164
- }
2165
- // If MIN_ABOVE_THE_FOLD_COUNT is STILL NOT met add more from hidden pkg ids.
2166
- for (const { 0: pkgId, 1: hiddenAlerts } of hiddenAlertsByPkgId.entries()) {
2167
- if (aboveTheFoldPkgIds.size >= MIN_ABOVE_THE_FOLD_COUNT) {
2168
- break
2169
- }
2170
- aboveTheFoldPkgIds.add(pkgId)
2171
- const viewableAlerts = viewableAlertsByPkgId.get(pkgId) ?? []
2172
- if (viewableAlerts.length < MIN_ABOVE_THE_FOLD_ALERT_COUNT) {
2173
- const neededCount = MIN_ABOVE_THE_FOLD_ALERT_COUNT - viewableAlerts.length
2174
- let removedHiddenAlerts
2175
- if (hiddenAlerts.length - neededCount > 0) {
2176
- removedHiddenAlerts = hiddenAlerts.splice(
2177
- 0,
2178
- MIN_ABOVE_THE_FOLD_ALERT_COUNT
2179
- )
2180
- } else {
2181
- removedHiddenAlerts = hiddenAlerts
2182
- hiddenAlertsByPkgId.delete(pkgId)
2183
- }
2184
- viewableAlertsByPkgId.set(pkgId, [
2185
- ...viewableAlerts,
2186
- ...removedHiddenAlerts
2187
- ])
2188
- }
2189
- }
2190
- const mentionedPkgIdsWithHiddenAlerts = new Set()
2191
- for (
2192
- let i = 0,
2193
- prevAboveTheFold = true,
2194
- entries = [...viewableAlertsByPkgId.entries()],
2195
- { length } = entries;
2196
- i < length;
2197
- i += 1
2198
- ) {
2199
- const { 0: pkgId, 1: alerts } = entries[i]
2200
- const lines = new Set()
2201
- for (const alert of alerts) {
2202
- const { type } = alert
2203
- const severity = alert.raw.severity ?? ''
2204
- const attributes = [
2205
- ...(severity
2206
- ? [
2207
- vendor.yoctocolorsCjsExports[ALERT_SEVERITY_COLOR[severity]](
2208
- getSeverityLabel(severity)
2209
- )
2210
- ]
2211
- : []),
2212
- ...(alert.blocked
2213
- ? [
2214
- vendor.yoctocolorsCjsExports.bold(
2215
- vendor.yoctocolorsCjsExports.red('blocked')
2216
- )
2217
- ]
2218
- : []),
2219
- ...(alert.fixable ? ['fixable'] : [])
2220
- ]
2221
- const maybeAttributes = attributes.length
2222
- ? ` ${vendor.yoctocolorsCjsExports.italic(`(${attributes.join('; ')})`)}`
2223
- : ''
2224
- // Based data from { pageProps: { alertTypes } } of:
2225
- // https://socket.dev/_next/data/94666139314b6437ee4491a0864e72b264547585/en-US.json
2226
- const info = translations.alerts[type]
2227
- const title = info?.title ?? type
2228
- const maybeDesc = info?.description ? ` - ${info.description}` : ''
2229
- const content = `${title}${maybeAttributes}${maybeDesc}`
2230
- // TODO: emoji seems to mis-align terminals sometimes
2231
- lines.add(` ${content}`)
2232
- }
2233
- const purlObj = packageurlJs.PackageURL.fromString(`pkg:npm/${pkgId}`)
2234
- const hyperlink = format.hyperlink(
2235
- pkgId,
2236
- getSocketDevPackageOverviewUrl(
2237
- NPM$1,
2238
- packages.resolvePackageName(purlObj),
2239
- purlObj.version
2240
- )
2241
- )
2242
- const isAboveTheFold = aboveTheFoldPkgIds.has(pkgId)
2243
- if (isAboveTheFold) {
2244
- aboveTheFoldPkgIds.add(pkgId)
2245
- output.write(`${i ? '\n' : ''}${hyperlink}:\n`)
2246
- } else {
2247
- output.write(`${prevAboveTheFold ? '\n' : ''}${hyperlink}:\n`)
2248
- }
2249
- for (const line of lines) {
2250
- output.write(`${line}\n`)
2251
- }
2252
- const hiddenAlerts = hiddenAlertsByPkgId.get(pkgId) ?? []
2253
- const { length: hiddenAlertsCount } = hiddenAlerts
2254
- if (hiddenAlertsCount) {
2255
- mentionedPkgIdsWithHiddenAlerts.add(pkgId)
2256
- if (hiddenAlertsCount === 1) {
2257
- output.write(
2258
- ` ${vendor.yoctocolorsCjsExports.dim(`+1 Hidden ${getSeverityLabel(hiddenAlerts[0].raw.severity ?? 'low')} risk alert`)}\n`
2259
- )
2260
- } else {
2261
- output.write(
2262
- ` ${vendor.yoctocolorsCjsExports.dim(`+${hiddenAlertsCount} Hidden alerts ${vendor.yoctocolorsCjsExports.italic(getHiddenRisksDescription(getHiddenRiskCounts(hiddenAlerts)))}`)}\n`
2263
- )
2264
- }
2265
- }
2266
- prevAboveTheFold = isAboveTheFold
2267
- }
2268
- const additionalHiddenCount =
2269
- hiddenAlertsByPkgId.size - mentionedPkgIdsWithHiddenAlerts.size
2270
- if (additionalHiddenCount) {
2271
- const totalRiskCounts = {
2272
- critical: 0,
2273
- high: 0,
2274
- middle: 0,
2275
- low: 0
2276
- }
2277
- for (const { 0: pkgId, 1: alerts } of hiddenAlertsByPkgId.entries()) {
2278
- if (mentionedPkgIdsWithHiddenAlerts.has(pkgId)) {
2279
- continue
2280
- }
2281
- const riskCounts = getHiddenRiskCounts(alerts)
2282
- totalRiskCounts.critical += riskCounts.critical
2283
- totalRiskCounts.high += riskCounts.high
2284
- totalRiskCounts.middle += riskCounts.middle
2285
- totalRiskCounts.low += riskCounts.low
2286
- }
2287
- output.write(
2288
- `${aboveTheFoldPkgIds.size ? '\n' : ''}${vendor.yoctocolorsCjsExports.dim(`${aboveTheFoldPkgIds.size ? '+' : ''}${additionalHiddenCount} Packages with hidden alerts ${vendor.yoctocolorsCjsExports.italic(getHiddenRisksDescription(totalRiskCounts))}`)}\n`
2289
- )
2290
- }
2291
- output.write('\n')
2292
- }
2293
-
2294
- async function getAlertsMapFromArborist(arb, options_) {
2295
- const options = {
2296
- __proto__: null,
2297
- consolidate: false,
2298
- nothrow: false,
2299
- ...options_
2300
- }
2301
- const include = {
2302
- __proto__: null,
2303
- existing: false,
2304
- ...options.include
2305
- }
2306
- const needInfoOn = getDetailsFromDiff(arb.diff, {
2307
- include: {
2308
- unchanged: include.existing
2309
- }
2310
- })
2311
- const purls = needInfoOn.map(d => `pkg:npm/${d.node.pkgid}`)
2312
- let overrides
2313
- const overridesMap = (
2314
- arb.actualTree ??
2315
- arb.idealTree ??
2316
- (await arb.loadActual())
2317
- )?.overrides?.children
2318
- if (overridesMap) {
2319
- overrides = Object.fromEntries(
2320
- [...overridesMap.entries()].map(([key, overrideSet]) => {
2321
- return [key, overrideSet.value]
2322
- })
2323
- )
2324
- }
2325
- return await getAlertsMapFromPurls(purls, {
2326
- overrides,
2327
- ...options
2328
- })
2329
- }
2330
- async function getAlertsMapFromPnpmLockfile(lockfile, options_) {
2331
- const options = {
2332
- __proto__: null,
2333
- consolidate: false,
2334
- nothrow: false,
2335
- ...options_
2336
- }
2337
- const depTypes = vendor.libExports$1.detectDepTypes(lockfile)
2338
- const purls = Object.keys(depTypes).map(id => `pkg:npm/${id}`)
2339
- return await getAlertsMapFromPurls(purls, {
2340
- overrides: lockfile.overrides,
2341
- ...options
2342
- })
2343
- }
2344
- async function getAlertsMapFromPurls(purls, options_) {
2345
- const options = {
2346
- __proto__: null,
2347
- consolidate: false,
2348
- nothrow: false,
2349
- ...options_
2350
- }
2351
- const include = {
2352
- __proto__: null,
2353
- actions: undefined,
2354
- blocked: true,
2355
- critical: true,
2356
- cve: true,
2357
- existing: false,
2358
- unfixable: true,
2359
- upgradable: false,
2360
- ...options.include
2361
- }
2362
- const { spinner } = options
2363
- const uniqPurls = arrays.arrayUnique(purls)
2364
- let { length: remaining } = uniqPurls
2365
- const alertsByPkgId = new Map()
2366
- if (!remaining) {
2367
- return alertsByPkgId
2368
- }
2369
- const getText = () => `Looking up data for ${remaining} packages`
2370
- spinner?.start(getText())
2371
- const sockSdk = await setupSdk(getPublicToken())
2372
- const toAlertsMapOptions = {
2373
- overrides: options.overrides,
2374
- consolidate: options.consolidate,
2375
- include,
2376
- spinner
2377
- }
2378
- for await (const batchResult of sockSdk.batchPackageStream(
2379
- {
2380
- alerts: 'true',
2381
- compact: 'true',
2382
- ...(include.actions
2383
- ? {
2384
- actions: include.actions.join(',')
2385
- }
2386
- : {}),
2387
- ...(include.unfixable
2388
- ? {}
2389
- : {
2390
- fixable: 'true'
2391
- })
2392
- },
2393
- {
2394
- components: uniqPurls.map(purl => ({
2395
- purl
2396
- }))
2397
- }
2398
- )) {
2399
- if (batchResult.success) {
2400
- await addArtifactToAlertsMap(
2401
- batchResult.data,
2402
- alertsByPkgId,
2403
- toAlertsMapOptions
2404
- )
2405
- } else if (!options.nothrow) {
2406
- const statusCode = batchResult.status ?? 'unknown'
2407
- const statusMessage = batchResult.error ?? 'No status message'
2408
- throw new Error(
2409
- `Socket API server error (${statusCode}): ${statusMessage}`
2410
- )
2411
- }
2412
- remaining -= 1
2413
- if (spinner && remaining > 0) {
2414
- spinner.start()
2415
- spinner.setText(getText())
2416
- }
2417
- }
2418
- spinner?.stop()
2419
- return alertsByPkgId
2420
- }
2421
-
2422
- const {
2423
- NPM,
2424
- NPX,
2425
- SOCKET_CLI_ACCEPT_RISKS,
2426
- SOCKET_CLI_SAFE_BIN,
2427
- SOCKET_CLI_SAFE_PROGRESS,
2428
- SOCKET_CLI_VIEW_ALL_RISKS,
2429
- kInternalsSymbol,
2430
- [kInternalsSymbol]: { getIpc }
2431
- } = constants
2432
- const SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES = {
2433
- __proto__: null,
2434
- audit: false,
2435
- dryRun: true,
2436
- fund: false,
2437
- ignoreScripts: true,
2438
- progress: false,
2439
- save: false,
2440
- saveBundle: false,
2441
- silent: true
2442
- }
2443
- const kCtorArgs = Symbol('ctorArgs')
2444
- const kRiskyReify = Symbol('riskyReify')
2445
- const Arborist = require(shadowNpmPaths.getArboristClassPath())
2446
-
2447
- // Implementation code not related to our custom behavior is based on
2448
- // https://github.com/npm/cli/blob/v11.0.0/workspaces/arborist/lib/arborist/index.js:
2449
- class SafeArborist extends Arborist {
2450
- constructor(...ctorArgs) {
2451
- super(
2452
- {
2453
- path:
2454
- (ctorArgs.length ? ctorArgs[0]?.path : undefined) ?? process$1.cwd(),
2455
- ...(ctorArgs.length ? ctorArgs[0] : undefined),
2456
- ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
2457
- },
2458
- ...ctorArgs.slice(1)
2459
- )
2460
- this[kCtorArgs] = ctorArgs
2461
- }
2462
- async [kRiskyReify](...args) {
2463
- const ctorArgs = this[kCtorArgs]
2464
- const arb = new Arborist(
2465
- {
2466
- ...(ctorArgs.length ? ctorArgs[0] : undefined),
2467
- progress: false
2468
- },
2469
- ...ctorArgs.slice(1)
2470
- )
2471
- const ret = await arb.reify(
2472
- {
2473
- ...(args.length ? args[0] : undefined),
2474
- progress: false
2475
- },
2476
- ...args.slice(1)
2477
- )
2478
- Object.assign(this, arb)
2479
- return ret
2480
- }
2481
-
2482
- // @ts-ignore Incorrectly typed.
2483
- async reify(...args) {
2484
- const options = {
2485
- __proto__: null,
2486
- ...(args.length ? args[0] : undefined)
2487
- }
2488
- const ipc = await getIpc()
2489
- const binName = ipc[SOCKET_CLI_SAFE_BIN]
2490
- if (!binName) {
2491
- return await this[kRiskyReify](...args)
2492
- }
2493
- await super.reify(
2494
- {
2495
- ...options,
2496
- ...SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES,
2497
- progress: false
2498
- },
2499
- // @ts-ignore: TypeScript gets grumpy about rest parameters.
2500
- ...args.slice(1)
2501
- )
2502
- // Lazily access constants.ENV[SOCKET_CLI_ACCEPT_RISKS].
2503
- const acceptRisks = constants.ENV[SOCKET_CLI_ACCEPT_RISKS]
2504
- // Lazily access constants.ENV[SOCKET_CLI_VIEW_ALL_RISKS].
2505
- const viewAllRisks = constants.ENV[SOCKET_CLI_VIEW_ALL_RISKS]
2506
- const progress = ipc[SOCKET_CLI_SAFE_PROGRESS]
2507
- const spinner =
2508
- options['silent'] || !progress
2509
- ? undefined
2510
- : // Lazily access constants.spinner.
2511
- constants.spinner
2512
- const isSafeNpm = binName === NPM
2513
- const isSafeNpx = binName === NPX
2514
- const alertsMap = await getAlertsMapFromArborist(this, {
2515
- spinner,
2516
- include:
2517
- acceptRisks || options.dryRun || options['yes']
2518
- ? {
2519
- actions: ['error'],
2520
- blocked: true,
2521
- critical: false,
2522
- cve: false,
2523
- existing: true,
2524
- unfixable: false
2525
- }
2526
- : {
2527
- existing: isSafeNpx,
2528
- unfixable: isSafeNpm
2529
- }
2530
- })
2531
- if (alertsMap.size) {
2532
- process$1.exitCode = 1
2533
- logAlertsMap(alertsMap, {
2534
- hideAt: viewAllRisks ? 'none' : 'middle',
2535
- output: process$1.stderr
2536
- })
2537
- throw new Error(vendor.html`
2538
- Socket ${binName} exiting due to risks.${viewAllRisks ? '' : `\nView all risks - Rerun with environment variable ${SOCKET_CLI_VIEW_ALL_RISKS}=1.`}${acceptRisks ? '' : `\nAccept risks - Rerun with environment variable ${SOCKET_CLI_ACCEPT_RISKS}=1.`}
2539
- `)
2540
- } else if (!options['silent']) {
2541
- logger.logger.success(
2542
- `Socket ${binName} ${acceptRisks ? 'accepted' : 'found no'} risks`
2543
- )
2544
- if (binName === NPX) {
2545
- logger.logger.log(`Running ${options.add[0]}`)
2546
- }
2547
- }
2548
- return await this[kRiskyReify](...args)
2549
- }
2550
- }
2551
-
2552
- function installSafeArborist() {
2553
- // Override '@npmcli/arborist' module exports with patched variants based on
2554
- // https://github.com/npm/cli/pull/8089.
2555
- const cache = require.cache
2556
- cache[shadowNpmPaths.getArboristClassPath()] = {
2557
- exports: SafeArborist
2558
- }
2559
- cache[shadowNpmPaths.getArboristEdgeClassPath()] = {
2560
- exports: SafeEdge
2561
- }
2562
- cache[shadowNpmPaths.getArboristNodeClassPath()] = {
2563
- exports: SafeNode
2564
- }
2565
- cache[shadowNpmPaths.getArboristOverrideSetClassPath()] = {
2566
- exports: SafeOverrideSet
2567
- }
2568
- }
2569
-
2570
- installSafeArborist()
2571
-
2572
- exports.ALERT_SEVERITY = ALERT_SEVERITY
2573
- exports.Arborist = Arborist
2574
- exports.AuthError = AuthError
2575
- exports.ColorOrMarkdown = ColorOrMarkdown
2576
- exports.InputError = InputError
2577
- exports.RangeStyles = RangeStyles
2578
- exports.SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES =
2579
- SAFE_ARBORIST_REIFY_OPTIONS_OVERRIDES
2580
- exports.SafeArborist = SafeArborist
2581
- exports.applyRange = applyRange
2582
- exports.captureException = captureException
2583
- exports.filterGlobResultToSupportedFiles = filterGlobResultToSupportedFiles
2584
- exports.findBestPatchVersion = findBestPatchVersion
2585
- exports.findPackageNode = findPackageNode
2586
- exports.findPackageNodes = findPackageNodes
2587
- exports.findUp = findUp
2588
- exports.formatSeverityCount = formatSeverityCount
2589
- exports.getAlertsMapFromArborist = getAlertsMapFromArborist
2590
- exports.getAlertsMapFromPnpmLockfile = getAlertsMapFromPnpmLockfile
2591
- exports.getAlertsMapFromPurls = getAlertsMapFromPurls
2592
- exports.getConfigValue = getConfigValue
2593
- exports.getCveInfoByAlertsMap = getCveInfoByAlertsMap
2594
- exports.getDefaultToken = getDefaultToken
2595
- exports.getPublicToken = getPublicToken
2596
- exports.getSeverityCount = getSeverityCount
2597
- exports.getSocketDevAlertUrl = getSocketDevAlertUrl
2598
- exports.getSocketDevPackageOverviewUrl = getSocketDevPackageOverviewUrl
2599
- exports.globWithGitIgnore = globWithGitIgnore
2600
- exports.globWorkspace = globWorkspace
2601
- exports.isReadOnlyConfig = isReadOnlyConfig
2602
- exports.overrideCachedConfig = overrideCachedConfig
2603
- exports.overrideConfigApiToken = overrideConfigApiToken
2604
- exports.pathsToGlobPatterns = pathsToGlobPatterns
2605
- exports.readFileBinary = readFileBinary
2606
- exports.readFileUtf8 = readFileUtf8
2607
- exports.removeNodeModules = removeNodeModules
2608
- exports.safeReadFile = safeReadFile
2609
- exports.sensitiveConfigKeys = sensitiveConfigKeys
2610
- exports.setupSdk = setupSdk
2611
- exports.supportedConfigKeys = supportedConfigKeys
2612
- exports.updateConfigValue = updateConfigValue
2613
- exports.updateNode = updateNode
2614
- exports.updatePackageJsonFromNode = updatePackageJsonFromNode
2615
- //# debugId=8912efe8-10b0-4b17-afba-c7a406c69a66
2616
- //# sourceMappingURL=shadow-npm-inject.js.map