Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b1d6a75
Validate native wheel architecture headers
Aug 6, 2026
6cea263
Verify native wheel ABI exports
Aug 6, 2026
89fc164
Add Linux native linkage inspection
Aug 6, 2026
ab85510
Validate native wheel linkage policies
Aug 6, 2026
d99508f
Require runtime verification for published wheels
Aug 6, 2026
911ea18
Address wheel verifier review findings
Aug 7, 2026
983c244
Reject empty release wheel matrices
Aug 7, 2026
a31c662
Complete wheel verifier review fixes
Aug 7, 2026
f515240
Address latest wheel release review feedback
Aug 7, 2026
03d998a
Merge upstream/main and resolve wheel ABI review
harsh21234i Oct 26, 2026
8eb29da
Guard runtime smoke coverage for every wheel target
harsh21234i Oct 26, 2026
6db26b6
Harden wheel platform and linkage validation
harsh21234i Oct 26, 2026
3807e8e
Clarify wheel target support impact
harsh21234i Oct 26, 2026
8101f0b
Isolate delay-load imports in verification test
harsh21234i Oct 26, 2026
b1c9435
Tighten native release verification coverage
harsh21234i Oct 26, 2026
2ee44d2
Clarify wheel matrix requires maintainer sign-off
harsh21234i Oct 26, 2026
142d716
Allow self-contained Linux wheel libraries
harsh21234i Oct 26, 2026
3568be8
Restore runtime verification for published wheel targets
harsh21234i Oct 26, 2026
ab2ea8b
Update platform support guidance and docs checks
harsh21234i Oct 26, 2026
2910ca9
Assert complete release smoke coverage modes
harsh21234i Oct 26, 2026
0a58351
Check published wheel rows in docs regression test
harsh21234i Oct 26, 2026
8a7edcd
Merge upstream main and resolve release readiness conflict
harsh21234i Oct 26, 2026
7515eab
Merge upstream main into fix/wheel-abi-linkage-verification-448
FarhanAliRaza Oct 27, 2026
6649f5b
Remove local validation artifacts from the source tree
FarhanAliRaza Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 65 additions & 35 deletions .github/workflows/build_release_artifacts.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Builds every artifact an `xy` release publishes: eleven cross-compiled platform
# Builds every artifact an `xy` release publishes: eleven runtime-verified native
# wheels, a runtime-verified PyEmscripten wheel and an sdist. No single runner can
# produce that set, which is why this is a repository-supplied build workflow
# rather than the `uv build` the release pipeline runs by default.
Expand Down Expand Up @@ -45,7 +45,7 @@ on:
required: true
type: string
# Dry run: build and verify the full matrix without a release. Use it to
# exercise the cross-compile legs (musllinux, win-arm64, wasm, ...) after
# exercise the native targets (Linux, macOS, Windows, wasm, ...) after
# touching the matrix, the toolchains or the wheel tags — a target added but
# never exercised is unverified, not working. Nothing here can publish: the
# upload path lives in publish.yml, which this workflow never calls.
Expand Down Expand Up @@ -99,30 +99,21 @@ jobs:
fail-fast: false
matrix:
include:
# Linux glibc (manylinux_2_17 floor) — cross-compiled with zig.
- { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, zigtarget: x86_64-unknown-linux-gnu.2.17, plat: manylinux_2_17_x86_64, zig: true, native: true }
- { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, zigtarget: aarch64-unknown-linux-gnu.2.17, plat: manylinux_2_17_aarch64, zig: true, native: false }
- { os: ubuntu-latest, target: armv7-unknown-linux-gnueabihf, zigtarget: armv7-unknown-linux-gnueabihf.2.17, plat: manylinux_2_17_armv7l, zig: true, native: false }
# Linux musl / Alpine. crt-static is musl's default, and rustc
# silently *drops* cdylib output under it (a warning, not an error)
# since a fully-static binary can't also be a shared library —
# -C target-feature=-crt-static switches to dynamic linking against
# musl libc so a real cdylib gets produced.
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl, zigtarget: x86_64-unknown-linux-musl, plat: musllinux_1_2_x86_64, zig: true, native: false, rustflags: "-C target-feature=-crt-static" }
- { os: ubuntu-latest, target: aarch64-unknown-linux-musl, zigtarget: aarch64-unknown-linux-musl, plat: musllinux_1_2_aarch64, zig: true, native: false, rustflags: "-C target-feature=-crt-static" }
- { os: ubuntu-latest, target: armv7-unknown-linux-musleabihf, zigtarget: armv7-unknown-linux-musleabihf, plat: musllinux_1_2_armv7l, zig: true, native: false, rustflags: "-C target-feature=-crt-static" }
# macOS. Both build on the arm64 runner (macos-14): Apple Silicon
# runners are plentiful, while the last Intel runner (macos-13) is
# deprecated and frequently unschedulable. The Apple toolchain
# cross-links x86_64 Mach-O natively, so the Intel wheel is a cross
# build (native: false -> content-verified, not import-smoked, since
# an x86_64 lib can't be imported on the arm64 runner).
- { os: macos-14, target: x86_64-apple-darwin, plat: macosx_10_12_x86_64, zig: false, native: false, deployment: "10.12" }
- { os: macos-14, target: aarch64-apple-darwin, plat: macosx_11_0_arm64, zig: false, native: true, deployment: "11.0" }
# Windows x64 (native), x86 and arm64 (cross-compiled).
- { os: windows-latest, target: x86_64-pc-windows-msvc, plat: win_amd64, zig: false, native: true }
- { os: windows-latest, target: i686-pc-windows-msvc, plat: win32, zig: false, native: false }
- { os: windows-latest, target: aarch64-pc-windows-msvc, plat: win_arm64, zig: false, native: false }
# Linux glibc. ARM64 builds on its native runner; armv7 is tested under QEMU.
- { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, zigtarget: x86_64-unknown-linux-gnu.2.17, plat: manylinux_2_17_x86_64, zig: true, native: true, smoke: host }
- { os: ubuntu-24.04-arm, target: aarch64-unknown-linux-gnu, zigtarget: aarch64-unknown-linux-gnu.2.17, plat: manylinux_2_17_aarch64, zig: true, native: true, smoke: host }
- { os: ubuntu-latest, target: armv7-unknown-linux-gnueabihf, zigtarget: armv7-unknown-linux-gnueabihf.2.17, plat: manylinux_2_17_armv7l, zig: true, native: true, smoke: manylinux-armv7 }
# musllinux wheels are runtime-smoked in Alpine, with QEMU for armv7.
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl, zigtarget: x86_64-unknown-linux-musl, plat: musllinux_1_2_x86_64, zig: true, native: true, smoke: alpine, rustflags: "-C target-feature=-crt-static" }
- { os: ubuntu-24.04-arm, target: aarch64-unknown-linux-musl, zigtarget: aarch64-unknown-linux-musl, plat: musllinux_1_2_aarch64, zig: true, native: true, smoke: alpine, rustflags: "-C target-feature=-crt-static" }
- { os: ubuntu-latest, target: armv7-unknown-linux-musleabihf, zigtarget: armv7-unknown-linux-musleabihf, plat: musllinux_1_2_armv7l, zig: true, native: true, smoke: alpine-armv7, rustflags: "-C target-feature=-crt-static" }
# Native macOS runners cover both published architectures.
- { os: macos-15-intel, target: x86_64-apple-darwin, plat: macosx_10_12_x86_64, zig: false, native: true, smoke: host, deployment: "10.12" }
- { os: macos-14, target: aarch64-apple-darwin, plat: macosx_11_0_arm64, zig: false, native: true, smoke: host, deployment: "11.0" }
# Windows x64/ARM64 run natively; win32 uses an x86 Python.
- { os: windows-latest, target: x86_64-pc-windows-msvc, plat: win_amd64, zig: false, native: true, smoke: host }
- { os: windows-latest, target: i686-pc-windows-msvc, plat: win32, zig: false, native: true, smoke: host, python-architecture: x86 }
- { os: windows-11-arm, target: aarch64-pc-windows-msvc, plat: win_arm64, zig: false, native: true, smoke: host }
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -149,6 +140,11 @@ jobs:
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "22"
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
if: matrix.python-architecture != ''
with:
python-version: "3.12"
architecture: ${{ matrix.python-architecture }}
- name: Install JS build toolchain
run: npm ci
- name: Cross-compile the native core (zig)
Expand Down Expand Up @@ -176,29 +172,63 @@ jobs:
XY_SKIP_CARGO: "1"
XY_CARGO_TARGET: ${{ matrix.target }}
XY_WHEEL_PLATFORM: ${{ matrix.plat }}
run: uv build --wheel
run: uv build --python python --wheel
- name: Verify wheel contents
shell: bash
run: |
whl=$(ls dist/*.whl)
python scripts/verify_wheel.py "$whl" --expect-native
python scripts/verify_wheel.py "$whl" --expect-native --expect-platform "${{ matrix.plat }}" --require-symbol xy_abi_version --require-linkage
Comment thread
harsh21234i marked this conversation as resolved.
Resolved
- name: Install-size budget (<= 15 MB)
shell: bash
run: |
whl=$(ls dist/*.whl)
size=$(wc -c < "$whl" | tr -d ' ')
echo "wheel size: $size bytes ($whl)"
test "$size" -le 15728640
- name: Enable QEMU for ARMv7 runtime checks
if: matrix.smoke == 'manylinux-armv7' || matrix.smoke == 'alpine-armv7'
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0
with:
platforms: arm
- name: Verify the wheel installs and loads the native core
# Only host-arch wheels can be imported on the runner; cross-compiled
# arches (aarch64/armv7/win-arm64/win32) are content-verified instead.
if: matrix.native
if: matrix.smoke == 'host'
shell: bash
run: |
uv venv smoke
uv venv smoke --python python
uv pip install -p smoke dist/*.whl numpy anywidget "reflex>=0.9.6"
./smoke/bin/python -c "import importlib.metadata as m, reflex_xy, xy.kernels as k; assert k.BACKEND=='native', k.BACKEND; assert reflex_xy.__version__ == m.version('xy'); print('native', k.__file__)" \
|| ./smoke/Scripts/python.exe -c "import importlib.metadata as m, reflex_xy, xy.kernels as k; assert k.BACKEND=='native', k.BACKEND; assert reflex_xy.__version__ == m.version('xy'); print('native')"
if [ -f ./smoke/bin/python ]; then py=./smoke/bin/python; else py=./smoke/Scripts/python.exe; fi
"$py" scripts/wheel_smoke.py
- name: Verify ARMv7 manylinux wheel in a runtime container
if: matrix.smoke == 'manylinux-armv7'
shell: bash
run: |
docker run --rm --platform linux/arm/v7 -v "$GITHUB_WORKSPACE:/workspace" -w /workspace quay.io/pypa/manylinux2014_armv7l:latest sh -eu -c '
/opt/python/cp311-cp311/bin/python -m venv /tmp/xy-smoke
/tmp/xy-smoke/bin/pip install numpy anywidget "reflex>=0.9.6" dist/*.whl
/tmp/xy-smoke/bin/python scripts/wheel_smoke.py
'
- name: Verify musllinux wheel in Alpine runtime
if: matrix.smoke == 'alpine'
shell: bash
run: |
alpine_platform=linux/amd64
if [ "${{ matrix.plat }}" = musllinux_1_2_aarch64 ]; then alpine_platform=linux/arm64; fi
docker run --rm --platform "$alpine_platform" -v "$GITHUB_WORKSPACE:/workspace" -w /workspace alpine:3.22 sh -eu -c '
apk add --no-cache python3 py3-numpy py3-pip
python3 -m venv --system-site-packages /tmp/xy-smoke
/tmp/xy-smoke/bin/pip install anywidget "reflex>=0.9.6" dist/*.whl
/tmp/xy-smoke/bin/python scripts/wheel_smoke.py
'
- name: Verify armv7 musllinux wheel in Alpine runtime
if: matrix.smoke == 'alpine-armv7'
shell: bash
run: |
docker run --rm --platform linux/arm/v7 -v "$GITHUB_WORKSPACE:/workspace" -w /workspace alpine:3.22 sh -eu -c '
apk add --no-cache python3 py3-numpy py3-pip
python3 -m venv --system-site-packages /tmp/xy-smoke
/tmp/xy-smoke/bin/pip install anywidget "reflex>=0.9.6" dist/*.whl
/tmp/xy-smoke/bin/python scripts/wheel_smoke.py
'
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.artifact-prefix }}${{ matrix.plat }}
Expand Down Expand Up @@ -365,6 +395,6 @@ jobs:

# Merge the matrix output into the single artifact the gated job uploads, and
# re-verify it as a batch: `verify-dist` fails unless *every* artifact — all
# eleven wheels, the wasm wheel and the sdist — declares the version being
# eleven native wheels, the wasm wheel and the sdist — declares the version being
# released, which is what catches a build that silently fell back to the
# derived development version.
23 changes: 17 additions & 6 deletions docs/app/tests/test_docs_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -1604,17 +1604,28 @@ def test_installation_uses_uv_first_package_manager_tabs() -> None:


def test_installation_distinguishes_supported_targets_from_pypi_artifacts() -> None:
"""Do not present missing release wheels as missing platform support."""
"""Distinguish XY's supported targets from the files in the 0.0.1 upload."""
content = (DOCS_ROOT / "overview" / "installation.md").read_text(encoding="utf-8")
macos_row = next(line for line in content.splitlines() if line.startswith("| macOS |"))
glibc_row = next(line for line in content.splitlines() if "manylinux_2_17" in line)
musl_row = next(line for line in content.splitlines() if "musllinux_1_2" in line)
windows_row = next(line for line in content.splitlines() if line.startswith("| Windows |"))
wasm_row = next(line for line in content.splitlines() if line.startswith("| WebAssembly |"))

assert all(value in windows_row for value in ("`x86_64`", "`x86`", "`arm64`"))
assert "| Supported | Not included |" in windows_row
assert "`x86_64`, `arm64`" in macos_row
assert "macOS 10.12+ on Intel" in macos_row
assert "Included" in macos_row
assert "`x86_64`, `aarch64`, `armv7l`" in glibc_row
assert "Included" in glibc_row
assert "`x86_64`, `aarch64`, `armv7l`" in musl_row
assert "Included" in musl_row
assert "`x86_64`, `x86`, `arm64`" in windows_row
assert "Supported" in windows_row
Comment thread
harsh21234i marked this conversation as resolved.
Resolved
assert "Not included" in windows_row
assert "Pyodide 314" in wasm_row
assert "`wasm32` | Supported | Not in 0.0.1 (on PyPI since 0.0.3) |" in wasm_row
assert "Windows is supported by XY's native core and release pipeline." in content
assert "0.0.1 PyPI upload does not include Windows wheels" in content
assert "`wasm32`" in wasm_row
assert "Not in 0.0.1" in wasm_row
assert "Windows is supported by XY's native core and release pipeline" in content
assert "runtime-verified WebAssembly wheel" in content
assert "`pyemscripten_2026_0_wasm32` platform" in content
assert "%pip install xy" in content
Expand Down
1 change: 1 addition & 0 deletions news/473.misc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Validate native wheel ABI, linkage and platform contracts, including normalized numeric development versions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ release-timezone = "America/Los_Angeles"
tag-prefix = "v"

# `xy` cannot be built by `uv build` on one runner: it publishes eleven
# cross-compiled platform wheels, a runtime-verified PyEmscripten wheel and an
# runtime-verified native platform wheels, a runtime-verified PyEmscripten wheel and an
# sdist, each needing its own operating system or toolchain. So the build is
# delegated to a workflow this repository owns, and the pipeline keeps
# everything either side of it — same changelog detection, same version, same
Expand Down
11 changes: 7 additions & 4 deletions python/xy/kernels.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
except ImportError as err: # pragma: no cover - platform-dependent
raise ImportError(
"xy requires its native Rust core, which could not be loaded "
f"({err}). Prebuilt wheels cover Linux glibc and musl (x86-64, aarch64, "
"armv7), macOS (x86-64, Apple Silicon), and Windows (x86, x64, arm64); "
"on those platforms `pip install xy` needs no toolchain. On any "
"other platform, install a Rust toolchain (https://rustup.rs) and "
f"({err}). Native wheels cover Linux glibc and musl/Alpine "
"(x86-64, aarch64, and armv7), macOS Intel (10.12+) and Apple Silicon "
"(11+), and Windows x86, x64, and ARM64. Pyodide 314 has a "
"runtime-verified Emscripten wheel. Those installs need no toolchain. "
"On other platforms, "
"install a Rust toolchain "
"(https://rustup.rs) and "
"reinstall from source (or run `cargo build --release`)."
) from err

Expand Down
Loading
Loading