| 
									
										
										
										
											2023-09-06 16:49:44 +02:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							| 
									
										
										
										
											2022-06-22 16:32:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | Compare checksums for wheels in :mod:`ensurepip` against the Cheeseshop. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When GitHub Actions executes the script, output is formatted accordingly. | 
					
						
							|  |  |  | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import hashlib | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | from pathlib import Path | 
					
						
							|  |  |  | from urllib.request import urlopen | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip" | 
					
						
							|  |  |  | WHEEL_DIR = ENSURE_PIP_ROOT / "_bundled" | 
					
						
							|  |  |  | ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8") | 
					
						
							|  |  |  | GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def print_notice(file_path: str, message: str) -> None: | 
					
						
							|  |  |  |     if GITHUB_ACTIONS: | 
					
						
							|  |  |  |         message = f"::notice file={file_path}::{message}" | 
					
						
							|  |  |  |     print(message, end="\n\n") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def print_error(file_path: str, message: str) -> None: | 
					
						
							|  |  |  |     if GITHUB_ACTIONS: | 
					
						
							|  |  |  |         message = f"::error file={file_path}::{message}" | 
					
						
							|  |  |  |     print(message, end="\n\n") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def verify_wheel(package_name: str) -> bool: | 
					
						
							|  |  |  |     # Find the package on disk | 
					
						
							| 
									
										
										
										
											2023-09-06 16:49:44 +02:00
										 |  |  |     package_paths = list(WHEEL_DIR.glob(f"{package_name}*.whl")) | 
					
						
							|  |  |  |     if len(package_paths) != 1: | 
					
						
							|  |  |  |         if package_paths: | 
					
						
							|  |  |  |             for p in package_paths: | 
					
						
							|  |  |  |                 print_error(p, f"Found more than one wheel for package {package_name}.") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print_error("", f"Could not find a {package_name} wheel on disk.") | 
					
						
							| 
									
										
										
										
											2022-06-22 16:32:22 +03:00
										 |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-06 16:49:44 +02:00
										 |  |  |     package_path = package_paths[0] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-22 16:32:22 +03:00
										 |  |  |     print(f"Verifying checksum for {package_path}.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Find the version of the package used by ensurepip | 
					
						
							|  |  |  |     package_version_match = re.search( | 
					
						
							|  |  |  |         f'_{package_name.upper()}_VERSION = "([^"]+)', ENSURE_PIP_INIT_PY_TEXT | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     if not package_version_match: | 
					
						
							|  |  |  |         print_error( | 
					
						
							|  |  |  |             package_path, | 
					
						
							|  |  |  |             f"No {package_name} version found in Lib/ensurepip/__init__.py.", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     package_version = package_version_match[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the SHA 256 digest from the Cheeseshop | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         raw_text = urlopen(f"https://pypi.org/pypi/{package_name}/json").read() | 
					
						
							|  |  |  |     except (OSError, ValueError): | 
					
						
							|  |  |  |         print_error(package_path, f"Could not fetch JSON metadata for {package_name}.") | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     release_files = json.loads(raw_text)["releases"][package_version] | 
					
						
							|  |  |  |     for release_info in release_files: | 
					
						
							|  |  |  |         if package_path.name != release_info["filename"]: | 
					
						
							|  |  |  |             continue | 
					
						
							|  |  |  |         expected_digest = release_info["digests"].get("sha256", "") | 
					
						
							|  |  |  |         break | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         print_error(package_path, f"No digest for {package_name} found from PyPI.") | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Compute the SHA 256 digest of the wheel on disk | 
					
						
							|  |  |  |     actual_digest = hashlib.sha256(package_path.read_bytes()).hexdigest() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print(f"Expected digest: {expected_digest}") | 
					
						
							|  |  |  |     print(f"Actual digest:   {actual_digest}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if actual_digest != expected_digest: | 
					
						
							|  |  |  |         print_error( | 
					
						
							|  |  |  |             package_path, f"Failed to verify the checksum of the {package_name} wheel." | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print_notice( | 
					
						
							|  |  |  |         package_path, | 
					
						
							|  |  |  |         f"Successfully verified the checksum of the {package_name} wheel.", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2024-01-30 02:25:31 +01:00
										 |  |  |     exit_status = int(not verify_wheel("pip")) | 
					
						
							| 
									
										
										
										
											2022-06-22 16:32:22 +03:00
										 |  |  |     raise SystemExit(exit_status) |