Skip to content

feat(bindings-py): manylinux wheel CI for Linux x86_64 + aarch64 (phase 7/9) #271

@dekobon

Description

@dekobon

Parent

Part of #103 — Python bindings via PyO3 / maturin.

Depends on the crate-skeleton sub-issue and ideally the tooling
sub-issue (so wheels are built from lint-clean source).

Status

Landed in 942f231 on 2026-05-23. See the in-thread comment
("Implementation note: manylinux wheel CI landed") for the
deviation rationale (native ARM, abi3 default, attestations) and
the action-SHA bibliography. The workflow file is
.github/workflows/python-wheels.yml.

One-time PyPI setup (Trusted Publisher + pypi GitHub
Environment) is documented in RELEASING.md
"Python wheels (PyPI) → One-time PyPI setup". It must be
completed before the first v* tag triggers a publish.

Goal

Build and publish manylinux wheels for big-code-analysis from CI so
target environments (no gcc, no cargo) can pip install.

Scope

Wheel matrix (v1)

  • Linux x86_64 — manylinux_2_28 (or whatever maturin-action's
    current default is; pin it explicitly).
  • Linux aarch64 — same manylinux profile, cross-compiled.
  • Python: 3.12, 3.13. Add 3.14 once it ships if the release lines up.
  • ABI: build as abi3 (limited-API) where PyO3 supports it for our
    feature set; falls back to per-version wheels otherwise. Document
    the decision in the workflow file.

macOS and Windows are explicitly out of scope (#103 lists them under
"Out of scope (track separately)"). Open follow-up issues only when
there is concrete demand.

Build workflow

.github/workflows/python-wheels.yml:

  • Triggers:
    • push to main for release branches / tags (v*) only —
      no wheel build on every commit.
    • Manual workflow_dispatch for ad-hoc test builds.
    • pull_request with a path filter on big-code-analysis-py/**
      AND a python-wheels label — keeps PR-time cost opt-in.
  • Jobs:
    • linux-x86_64PyO3/maturin-action@v1 with target = x86_64-unknown-linux-gnu, manylinux = 2_28,
      args = "--release --strip --out dist".
    • linux-aarch64 — same with target = aarch64-unknown-linux-gnu. Implemented with the native
      ubuntu-24.04-arm runner instead of QEMU
      — see the in-
      thread comment for the rationale (GA for private repos
      Jan 2026, ~10× faster than QEMU).
    • sdistmaturin sdist so PyPI has a source distribution as
      well (even though we mark wheels as required, the sdist is
      useful for niche architectures and reproducibility).
    • smoke-test — pulls the built wheel for the runner arch and
      runs a minimal python -c "import big_code_analysis; big_code_analysis.analyze(...)" to catch dynamic-linker /
      missing-symbol failures before publish. Runs on both Python
      3.12 and 3.13 so the abi3 forward-compat claim is verified.
    • publish — gated on a tag matching v* and the pypi
      environment with PyPI trusted-publisher OIDC. No PyPI API
      tokens — uses pypa/gh-action-pypi-publish@v1.14.0.

Reproducibility / security

  • Pin every action by SHA, not by tag (the repo already does this
    for the Rust workflows — match the style).
  • Cache cargo and maturin builds keyed off Cargo.lock +
    pyproject.toml.
  • Sign artefacts with PEP 740 Sigstore attestations, generated
    automatically by gh-action-pypi-publish@v1.14.0
    (replaces the
    separate sigstore/gh-action-sigstore-python step in the
    original spec — see in-thread comment).
  • cargo deny runs in ci.yml already; pip-audit runs in the
    smoke-test job as the wheel-side equivalent.

Release coordination

  • ✅ Updated RELEASING.md with the Python release procedure:
    • When to bump big-code-analysis-py/pyproject.toml version
      (it inherits from [workspace.package]).
    • The fact that wheels are built only on tags.
    • How to test a release candidate via workflow_dispatch.
    • PyPI Trusted Publisher one-time setup.
  • packaging/README.md is binary-only; the Python wheel
    pipeline is cross-referenced from RELEASING.md directly,
    not duplicated under packaging/.

Documentation

Acceptance criteria

  • ✅ Manually triggering python-wheels.yml on a feature branch
    produces uploadable wheels for both Linux x86_64 and aarch64,
    Python 3.12 + 3.13. (Single abi3 wheel per arch covers both
    Python versions; smoke-test verifies both 3.12 and 3.13 load
    the same wheel.)
  • ✅ The smoke-test job successfully imports and analyses a
    fixture on the built wheel.
  • ⏭️ Tagging vX.Y.Z on main publishes those wheels to PyPI
    via trusted-publisher OIDC. (Cannot verify until the first
    tag — the one-time PyPI setup in RELEASING.md must be
    completed first. The publish job is gated on
    github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
    so PR / workflow_dispatch runs validate the matrix without
    uploading.)
  • ✅ No PyPI tokens stored as repo secrets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions