@@ -248,6 +248,17 @@ const kRiskyReify = Symbol('riskyReify')
248248const formatter = new ColorOrMarkdown ( false )
249249const 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+ }
251262type IssueUXLookup = ReturnType < typeof createIssueUXLookup >
252263type IssueUXLookupSettings = Parameters < IssueUXLookup > [ 0 ]
253264type 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+
372396function 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