1#!/usr/bin/env python3 2 3""" 4Compare checksums for wheels in :mod:`ensurepip` against the Cheeseshop. 5 6When GitHub Actions executes the script, output is formatted accordingly. 7https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message 8""" 9 10import hashlib 11import json 12import os 13import re 14from pathlib import Path 15from urllib.request import urlopen 16 17ENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip" 18WHEEL_DIR = ENSURE_PIP_ROOT / "_bundled" 19ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8") 20GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true" 21 22 23def print_notice(file_path: str, message: str) -> None: 24 if GITHUB_ACTIONS: 25 message = f"::notice file={file_path}::{message}" 26 print(message, end="\n\n") 27 28 29def print_error(file_path: str, message: str) -> None: 30 if GITHUB_ACTIONS: 31 message = f"::error file={file_path}::{message}" 32 print(message, end="\n\n") 33 34 35def verify_wheel(package_name: str) -> bool: 36 # Find the package on disk 37 package_paths = list(WHEEL_DIR.glob(f"{package_name}*.whl")) 38 if len(package_paths) != 1: 39 if package_paths: 40 for p in package_paths: 41 print_error(p, f"Found more than one wheel for package {package_name}.") 42 else: 43 print_error("", f"Could not find a {package_name} wheel on disk.") 44 return False 45 46 package_path = package_paths[0] 47 48 print(f"Verifying checksum for {package_path}.") 49 50 # Find the version of the package used by ensurepip 51 package_version_match = re.search( 52 f'_{package_name.upper()}_VERSION = "([^"]+)', ENSURE_PIP_INIT_PY_TEXT 53 ) 54 if not package_version_match: 55 print_error( 56 package_path, 57 f"No {package_name} version found in Lib/ensurepip/__init__.py.", 58 ) 59 return False 60 package_version = package_version_match[1] 61 62 # Get the SHA 256 digest from the Cheeseshop 63 try: 64 raw_text = urlopen(f"https://pypi.org/pypi/{package_name}/json").read() 65 except (OSError, ValueError): 66 print_error(package_path, f"Could not fetch JSON metadata for {package_name}.") 67 return False 68 69 release_files = json.loads(raw_text)["releases"][package_version] 70 for release_info in release_files: 71 if package_path.name != release_info["filename"]: 72 continue 73 expected_digest = release_info["digests"].get("sha256", "") 74 break 75 else: 76 print_error(package_path, f"No digest for {package_name} found from PyPI.") 77 return False 78 79 # Compute the SHA 256 digest of the wheel on disk 80 actual_digest = hashlib.sha256(package_path.read_bytes()).hexdigest() 81 82 print(f"Expected digest: {expected_digest}") 83 print(f"Actual digest: {actual_digest}") 84 85 if actual_digest != expected_digest: 86 print_error( 87 package_path, f"Failed to verify the checksum of the {package_name} wheel." 88 ) 89 return False 90 91 print_notice( 92 package_path, 93 f"Successfully verified the checksum of the {package_name} wheel.", 94 ) 95 return True 96 97 98if __name__ == "__main__": 99 exit_status = int(not verify_wheel("pip")) 100 raise SystemExit(exit_status) 101