ci(release): ship licence texts and third-party notices; link self_encryption only with test-utils - #243
Conversation
The default `webrtc-direct` feature enabled `dep:self_encryption`, but the only code that calls it is `Devnet::publish_public_file`, which is compiled only with `test-utils` (it seeds public files for the browser devnet tests). Release builds therefore compiled self_encryption without using it, and the crate appeared in the dependency graph of every shipped binary. The published self_encryption releases are GPL-3.0 with a linking exception, so licence scanners report it against ant-node even though no code reaches the binary. Move the optional dependency to `test-utils`. Default and release builds no longer resolve self_encryption on any release target; `test-utils` builds and the five-node browser devnet test that self-encrypts a file are unchanged. No public API changes: the one function that uses the crate already required `test-utils`.
Release archives contained only the binary and bootstrap_peers.toml. The binary statically links several hundred third-party crates and some bundled C libraries whose licences (MIT, BSD, ISC, Apache-2.0, MPL-2.0, OpenLDAP and others) require their copyright and licence notices to accompany binary redistribution, and the archives did not carry ant-node's own licence files. scripts/third_party_notices/generate.py builds THIRD-PARTY-NOTICES.txt from Cargo.lock for one or more targets. It takes the packages `cargo tree` resolves (normal and build dependencies, so build tools are listed too), matches each to exactly one `cargo metadata` package, and for each: - reproduces, unaltered, every licence, copyright, notice, authors, patents, credits and third-party file the crate ships at any depth, printing identical texts once, and names the crate's exact crates.io source archive, which is also how source is offered where a licence requires it (MPL-2.0); - checks the declared licence against the policy in config.toml and records the licence it is redistributed under, which must be allowed and whose text must be identified in one of the crate's own licence files (those of bundled components do not count); - when a crate ships no such files, or none with that licence's text, takes them from its repository at the commit recorded in the crate (or Cargo's checkout, for a git dependency), and failing that from a reviewed, version-pinned config entry with a checksummed canonical text (saorsa-pqc, siphasher, lmdb-master-sys and five macOS objc2 crates today); - requires a reviewed config entry for any crate that may contain native code: one that ships C, C++, Objective-C, CUDA or assembly sources or prebuilt libraries, builds with cc/cmake/nasm, declares `links`, or is a `*-src` crate (LMDB under the OpenLDAP Public License 2.8, mimalloc, zstd, bzip2, XZ Utils, AWS-LC, ring, BLAKE3, and a few build tools and test fixtures). Any gap fails generation. For the statically linked Linux builds it also appends musl's COPYRIGHT for the musl release the building rustc uses: the version is read from Rust's own build scripts at that rustc's commit, and the text from that musl release tarball. Each release build job generates the notices for its own target and puts them in the archive with LICENSE-MIT, LICENSE-APACHE and RUST-STD-COPYRIGHT.html, the Rust standard library's notices copied from the toolchain that built the binary. The signed Windows archive is repackaged with the same files. The upgrade path and the client's node installer extract the binary by name, so the extra entries do not affect them. CI generates the notices for all release targets on every pull request.
afd05bb to
638a5b5
Compare
|
Reviewed as part of the V2-1385 sweep. This is the strongest PR in the set, and it closes two sub-issues (V2-1390, V2-1391). On the
So moving On the notices (V2-1391) — notices are generated per target, and the archives now carry them with The config does the work the issue asked for on the C code Cargo metadata hides — LMDB under OpenLDAP 2.8, mimalloc, zstd (with a clear note on why The part that isn't in either issue, and is the most valuable thing here: because Two notes for later, neither blocking:
Approving. |
jacderida
left a comment
There was a problem hiding this comment.
Verified the self_encryption call sites were already gated on both features, so the Cargo change moves no code. The CI notices job doubles as a standing GPL guard.
Linear issue
Closes V2-1390
Closes V2-1391
Risk tier
No node behaviour changes. One optional dependency moves between Cargo features, so the default dependency graph loses a crate no release code calls, and the release workflow adds licence files to the archives. Reviewers may prefer to raise the tier because archive contents change.
Compatibility
Devnet::publish_public_file, the only code that uses self_encryption, already requiredtest-utils; enablingtest-utilsnow also pulls in self_encryption. Release archives gainLICENSE-MIT,LICENSE-APACHE,THIRD-PARTY-NOTICES.txtandRUST-STD-COPYRIGHT.html; the auto-upgrade extractor (src/upgrade/apply.rs) and ant-client's node installer pick the binary by file name and skip other entries, so nodes and clients upgrading to these archives are unaffected.Semver impact
Test evidence
Two commits.
1. self_encryption only with
test-utils. The defaultwebrtc-directfeature enableddep:self_encryption, but every use is insideDevnet::publish_public_file(#[cfg(all(feature = "webrtc-direct", feature = "test-utils"))]) and thetest-utils-gated parts oftests/webrtc_direct_devnet.rs. Release builds therefore compiled a GPL-3.0 crate (published self_encryption releases carry a linking exception) that no code called, and licence scanners listed it against every shipped binary.cargo tree -e normal -i self_encryption --target <t>with default features finds no match on the release targets; with--features test-utilsit resolvesself_encryption v0.36.0.cargo clippy --all-targets --all-features -- -D warnings(the CI command),cargo fmt --checkandRUSTDOCFLAGS=-D warnings cargo doc --no-depspass. Library and binaries compile for default, no-default, no-default +webrtc-direct, no-default +test-utils, no-default + both,test-utilsand all features. (--all-targetswith no-default +test-utilsfails intests/e2eon a missingtracing_subscriber, identically on unmodifiedmain.)cargo test --test webrtc_direct_devnet: 3 passed with default features, 6 with--features test-utils, and the ignored five-node test that self-encrypts a file passed against a local Anvil.2. Licence texts and third-party notices in release archives. Archives held only the binary and
bootstrap_peers.toml, while the binary statically links several hundred third-party crates and bundled C libraries whose licences require their notices in binary redistribution.scripts/third_party_notices/generate.py(Python 3.11+, standard library only) buildsTHIRD-PARTY-NOTICES.txtfromCargo.lockfor a target. It takes the packagescargo treeresolves (normal and build dependencies, so build tools are listed too), matches each to exactly onecargo metadatapackage by source, and reproduces unaltered every licence, copyright, notice, authors, patents, credits and third-party file each crate ships at any depth, identical texts once, with each crate's exact crates.io source archive as its Source link.config.tomllists the licences the release may redistribute under. Each crate's SPDX expression is parsed; the notice records the licence it is redistributed under, which must be allowed and whose text must be identified in one of the crate's own licence files (licence files of bundled components do not count). Gaps fail generation: no licence text, an unreviewed licence, an ambiguous package, or a crate that may contain native code (C, C++, Objective-C, CUDA or assembly sources, prebuilt libraries, a cc/cmake/nasm build dependency, alinkskey, or a*-srccrate) without a reviewed entry..minimax/folder with .NET DLLs (removed in its own PR); nothing from it is compiled.rustcuses: the version is read from rust-lang/rust'ssrc/ci/docker/scripts/musl.shat that rustc's commit, and the text from that musl release tarball (musl 1.2.5 for Rust 1.98). Each build job also copies the toolchain's own Rust standard library notices (share/doc/rust/COPYRIGHT-library.html) into the archive asRUST-STD-COPYRIGHT.html.LICENSE-MIT,LICENSE-APACHEandRUST-STD-COPYRIGHT.html; the Windows signing job repackages the same files and fails if any is missing. CI generates the notices for all five targets on every pull request.Copyrightline in every crate's licence files against the output found none missing on any target. An earlier attempt with cargo-about replaced 85 crates' licence files with generic templates (Copyright (c) <year> <copyright holders>), which is why this uses a verbatim generator. Workflow YAML parses; archive commands were exercised locally with a placeholder binary. The release workflow itself only runs on a tag.attohttpc,option-ext).New dependency
none (the generator is a standard-library Python script run in CI;
actions/setup-pythonpins Python 3.12 in the release build jobs)ADR
n/a
Mitigation / rollback
Revert either commit; neither touches runtime code, and the release workflow returns to the previous archive contents.