From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id BC5C21581FB for ; Mon, 2 Dec 2024 08:46:22 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 542F0E077F; Mon, 2 Dec 2024 08:46:21 +0000 (UTC) Received: from smtp.gentoo.org (mail.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 9F0D2E077C for ; Mon, 2 Dec 2024 08:46:19 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id BFFE433BF08 for ; Mon, 2 Dec 2024 08:46:18 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id C13D11E15 for ; Mon, 2 Dec 2024 08:46:16 +0000 (UTC) From: "Matt Jolly" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Matt Jolly" Message-ID: <1733126057.12a24a054fb00f9b7706348b0b2de3f2f85e0b54.kangie@gentoo> Subject: [gentoo-commits] repo/gentoo:master commit in: eclass/ X-VCS-Repository: repo/gentoo X-VCS-Files: eclass/cargo.eclass X-VCS-Directories: eclass/ X-VCS-Committer: kangie X-VCS-Committer-Name: Matt Jolly X-VCS-Revision: 12a24a054fb00f9b7706348b0b2de3f2f85e0b54 X-VCS-Branch: master Date: Mon, 2 Dec 2024 08:46:16 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 1cb4ab88-8934-4496-a275-04771d4c7690 X-Archives-Hash: c05eb17cbda74b788d036ceee91e5559 commit: 12a24a054fb00f9b7706348b0b2de3f2f85e0b54 Author: Matt Jolly gentoo org> AuthorDate: Thu Nov 21 14:08:40 2024 +0000 Commit: Matt Jolly gentoo org> CommitDate: Mon Dec 2 07:54:17 2024 +0000 URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=12a24a05 cargo.eclass: add trivial crate overrides Updating vulnerable (or otherwise outdated) crates in Rust ebuilds is painful. Generally speaking, there are 5 options: - Run `cargo update` to fetch new versions from the web. This is obviously not suitable for use in Portage. - Patch the software via Portage to accept a non-vulnerable crate. This is a reasonable option when the package is not too complex but still requires significant developer effort and some familiarity with Cargo. In the case of complex patches this may not be feasible, or require the generation of a dependency tarball. - [patch] the source (repository) in Cargo.toml. This enables the targeting of specific crates, but does not allow the replacement of only a specific version in the depgraph. - [replace] a particular crate:version in the Cargo.toml. This enables the targeting of a particular version with an arbitrary path however the replacement crate must *have the same version* as the one being overridden. - `paths = [...]` overrides: pass an array of paths to directories that contain a Cargo.toml. Cargo will override any crate with the same package name arbitrarily, ignoring the lock file and versions; typically used for testing. Is applied via ${CARGO_HOME}/config.toml (i.e. globally) This commit: - Implements the `paths` overrides, which will work even when Cargo is configured to use a vendored directory. This is not a 'smart' replacement and care must be taken to ensure that all versions of the crate in use are compatible (`cargo tree` will help). - Provides a helper which runs `cargo --update --offline` against ${ECARGO_VENDOR} (where ${CRATES} are unpacked). This enables the replacement of vulnerable versions in ${CRATES}. It is up to the consumer to ensure that only the desired crates are being replaced and that package behaviour does not change. Resources: - https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html - https://github.com/rust-lang/cargo/issues/3308 Signed-off-by: Matt Jolly gentoo.org> eclass/cargo.eclass | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/eclass/cargo.eclass b/eclass/cargo.eclass index 5a3820267544..02b048732f7f 100644 --- a/eclass/cargo.eclass +++ b/eclass/cargo.eclass @@ -7,6 +7,7 @@ # @AUTHOR: # Doug Goldstein # Georgy Yakovlev +# Matt Jolly # @SUPPORTED_EAPIS: 8 # @PROVIDES: rust # @BLURB: common functions and variables for cargo builds @@ -51,6 +52,10 @@ case ${EAPI} in ;; esac +if [[ -n ${CRATE_PATHS_OVERRIDE} ]]; then + CRATES="${CRATES} ${CRATE_PATHS_OVERRIDE}" +fi + inherit flag-o-matic multiprocessing rust rust-toolchain toolchain-funcs IUSE="${IUSE} debug" @@ -81,6 +86,41 @@ ECARGO_VENDOR="${ECARGO_HOME}/gentoo" # SRC_URI="${CARGO_CRATE_URIS}" # @CODE +# @ECLASS_VARIABLE: CRATE_PATHS_OVERRIDE +# @DEFAULT_UNSET +# @PRE_INHERIT +# @DESCRIPTION: +# Bash string containing crates that will be used to override +# dependencies via generated `paths = ['/path/to/crate']` configuration. +# This is not "smart", _all crates_ which match the `Cargo.toml` +# for a given crate/path will be overridden, ignoring lockfiles, +# version constraints, etc. +# +# This should be used as a last resort where (e.g.) you are +# bootstrapping Rust and need to override a vendored crate +# with a newer version, and all versions in use are compatible. +# +# Crate names and versions must be separated by a `@`; +# multiple crates are separated by a space or newline. +# Crates in CRATE_PATHS_OVERRIDE are implicitly added to CRATES; +# they do not need to be listed. +# +# Example: +# @CODE +# CRATES=" +# foo@1.2.3 +# " +# +# CRATE_PATHS_OVERRIDE=" +# openssl@0.10.35 +# openssl-sys@0.9.65 +# " +# +# inherit cargo +# ... +# SRC_URI="${CARGO_CRATE_URIS}" +# @CODE + # @ECLASS_VARIABLE: GIT_CRATES # @DEFAULT_UNSET # @PRE_INHERIT @@ -277,6 +317,26 @@ cargo_crate_uris() { echo "${CARGO_CRATE_URIS}" } +# @FUNCTION: _cargo_gen_override_paths_config +# @INTERNAL +# @DESCRIPTION: +# Generate the TOML content for overriding crates globally using the package manager. +# This is called from within cargo_gen_config to insert the appropriate snippet +# into the generated config.toml. Does not support git crates. +_cargo_gen_override_paths_config() { + if [[ ! ${#CRATE_PATHS_OVERRIDE[@]} -gt 0 ]]; then + return + fi + local content override path + content=( 'paths = [' ) + for override in ${CRATE_PATHS_OVERRIDE}; do + local path="${ECARGO_VENDOR}/${override//@/-}" + content+=( "'${path}'," ) + done + content+=( ']' ) + printf "%s\n" "${content[@]}" +} + # @FUNCTION: cargo_gen_config # @DESCRIPTION: # Generate the $CARGO_HOME/config.toml necessary to use our local registry and settings. @@ -293,6 +353,8 @@ cargo_gen_config() { mkdir -p "${ECARGO_HOME}" || die cat > "${ECARGO_HOME}/config.toml" <<- _EOF_ || die "Failed to create cargo config" + $(_cargo_gen_override_paths_config) + [source.gentoo] directory = "${ECARGO_VENDOR}" @@ -311,6 +373,7 @@ cargo_gen_config() { verbose = true $([[ "${NOCOLOR}" = true || "${NOCOLOR}" = yes ]] && echo "color = 'never'") $(_cargo_gen_git_config) + _EOF_ export CARGO_HOME="${ECARGO_HOME}" @@ -358,6 +421,37 @@ cargo_target_dir() { echo "${CARGO_TARGET_DIR:-target}/$(rust_abi)/$(usex debug debug release)" } +# @FUNCTION: cargo_update_crates +# @USAGE: +# @DESCRIPTION: +# Helper function to call `cargo update --offline` with the given Cargo.toml. +# This will update Cargo.{toml,lock}. This should provide a straightforward +# approach to updating vulnerable crates in a package. +# +# To use: replace any vulnerable crates in ${CRATES} with updated (and compatible) +# versions, then call `cargo_update_crates` in src_prepare. If Cargo.toml is not +# in the root of ${S}, pass the path to the Cargo.toml as the first argument. +# It is up to the ebuild to ensure that the updated crates are compatible with the +# package and that no unexpected breakage occurs. +cargo_update_crates () { + debug-print-function ${FUNCNAME} "$@" + + if [[ -z ${CARGO} ]]; then + die "CARGO is not set; was rust_pkg_setup run?" + fi + + local path=${1:-"${S}/Cargo.toml"} + if [[ $# -gt 1 ]]; then + die "Usage: cargo_update_crates [path_to_Cargo.toml]" + fi + [[ -f ${path} ]] || die "${path} does not exist" + + set -- "${CARGO}" update --offline --manifest-path "${path}" + einfo "${@}" + # This is overkill (we're not using rustflags (etc) here) but it's safe. + cargo_env "${@}" || die "Failed to update crates" +} + # @FUNCTION: cargo_src_unpack # @DESCRIPTION: # Unpacks the package and the cargo registry.