* 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
* fix: populate sha256 in resource files and fix Windows PythonConfiguration
- Add sha256 field to Windows PythonConfiguration (PyPy/GraalPy have
direct download URLs on Windows too)
- Pass sha256 to install_pypy() and install_graalpy() in windows.py
- Fix update_pythons.py: handle empty sha256 from CPython API (older
versions) by streaming download to compute it; fix condition to
check 'not sha256' rather than 'not in dict'
- Fix update_virtualenv.py: compute sha256 even when version unchanged
but sha256 is empty (first-time population)
- Fix update_python_build_standalone.py: resolve file path relative to
the script itself (not the installed package) so writes go to source
checkout, not the uv cache
- Populate actual sha256 values by running all three update scripts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: copilot-cli:claude-sonnet-4.6
* fix: also include pyodide
Assisted-by: CopilotCLI:gpt-5.3-codex
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: PR review comments for cache verification and docs wording
Co-authored-by: henryiii <4616906+henryiii@users.noreply.github.com>
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: require sha256 for download configs
Require sha256 for URL-backed Python and virtualenv download configs. Update the GraalPy updater to refresh macOS x86_64 entries by selecting the latest release that still has a matching asset, and fill the two missing GraalPy checksums in build-platforms.toml.
Assisted-by: CopilotCLI:gpt-5.4
* ci: remove unit test for bin item
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* refactor: combine sha256 unit tests into test_sha256.py
Merge pyodide_test.py and python_build_standalone_test.py into a
single unit_test/test_sha256.py since both test sha256-related
behaviour.
Assisted-by: opencode:glm-5
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: henryiii <4616906+henryiii@users.noreply.github.com>
* feat: add CIBUILDWHEEL_BUILD_IDENTIFIER environment variable
Set `CIBUILDWHEEL_BUILD_IDENTIFIER` to the current build identifier
(e.g. `cp311-manylinux_x86_64`) in the environment for all per-build
steps: `before_build`, the build itself, `repair_command`,
`before_test`, and `test_command`.
This allows scripts and commands to inspect which build is currently
running, which is useful for e.g. writing per-build output files:
CIBW_TEST_COMMAND='pytest --junit-xml=results-$CIBUILDWHEEL_BUILD_IDENTIFIER.xml'
The variable is set after the user's environment overrides are applied
and is only available for per-build steps (not `before_all`, where no
single identifier applies). All six platforms are covered: linux, macOS,
Windows, pyodide, Android, and iOS.
Closes#944, closes#2750
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Assisted-by: OpenCode:claude-sonnet-4.6
* fix: address review comment moving this for Android
Assisted-by: OpenCode:glm-5.1
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: add CPython 3.15 support for iOS
Assisted-by: OpenCode:Kimi-K2.6
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: copy in iOS support files
Assisted-by: Copilot:claude-sonnet-4.6
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: skip directories when copying iOS support files
When copying multiarch-specific support files (e.g. _cross_arm64_iphoneos.py),
the code was trying to copy all items in the directory including __pycache__
directories. The shutil.copy() function only works with files, not directories,
which caused an IsADirectoryError.
This fix adds a check to only copy files, skipping any directories like
__pycache__ that may have been created by Python imports.
Assisted-by: Copilot:claude-haiku-4.5
* fix: - in dir fine for now
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: apply review suggestions
Assisted-by: Copilot:claude-sonnet-4.6
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: only do this on 3.15+
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* Ensure target Python directory exists before build
Add assertion to check if target Python directory exists.
* fix(ios): use stdlib dir directly instead of copying to platform-config
Remove the _inject_support_files workaround for python.org 3.15+
distributions. Instead of copying sysconfig files from the stdlib into
a synthetic platform-config/ directory, pass the stdlib directory
directly to make_cross_venv.py.
make_cross_venv.py is updated to derive the multiarch tag from the
_sysconfigdata_ filename rather than assuming it comes from the
directory name.
Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
Assisted-by: OpenCode:Kimi-K2.6
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* Minor format cleanups on pre-commit skipped files.
* Clarify path names in make_cross_venv script.
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
* WIP - initial punt at audit command
* Add `abi3audit` as a dependency
* Add helper functions to check stable ABI wheels
* Run `abi3audit` for macOS and Windows wheels
* Copy out of container for repairing?
* Add some notes that `cibuildwheel` runs `abi3audit`
* Add basic unit tests
* Add a basic C extension with `Py_LIMITED_API`
* Add a test project that violates Stable ABI
* Fix linux test
* Skip abi3 wheel tests for Pyodide
* Patch the correct subprocess module
* wrap cleanup of abi3audit dir
* Write the docs for the new options
* Move to above testing in docs
* Implement audit-requires and audit-command
* Some cleanups after self-review
* Add default value
* fix type errors
* the key is `audit-command`, not `audit`
* Add a variety of tests for audit requires options
* Add `test_audit_requires` similar to `test_test_requires`
* Add some configurability-related audit tests
* Fix parsing error with options docs leaving out commands
* Better way to extract version (maybe helps Pyodide?)
* Fix a case of unbound `use_uv`
* Standardise: rename to `abi3_wheel`
* Fix audit command run message
* Simplify custom audit command a bit
* Remove unnecessary skip for Pyodide
* Pyodide should have no default audit command
* More accurate skip messages for Pyodide skips
* Wheels are audited after they are repaired
* Regenerate constraints to include `abi3audit`
* Fix typos
* Some attempts for Windows fixes
* Check `pyvenv.cfg` instead of directory existence
* Add validation for lack of wheel placeholders
* Try yet another Windows `uv` fix
* Regenerate diagram and re-trigger Azure CI
* Add missing `import sys` for abi3 C extension tests
* Remove audit-command at the global level
* Clarify `abi3audit` pinning a little bit
* Regen constraints
* Discard changes to cibuildwheel/resources/constraints-pyodide312.txt
* Discard changes to cibuildwheel/resources/constraints-pyodide313.txt
* try opt-in uv again
* fix issue on windows on Python 3.13 related to nested venvs
On win / python 3.13, virtualenv creates a venv where the 'home'
points back to the venv that sys.executable was running in, rather
than the root install. that seemingly leads to problems with package
resolution, where pip.exe couldn't find the pip python package.
this appears to fix it!
* Update constraints
* chore: revert python-discovery bump
Assisted-by: OpenCode:glm-5.1
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
* fix: restore workaround for graalpy
Assisted-by: OpenCode:glm-5.1
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
---------
Signed-off-by: Henry Schreiner <henryfs@princeton.edu>
Co-authored-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Co-authored-by: Henry Schreiner <henryfs@princeton.edu>
* chore: clean up config a bit
* chore: add an extra check
* Apply suggestions from code review
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
* Don't constrain build-system.requires with dependency-versions
* Remove setting of VIRTUALENV_PIP (it doesn't appear to have any effect)
* Alter tests to assert the versions in before_build, not setup.py
* Skip the util-test on linux
---------
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
* Add test-execution-args option.
* Add usage of test-execution-args.
* Add CI configuration to use test-execution-args.
* Document the test-execution-args setting.
* Simplify code using or syntax instead of inline if.
Co-authored-by: Malcolm Smith <smith@chaquo.com>
* Clarified some Android-specific terminology, and added details about the default args to the test runner.
* Switch to a dict-based test-execution configuration
* Add tests for test-execution parsing.
* Add all the files before pushing...
* Add note about default Android version for testbed.
* Improve description of test-execution setting.
Co-authored-by: Joe Rickerby <joerick@mac.com>
* Switch to using test-runtime.
---------
Co-authored-by: Malcolm Smith <smith@chaquo.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
* Add Android to resource files
* Add Android to miscellaneous places
* Add Android documentation
* Docs cleanups
* Add Android platform module; implement top-level structure and target Python installation
* Implement setup_env and build_wheel
* lru-dict build working
* Alter prefix in sysconfigdata file; fix various issues with FLAGS variables
* Implement Android testing
* Add type annotations to _cross_venv
* Revert Python 3.8 to pip 25.0.1
* Make test-sources required on Android
* Add Android integration tests
* Test cleanups
* Add test of all available Python versions
* Update test-sources and test-command behavior to match iOS
* Documentation cleanups
* Replace Builder class with a set of global functions
* Rename "env" to "build_env"
* Remove Chaquopy repository from default pip command line
* Move native_platform to platforms module
* Fix parse_config_settings
Co-authored-by: Joe Rickerby <joerick@mac.com>
* Add unit tests for parse_config_settings and arch_synonym
* Make `shell_prepared` arguments keyword-only, and add tests for the commands that use it
* Replace `importlib.util.spec_from_file_location` with `runpy.run_path`
* Use python-build-standalone
* Update Android Python
* Enable KVM in Linux CI
* Move KVM code to test_android.py
* Use Java 17 on Azure
* Install emulator if necessary before running -accel-check
* Free up additional disk space on Linux runners
* Add sudo
* Skip emulator tests on CI platforms that don't support it
* Download Android Python from Maven Central
* Free up more disk space on Linux runners
* fix: minor fixups
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* Set sysconfig._BASE_PREFIX to support sysconfig.get_path("include")
* Get ANDROID_API_LEVEL from the build environment, not cibuildwheel's own environment
* Correct relative path of test-sources
* Pass a CMake toolchain file to the build
* Add "repair" step which adds libc++ to the wheel when necessary
* Add missing needs_emulator decorator
* Provide useful error message if ANDROID_HOME is not set
* Remove use of HOST environment variable
* Update to Python 3.15.5
* Fix PyLint warnings, clarify comment
* Group common arguments into a dataclass
* Handle environment variables containing newlines
* Discourage the use of `pytest` test commands without `python -m`
* Use single quotes in user-visible messages
* Improve testing documentation
* Pass wheel filename to `log.build_end`
* In GitHub Actions example, skip Android tests on macOS
* Correct relative paths in `patchelf --set-rpath`
* Clarify `test-sources` docs
* Update to Python 3.13.5+20250722.214220
---------
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
Co-authored-by: Henry Schreiner <henryschreineriii@gmail.com>
* chore: add summary to Action
* refactor: new summary table
* fix: fixup tests and formatting
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: pyodide missing some logging
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: nicer printout, nicer in-place summary
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: use summary for everything
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: support only one output wheel from repair
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* Add new Github summary format
* Remove a couple of humanize uses
* fix: filter ANSI codes in summary
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: add sha256
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* fix: nicer wheel/wheels depending on how many are present
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
---------
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
* feat: support multiple commands on iOS
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
* Move split_command into a util module
* (unrelated) fix test docstring
* Implement short-circuit behaviour on test-command
---------
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
Co-authored-by: Joe Rickerby <joerick@mac.com>
* Revert to running tests from from a temp dir when test-sources is unset
* Fix placeholders error message, add test for it
* Add back {project} placeholders to CIBW_TEST_COMMAND in tests & docs
* Update test/test_before_test.py
---------
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
* Add TEST_ENVIRONMENT option and set PYTHONSAFEPATH=1 in the test env
Closes https://github.com/pypa/cibuildwheel/issues/2358
* Add toml docs examples
* Add TOML examples
* Use double-quotes for windows
* Change to the iOS testing option semantics
Don't assume the presence of `python -m` in the test command. Less magic
and allows more option reuse between platforms.
* Update schema
* Add a test for this warning
* Don't try to execute a test-command when it doesn't look like a module
* Update docs/options.md
Co-authored-by: Malcolm Smith <smith@chaquo.com>
* Only allow invalid test command if the first part is 'pytest'
* Responses to code review from @freakboy3742
* Fixes post-merge
---------
Co-authored-by: Malcolm Smith <smith@chaquo.com>
* Add the ability to declare safe tools in a cross-build environment.
* Add an xfail if cmake isn't available on the test machine.
* Placate linter regarding positional args.
* Rework test to provide more robust confirmation of safe tools.
* Remove a test skip condition that is no longer needed.
Co-authored-by: Joe Rickerby <joerick@mac.com>
* Rename the setting to xbuild-tools.
* Add docs to clarify that xbuild-tools is transitive.
* Raise a warning if xbuild-tools isn't defined.
* Correct a bad copy-paste in the schema generator.
* .. and now fix the indentation.
* Move sentinel handling earlier into the parsing process.
* Remove serialization from tests that won't start a test suite.
---------
Co-authored-by: Joe Rickerby <joerick@mac.com>
* feat: stricter selector parsing, refactor to `platforms` module
- Use a different method to build nothing
- Make the check aware of enable groups
* optimise unit tests - a specific platform module API for all configs
Unit test time: 26.2s -> 13.1s
* Remove unnecessary get_platform_module function