99import zipfile
1010import pip
1111from pip ._vendor import msgpack , urllib3
12+ from vendor_source_inventory import inventory
1213
1314EXPECTED_SHA = "be5f63d537bbe611dc422fabb6740a44b5997888b592888df5091727f023802a"
15+ BOM_SHA = "3581cb8f0a6128c19ccec4e9aeab0d3ac8212fd19bd19d485b2e24fd4dc10f2a"
1416FINDINGS = {
1517 "GHSA-6v7p-g79w-8964" : ("msgpack" , "1.1.2" , "C/Cython unpacker is absent; runtime selects pure Python fallback" ),
1618 "CVE-2026-57585" : ("msgpack" , "1.1.2" , "C/Cython unpacker is absent; runtime selects pure Python fallback" ),
19+ "CVE-2026-114613" : ("msgpack" , "1.1.2" , "_unpacker.pyx/unpack.h strict-map-key C extension is absent; fallback.py is not affected" ),
20+ "GHSA-j586-36cw-2gc2" : ("msgpack" , "1.1.2" , "_unpacker.pyx/unpack.h strict-map-key C extension is absent; fallback.py is not affected" ),
1721 "CVE-2025-47273" : ("setuptools" , "70.3.0" , "setuptools/package_index.py is absent; only pkg_resources is vendored" ),
1822 "CVE-2026-59890" : ("setuptools" , "70.3.0" , "setuptools/command/egg_info.py and FileList are absent" ),
23+ "GHSA-xmj3-9gf7-h52w" : ("setuptools" , "70.3.0" , "setuptools/wheel.py Wheel._fix_namespace_packages is absent; only pkg_resources is vendored" ),
1924}
2025
2126
27+ def require_absent_vulnerable_modules (names ):
28+ names = tuple (names )
29+ assert not any (name .startswith ("pip/_vendor/msgpack/_cmsgpack" ) for name in names ), "Native msgpack module present"
30+ assert not any (name .startswith ("pip/_vendor/setuptools/" ) for name in names ), "Full setuptools module present"
31+
32+
2233def verify (wheel ):
2334 assert hashlib .sha256 (wheel .read_bytes ()).hexdigest () == EXPECTED_SHA
2435 assert pip .__version__ == "26.2.2+pasturestack.1"
@@ -36,8 +47,7 @@ def verify(wheel):
3647 expected_files .add (name .removeprefix ("pip/_vendor/" ))
3748 checked += 1
3849 assert not any (name .startswith ("pip/_vendor/" ) and name .endswith ((".so" , ".pyd" )) for name in names )
39- assert not any (name .startswith ("pip/_vendor/setuptools/" ) for name in names )
40- assert not any (name .startswith ("pip/_vendor/msgpack/_cmsgpack" ) for name in names )
50+ require_absent_vulnerable_modules (names )
4151 def live_files (directory , prefix = "" ):
4252 for entry in directory .iterdir ():
4353 if entry .name == "__pycache__" :
@@ -47,17 +57,20 @@ def live_files(directory, prefix=""):
4757 yield from live_files (entry , relative + "/" )
4858 else :
4959 yield relative
50- assert set (live_files (live .joinpath ("_vendor" ))) == expected_files , "Unexpected live vendor files"
60+ observed_files = set (live_files (live .joinpath ("_vendor" )))
61+ require_absent_vulnerable_modules ("pip/_vendor/" + name for name in observed_files )
62+ assert observed_files == expected_files , "Unexpected live vendor files"
5163 # A separate full setuptools installation cannot inherit the vendor-slice VEX.
5264 for distribution in importlib .metadata .distributions ():
5365 if distribution .metadata .get ("Name" , "" ).lower () == "setuptools" :
5466 assert distribution .version != "70.3.0" , "A full setuptools 70.3.0 distribution is installed"
5567 if distribution .metadata .get ("Name" , "" ).lower () == "msgpack" :
5668 assert distribution .version != "1.1.2" , "A separate msgpack 1.1.2 distribution is installed"
57- return {"verifiedWheelSha256" : EXPECTED_SHA , "pip" : pip .__version__ ,
69+ return {"verifiedWheelSha256" : EXPECTED_SHA , "verifiedWheelPath" : str ( wheel . resolve ()), " pip" : pip .__version__ ,
5870 "urllib3" : urllib3 .__version__ , "vendorFilesByteCompared" : checked ,
5971 "msgpackImplementation" : msgpack .Unpacker .__module__ ,
60- "setuptoolsPackageAbsent" : True , "scope" : "this exact pip vendor slice only" ,
72+ "setuptoolsPackageAbsent" : True , "vulnerableModulesAbsent" : ["msgpack._cmsgpack" , "setuptools.wheel" ],
73+ "scope" : "this exact pip vendor slice only" ,
6174 "notAffected" : [{"id" : key , "package" : value [0 ], "version" : value [1 ],
6275 "justification" : "vulnerable_code_not_present" , "detail" : value [2 ]}
6376 for key , value in FINDINGS .items ()]}
@@ -81,6 +94,7 @@ def live_files(directory, prefix=""):
8194 else :
8295 with ensurepip ._get_pip_whl_path_ctx () as wheel :
8396 result = verify (Path (wheel ))
97+ result ["vendorSourceInventory" ] = inventory (Path ("/" ), EXPECTED_SHA , BOM_SHA )
8498 data = json .dumps (result , indent = 2 ) + "\n "
8599 if args .output :
86100 args .output .write_text (data )
0 commit comments