Files
cibuildwheel/bin/update_python_build_standalone.py
T
Henry SchreinerandCopilot 97537fe937 feat: add SHA256 verification for direct downloads
Store SHA256 hashes when running update scripts and verify them
when downloading files at build time. This improves security by
detecting unexpected changes to downloaded artifacts.

Platforms covered: macOS (CPython, PyPy, GraalPy), iOS, Android,
virtualenv, and python-build-standalone. Windows (nuget) and
Linux (Docker) are excluded.

SHA256 sources per platform:
- macOS/iOS/Android CPython (python.org): sha256_sum from API
- GraalPy: .sha256 sidecar assets from GitHub releases
- python-build-standalone: SHA256SUMS file in release
- PyPy, BeeWare iOS, Maven (Chaquopy): stream-download and compute

Changes:
- cibuildwheel/util/file.py: add sha256 param to download()
- cibuildwheel/platforms/{macos,ios,android}.py: add sha256 to
  PythonConfiguration and pass to download()
- cibuildwheel/venv.py: read sha256 from toml and pass to download()
- cibuildwheel/util/python_build_standalone.py: add sha256 to
  PythonBuildStandaloneAsset and pass to download()
- cibuildwheel/resources/build-platforms.toml: add sha256 fields
- cibuildwheel/resources/virtualenv.toml: add sha256 field
- cibuildwheel/resources/python-build-standalone-releases.json: add sha256
- bin/update_pythons.py: compute/store sha256 per source strategy
- bin/update_virtualenv.py: compute sha256 by streaming download
- bin/update_python_build_standalone.py: parse SHA256SUMS file

Closes #908

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: copilot-cli:claude-sonnet-4.6
2026-05-28 11:03:52 -04:00

91 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env -S uv run --script
# /// script
# dependencies = [
# "cibuildwheel",
# "requests",
# ]
#
# [tool.uv.sources]
# cibuildwheel = { path = ".." }
# ///
import json
import requests
from cibuildwheel.extra import github_api_request
from cibuildwheel.util.python_build_standalone import (
PythonBuildStandaloneAsset,
PythonBuildStandaloneReleaseData,
)
from cibuildwheel.util.resources import PYTHON_BUILD_STANDALONE_RELEASES
def main() -> None:
"""
This script updates the vendored list of release assets to the latest
version of astral-sh/python-build-standalone.
"""
# Get the latest release tag from the GitHub API
latest_release = github_api_request("repos/astral-sh/python-build-standalone/releases/latest")
latest_tag = latest_release["tag_name"]
# Get the list of assets for the latest release
github_assets = github_api_request(
f"repos/astral-sh/python-build-standalone/releases/tags/{latest_tag}"
)["assets"]
# Build a sha256 map from the SHA256SUMS file in the release
sha256_sums_urls = [
ga["browser_download_url"] for ga in github_assets if ga["name"] == "SHA256SUMS"
]
name_to_sha256: dict[str, str] = {}
if sha256_sums_urls:
response = requests.get(sha256_sums_urls[0])
response.raise_for_status()
for line in response.text.splitlines():
parts = line.split()
if len(parts) == 2:
sha256_hex, filename = parts
# The filename may have a leading "./" or spaces - strip it
name_to_sha256[filename.lstrip("./")] = sha256_hex
assets = [
PythonBuildStandaloneAsset(
name=ga["name"],
url=ga["browser_download_url"],
sha256=name_to_sha256.get(ga["name"], ""),
)
for ga in github_assets
if ga["name"].endswith("install_only.tar.gz")
]
# Try to keep output order stable
assets = sorted(assets, key=lambda x: x["name"])
# Write the assets to the JSON file. One day, we might need to support
# multiple releases, but for now, we only support the latest one
json_file_contents = PythonBuildStandaloneReleaseData(
releases=[
{
"tag": latest_tag,
"assets": assets,
}
]
)
with PYTHON_BUILD_STANDALONE_RELEASES.open("w", encoding="utf-8") as f:
json.dump(json_file_contents, f, indent=2)
# Add a trailing newline, our pre-commit hook requires it
f.write("\n")
print(
f"Updated {PYTHON_BUILD_STANDALONE_RELEASES.name} with {len(assets)} assets for tag {latest_tag}"
)
if __name__ == "__main__":
main()