Repository navigation
ci(release): build the Binding RC Linux wheel and addon with maturin and napi - #1651
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository: CurateLabs/graphforge/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Independent integration review at cbe3459 found two merge blockers:
Both were independently reproduced from the immutable PR head. Linux wheel/addon execution evidence remains required by #1645; the review does not claim a green Binding RC dispatch. |
|
Follow-up review at Two findings remain before integration:
The first #1645 criterion requests a dispatch on the PR head, while |
…and napi Binding RC built the Linux Python wheel and the Linux x64 Node addon with Bazel through scripts/ci/binding_rc_bazel_native.py. Both now use the same maturin and napi path as macOS and Windows (ADR 0048, decision item 4). - Python: every lane runs maturin-action. Linux builds in the manylinux2014 container with `--compatibility manylinux_2_17`, so maturin's audit refuses a wheel that needs a newer glibc rather than relabelling it. The Bazel-built wheel was tagged manylinux_2_17 but links GLIBC_2.39 (auditwheel: consistent only with manylinux_2_39_x86_64). Each lane now asserts its declared wheel tag in the file name and in dist-info/WHEEL. - Node: the Linux x64 lane runs `napi build`, which also fixes the Bazel addon reporting version() == "0.0.0" that failed every recent RC assembly in the offline rehearsal. The lane uploads the napi-generated index.js/index.d.ts its native contract executed, and the release assembly packs exactly those instead of synthesizing loaders. - Retire binding_rc_bazel_native.py and its test coverage; the workflow has no Bazel step and the policy test asserts that. Closes #1645 Part of #1618 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…linux 2_17 once A local build of the exact maturin-action command in the manylinux2014 image names the wheel cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64 and writes both Tag: lines. Declare that tag set and check the expanded set, and let the action's manylinux input supply the single --manylinux 2_17 flag. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Match the other Binding RC same-run downloads (pattern + merge-multiple). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e Linux RC sticky disk The Linux x64 Node lane uploads the napi loaders it tested and the assembly downloads them by exact-run pattern; the retired Python sticky mount leaves one binding-rc-linux-rust disk. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
c4128bd to
26b131e
Compare
|
Reviewed author head 26b131e: the loader counters, sticky census and existing allowance now pass policy, but the allowance still accepts addon bytes under the loader name, a generic dist destination and an unrelated repository override. I reproduced those against the actual workflow. A bounded additive correction is prepared in my isolated checkout, commit 3076314: it binds the loader producer to index.js/index.d.ts, binds the consumer to the current run and exact destination, and removes the accidental admission lock. All relevant static checks and negative fixtures pass. I will preserve the running independent CI lanes and push the correction after they finish; no external author worktree was changed. |
|
The additive artifact-policy correction is now pushed at Binding RC dispatch 36655614470 executes this PR workflow revision, while preserving the current-main certification guard: its requested native-source SHA is The current body inaccurately says the PR workflow cannot be dispatched at all: it can run with the main source SHA as above. Remaining assembler/platform-parity retirement is already included in #1646, so canonical #1618 stays open until that removal is merged; no remaining Bazel source is being declared retired here. |
Closes #1645
Part of #1618
What changes
Binding RC now builds the Linux Python wheel with maturin and the Linux x64 Node addon with napi, the same way macOS and Windows already do (ADR 0048, decision item 4). The workflow has no Bazel step left.
PyO3/maturin-action. The Linux lane usesmanylinux: "2_17", which runs the build in the manylinux2014 (glibc 2.17) container and passes--manylinux 2_17. maturin's audit then refuses the wheel if any symbol needs a newer glibc. A new step, Require the declared wheel platform tag, checks that each lane's wheel file name and the expandeddist-info/WHEELTag:lines exactly match the tag set declared in the matrix.napi build --platform --release --target x86_64-unknown-linux-gnu. It uploads the napi-generatedindex.jsandindex.d.tsthat its native contract ran against. The release assembly packs exactly those files. Before, it synthesized loaders withbinding_rc_bazel_native.py emit-node-loaders.scripts/ci/binding_rc_bazel_native.pyis deleted, along with its coverage intest-binding-release-candidate.py. That test now asserts that the workflow contains nobazelat all..github/workflows/README.mdis updated to match.Defects found in the Bazel-built RC artifacts (run 36638329649, main
fcb3d9e6)cp310-abi3-manylinux_2_17_x86_64, but its.solinksGLIBC_2.39(built on the Ubuntu 24.04 runner). The Bazel assembler wrote the tag without auditing the binary.auditwheel showreports: consistent with the following platform tag: "manylinux_2_39_x86_64".version() == "0.0.0". This is why the last RC assembly failed in the offline rehearsal:clean Node/native consumer loaded version '0.0.0', expected 0.5.2. A napi build takes the version from Cargo.Evidence (local, pre-merge)
Wheel. I ran maturin-action v1.51.0's container script (maturin 1.15.0, Rust 1.96.0) in the
quay.io/pypa/manylinux2014_x86_64rootfs, image created 2026-09-26, asmaturin build --manylinux 2_17 --release --manifest-path crates/graphforge-bindings-py/Cargo.toml. This is the argument order the action produces.graphforge-0.5.2-cp310-abi3-manylinux_2_17_x86_64.whlgraphforge-0.5.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whlWHEELTagcp310-abi3-manylinux_2_17_x86_64cp310-abi3-manylinux_2_17_x86_64andcp310-abi3-manylinux2014_x86_64assemble_bazel_binding_packages.pymaturin (1.15.0)(the same as the macOS and Windows RC wheels)auditwheel showmanylinux_2_39_x86_64manylinux_2_17_x86_64METADATAdist-info/sboms/graphforge-bindings-py.cyclonedx.json(the macOS wheel has it too)graphforge.__version__The platform tag stays
manylinux_2_17_x86_64. maturin also writes the equivalent PEP 600 legacy aliasmanylinux2014_x86_64, so the file name changes. Nothing in the repo matches the Linux wheel file name exactly. The RC Python contract (smoke.py,gil_release.py,multi_ontology.py,non_cypher_release.py --classification-only) passes on the local wheel.The guard rejects a non-compliant wheel.
maturin build --manylinux 2_17 --releaseon this Ubuntu 26.04 host (glibc 2.43) fails:Your library is not manylinux_2_17 (aka manylinux2014) compliant because of the presence of too-recent versioned symbols.The tag-check step, run from the workflow YAML: it passes the local manylinux wheel and the maturin-built macOS (
cp310-abi3-macosx_11_0_arm64) and Windows (cp310-abi3-win_amd64) wheels from run 36638329649. It rejects the Bazel Linux wheel.Addon. I ran
napi build --platform --release --target x86_64-unknown-linux-gnuon the host.graphforge.linux-x64-gnu.node(x86-64 ELF). It needs the same libraries as the Bazel addon (libgcc_s,libm,libc,ld-linux-x86-64).version()returns0.5.2. The Bazel addon from run 36638329649 returns0.0.0.test:smoke(8/8), andnon-cypher-release-parity+async-errors+export-surface(11/11). The addon,index.jsandindex.d.tshashes are unchanged after the tests.napi create-npm-dirs,napi artifactsandvalidate-napi-artifacts.py, and packed withnpm pack. The main tarball containspackage/index.jsandpackage/index.d.ts. A cleannpm installof the main andlinux-x64-gnutarballs loadsversion() == "0.5.2"through the named ESM import.napi create-npm-dirs, the same as before:@curatelabs/graphforge-linux-x64-gnu,os: [linux],cpu: [x64],libc: [glibc],main: graphforge.linux-x64-gnu.node.blacksmith-4vcpu-ubuntu-2404runner, so both need glibc 2.39. My local napi build needs 2.43 only because this host is newer. See the follow-up note below.Gates:
make workflow-lint(actionlint 1.7.12),python3 scripts/ci/workflow_policy.py,python3 scripts/ci/test-binding-release-candidate.py,pytest scripts/ci/test-release-workflows.py(15 passed),test-publish-track.py,test-release-certification.py,test-release-candidate.py,test-release-rehearsal.py,tests/unit/test_publish_dry_run.py(9 passed), andmake pre-push-fastall pass. I mutation-tested the new policy assertions. Each of these mutations madetest-binding-release-candidate.pyfail: removing the compatibility input, dropping the tag-step, changing the declared tag, removingpublishes_loaders, gating the napi build off Linux, disabling the ownership reclaim, and adding a Bazel step.Dispatch qualification
Binding RC run 36655614470 runs this PR workflow at
307631419d7a8aa35a011000bd6e67f502c4eff6. Its unchanged current-main guard selects native source471c16ff01daa1b6d76f3e654d59796d8fc096c8. All eight target lanes, the aggregate, release assembly and offline rehearsal passed. Workflow and native-source identities are separate. The PR changes no native crate, Cargo manifest/lock, package manifest or dependency-lock inputs relative to that source. Publication certification of a later merged source requires its own ordinary SHA-bound evidence.Independent inspection of the actual downloaded Linux artifacts verifies:
cp310-abi3cp310-abi3manylinux_2_17_x86_64manylinux2014_x86_64aliasversion()The wheel and addon SHA-256 digests match the passed aggregate report. The exact-run tested loader digests are retained with the comparison results. The assembled Linux x64 package retains linux/x64/glibc metadata and the declared native filename. Its native binary and the main package loaders match the tested artifacts exactly by SHA-256. The offline rehearsal passed clean Python, Node, CLI/skills and Rust consumers, with zero registry writes. Full results and digests are posted on #1645.
Storage policy
The policy permits only the
binding-rc-node-loaders-${{ github.run_id }}transfer with exactlyindex.jsandindex.d.ts, its declared upload and${{ runner.temp }}/node-loadersdestination, and current-run/default-repository download semantics. Eighteen negative fixtures reject native binaries, directory/glob payloads, changed destinations and cross-run/repository overrides. The Linux sticky-disk expectation is one. The accidentally tracked admission lock is removed.Remaining retirement
scripts/ci/assemble_bazel_binding_packages.pyand its test are kept becausetest.ymlstill runs the test. They go in ci: make Cargo with nextest the CI Gate Rust lane and retire the Bazel jobs (#1618) #1644/build: remove Bazel build descriptions, tooling, and docs (#1618) #1646. This deviates from scope item 2 of the issue.tools/bazel/release/release_platforms.jsonis read only by the Bazel parity tooling (cargo-bazel-parity-check.pyand its test), so its retirement belongs to build: remove Bazel build descriptions, tooling, and docs (#1618) #1646.crates/graphforge-bindings-node/napi-export-surface.jsonexisted only to feed the Bazel loader synthesis. Its test still checks the napi loader, so I left it for build: remove Bazel build descriptions, tooling, and docs (#1618) #1646.--use-napi-cross). This PR does not change it.🤖 Generated with Claude Code