@@ -497,25 +497,41 @@ def fetch_global_advisories(self, packages: List[Dict[str, str]]) -> List[Dict]:
497497 requested = tuple (sorted ({f"{ package ['name' ]} @{ package ['version' ]} " for package in packages }))
498498 if requested in cache :
499499 return cache [requested ]
500- query = urllib .parse .urlencode ([
501- ("ecosystem" , "npm" ),
502- ("affects" , "," .join (requested )),
503- ("per_page" , "100" ),
504- ])
505- url = f"https://api.github.com/advisories?{ query } "
500+
506501 headers = {
507502 "Accept" : "application/vnd.github+json" ,
508503 "X-GitHub-Api-Version" : GITHUB_API_VERSION ,
509504 "User-Agent" : "nsolid-dependency-vuln-assessments" ,
510505 }
511- request = urllib .request .Request (url , headers = headers )
512- with urllib .request .urlopen (request , timeout = min (self .timeout , 30 )) as response :
513- payload = json .load (response )
514- if not isinstance (payload , list ):
515- logger .warning (f"Global advisory query returned non-list payload for { len (requested )} packages: { payload } " )
516- return []
517- cache [requested ] = [item for item in payload if isinstance (item , dict )]
518- return cache [requested ]
506+ advisories : List [Dict ] = []
507+ seen_ids : set [str ] = set ()
508+ batch_size = 25
509+
510+ for index in range (0 , len (requested ), batch_size ):
511+ batch = requested [index :index + batch_size ]
512+ query = urllib .parse .urlencode (
513+ [("ecosystem" , "npm" ), * ( ("affects[]" , item ) for item in batch ), ("per_page" , "100" )]
514+ )
515+ url = f"https://api.github.com/advisories?{ query } "
516+ request = urllib .request .Request (url , headers = headers )
517+ with urllib .request .urlopen (request , timeout = min (self .timeout , 30 )) as response :
518+ payload = json .load (response )
519+ if not isinstance (payload , list ):
520+ logger .warning (
521+ f"Global advisory query returned non-list payload for batch { index // batch_size + 1 } of { ((len (requested ) - 1 ) // batch_size ) + 1 } : { payload } "
522+ )
523+ continue
524+ for item in payload :
525+ if not isinstance (item , dict ):
526+ continue
527+ advisory_id = item .get ("ghsa_id" ) or item .get ("cve_id" ) or id (item )
528+ if advisory_id in seen_ids :
529+ continue
530+ seen_ids .add (advisory_id )
531+ advisories .append (item )
532+
533+ cache [requested ] = advisories
534+ return advisories
519535
520536 def preferred_global_advisory_cve (self , advisory : Dict ) -> Optional [str ]:
521537 for identifier in advisory .get ("identifiers" ) or []:
0 commit comments