@@ -373,10 +373,30 @@ def execute(self, query, variable_values):
373373 npm_audit .searchCVE = original_search
374374
375375
376- def test_repository_advisory_fallback_discovers_package_cve () -> None :
376+ def test_repository_advisories_are_merged_with_ghad_results () -> None :
377377 class FakeClient :
378378 def execute (self , query , variable_values ):
379- return {"securityVulnerabilities" : {"nodes" : []}}
379+ return {
380+ "securityVulnerabilities" : {
381+ "nodes" : [
382+ {
383+ "severity" : "MODERATE" ,
384+ "vulnerableVersionRange" : ">=10.1.1, <=10.2.0" ,
385+ "firstPatchedVersion" : {"identifier" : "10.2.1" },
386+ "advisory" : {
387+ "ghsaId" : "GHSA-22jq-vg5j-6vgg" ,
388+ "identifiers" : [
389+ {"type" : "GHSA" , "value" : "GHSA-22jq-vg5j-6vgg" },
390+ {"type" : "CVE" , "value" : "CVE-2026-54272" },
391+ ],
392+ "permalink" : "https://github.com/advisories/GHSA-22jq-vg5j-6vgg" ,
393+ "summary" : "ip-address mapped/NAT64 bypass" ,
394+ "withdrawnAt" : None ,
395+ },
396+ }
397+ ]
398+ }
399+ }
380400
381401 class FakeResponse :
382402 def __enter__ (self ):
@@ -387,12 +407,32 @@ def __exit__(self, exc_type, exc, tb):
387407
388408 def read (self ):
389409 return json .dumps ([
410+ {
411+ "ghsa_id" : "GHSA-mwp4-54f8-5fhr" ,
412+ "cve_id" : "CVE-2026-69192" ,
413+ "html_url" : "https://github.com/beaugunderson/ip-address/security/advisories/GHSA-mwp4-54f8-5fhr" ,
414+ "severity" : "high" ,
415+ "summary" : "ip-address leading-zero octet parsing bypass" ,
416+ "state" : "published" ,
417+ "withdrawn_at" : None ,
418+ "identifiers" : [
419+ {"type" : "GHSA" , "value" : "GHSA-mwp4-54f8-5fhr" },
420+ {"type" : "CVE" , "value" : "CVE-2026-69192" },
421+ ],
422+ "vulnerabilities" : [
423+ {
424+ "package" : {"ecosystem" : "npm" , "name" : "ip-address" },
425+ "vulnerable_version_range" : "<=10.3.0" ,
426+ "patched_versions" : "10.3.1" ,
427+ }
428+ ],
429+ },
390430 {
391431 "ghsa_id" : "GHSA-4xrf-jv44-h6hh" ,
392432 "cve_id" : "CVE-2026-69198" ,
393433 "html_url" : "https://github.com/beaugunderson/ip-address/security/advisories/GHSA-4xrf-jv44-h6hh" ,
394434 "severity" : "medium" ,
395- "summary" : "ip-address SSRF classification bypass" ,
435+ "summary" : "ip-address CIDR suffix bypass" ,
396436 "state" : "published" ,
397437 "withdrawn_at" : None ,
398438 "identifiers" : [
@@ -402,11 +442,11 @@ def read(self):
402442 "vulnerabilities" : [
403443 {
404444 "package" : {"ecosystem" : "npm" , "name" : "ip-address" },
405- "vulnerable_version_range" : ">=10.1.1, <10.2.2 " ,
445+ "vulnerable_version_range" : ">=10.1.1, <= 10.2.1 " ,
406446 "patched_versions" : "10.2.2" ,
407447 }
408448 ],
409- }
449+ },
410450 ]).encode ()
411451
412452 original_client = npm_audit .Client
@@ -430,10 +470,8 @@ def read(self):
430470 [{"name" : "ip-address" , "version" : "10.2.0" , "path" : "node_modules/ip-address" }],
431471 Vulnerability ,
432472 )
433- assert len (vulns ) == 1 , vulns
434- assert vulns [0 ].id == "CVE-2026-69198"
435- assert vulns [0 ].advisory_aliases == ["GHSA-4xrf-jv44-h6hh" ]
436- assert vulns [0 ].url == "https://github.com/beaugunderson/ip-address/security/advisories/GHSA-4xrf-jv44-h6hh"
473+ ids = sorted (v .id for v in vulns )
474+ assert ids == ["CVE-2026-54272" , "CVE-2026-69192" , "CVE-2026-69198" ], vulns
437475 finally :
438476 npm_audit .Client = original_client
439477 npm_audit .AIOHTTPTransport = original_transport
@@ -707,7 +745,7 @@ def test_npm_audit_basic() -> None:
707745 test_enolock_with_node_modules_still_falls_back ()
708746 test_enolock_falls_back_to_install_and_normal_audit ()
709747 test_nvd_primary_merges_ghad_aliases ()
710- test_repository_advisory_fallback_discovers_package_cve ()
748+ test_repository_advisories_are_merged_with_ghad_results ()
711749 test_query_failure_is_skipped_per_package ()
712750 test_invalid_advisory_range_or_version_is_skipped ()
713751 test_normalize_npm_advisory_id ()
0 commit comments