Skip to content

Commit 427d928

Browse files
committed
Mark issues as fixable
1 parent 2b5e525 commit 427d928

File tree

1 file changed

+55
-27
lines changed

1 file changed

+55
-27
lines changed

src/shadow/arborist.ts

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,17 @@ const kRiskyReify = Symbol('riskyReify')
248248
const formatter = new ColorOrMarkdown(false)
249249
const pubToken = getDefaultKey() ?? FREE_API_KEY
250250

251+
type BatchIssue = {
252+
type: string
253+
value: {
254+
severity: string
255+
category: string
256+
locations: ({ [key: string]: any })[]
257+
label: string
258+
description: string
259+
props: { [key: string]: any }
260+
}
261+
}
251262
type IssueUXLookup = ReturnType<typeof createIssueUXLookup>
252263
type IssueUXLookupSettings = Parameters<IssueUXLookup>[0]
253264
type IssueUXLookupResult = ReturnType<IssueUXLookup>
@@ -271,7 +282,12 @@ async function* batchScan(
271282
): AsyncGenerator<
272283
{ eco: string; pkg: string; ver: string } & (
273284
| { type: 'missing' }
274-
| { type: 'success'; value: { issues: any[] } }
285+
| {
286+
type: 'success'
287+
value: {
288+
issues: BatchIssue[]
289+
}
290+
}
275291
)
276292
> {
277293
const query = {
@@ -369,6 +385,14 @@ function findSpecificOverrideSet(
369385
return undefined
370386
}
371387

388+
function isIssueFixable(issue: BatchIssue): boolean {
389+
const { type } = issue
390+
if (type === 'cve' || type === 'mediumCVE' || type === 'mildCVE' || type === 'criticalCVE') {
391+
return !!issue.value.props['firstPatchedVersionIdentifier']
392+
}
393+
return type === 'socketUpgradeAvailable'
394+
}
395+
372396
function maybeReadfileSync(filepath: string): string | undefined {
373397
try {
374398
return readFileSync(filepath, 'utf8')
@@ -400,26 +424,27 @@ async function packagesHaveRiskyIssues(
400424
const id = `${name}@${version}`
401425

402426
let displayWarning = false
403-
let failures: {
427+
let issues: {
404428
type: string
405429
block: boolean
430+
fixable: boolean
406431
raw?: any
407432
}[] = []
408433
if (pkgData.type === 'missing') {
409434
result = true
410-
failures.push({
435+
issues.push({
411436
type: 'missingDependency',
412437
block: false,
438+
fixable: false,
413439
raw: undefined
414440
})
415441
} else {
416442
let blocked = false
417-
for (const failure of pkgData.value.issues) {
418-
const { type } = failure
443+
for (const issue of pkgData.value.issues) {
419444
// eslint-disable-next-line no-await-in-loop
420445
const ux = await uxLookup({
421446
package: { name, version },
422-
issue: { type }
447+
issue: { type: issue.type }
423448
})
424449
if (ux.block) {
425450
result = true
@@ -429,10 +454,11 @@ async function packagesHaveRiskyIssues(
429454
displayWarning = true
430455
}
431456
if (ux.block || ux.display) {
432-
failures.push({
433-
type,
457+
issues.push({
458+
type: issue.type,
434459
block: ux.block,
435-
raw: failure
460+
raw: issue,
461+
fixable: isIssueFixable(issue)
436462
})
437463
// Before we ask about problematic issues, check to see if they
438464
// already existed in the old version if they did, be quiet.
@@ -445,10 +471,10 @@ async function packagesHaveRiskyIssues(
445471
(await batchScan([pkg.existing]).next()).value
446472
)
447473
if (oldPkgData.type === 'success') {
448-
failures = failures.filter(
449-
issue =>
474+
issues = issues.filter(
475+
({ type }) =>
450476
oldPkgData.value.issues.find(
451-
oldIssue => oldIssue.type === issue.type
477+
oldIssue => oldIssue.type === type
452478
) === undefined
453479
)
454480
}
@@ -469,30 +495,32 @@ async function packagesHaveRiskyIssues(
469495
}
470496
}
471497
}
498+
if (displayWarning && isBlessedPackageName(name)) {
499+
issues = issues.filter(
500+
({ type }) =>
501+
type !== 'unpopularPackage' && type !== 'unstableOwnership'
502+
)
503+
displayWarning = issues.length > 0
504+
}
472505
if (displayWarning) {
473506
spinner.stop(
474507
`(socket) ${formatter.hyperlink(id, `https://socket.dev/npm/package/${name}/overview/${version}`)} contains risks:`
475508
)
476-
// Filter issues for blessed packages.
477-
if (isBlessedPackageName(name)) {
478-
failures = failures.filter(
479-
({ type }) =>
480-
type !== 'unpopularPackage' && type !== 'unstableOwnership'
481-
)
482-
}
483-
failures.sort((a, b) => (a.type < b.type ? -1 : 1))
484-
509+
issues.sort((a, b) => (a.type < b.type ? -1 : 1))
485510
const lines = new Set()
486-
for (const failure of failures) {
487-
const { type } = failure
511+
for (const issue of issues) {
488512
// Based data from { pageProps: { alertTypes } } of:
489513
// https://socket.dev/_next/data/94666139314b6437ee4491a0864e72b264547585/en-US.json
490-
const info = translations.issues[type]
491-
const title = info?.title ?? type
492-
const maybeBlocking = failure.block ? '' : ' (non-blocking)'
514+
const info = translations.issues[issue.type]
515+
const title = info?.title ?? issue.type
516+
const attributes = [
517+
...(issue.fixable ? ['fixable'] : []),
518+
...(issue.block ? [] : ['non-blocking'])
519+
]
520+
const maybeAttributes = attributes.length ? ` (${attributes.join('; ')})` : ''
493521
const maybeDesc = info?.description ? ` - ${info.description}` : ''
494522
// TODO: emoji seems to mis-align terminals sometimes
495-
lines.add(` ${title}${maybeBlocking}${maybeDesc}\n`)
523+
lines.add(` ${title}${maybeAttributes}${maybeDesc}\n`)
496524
}
497525
for (const line of lines) {
498526
output?.write(line)

0 commit comments

Comments
 (0)