From ad7eaf8a810b4af87f4e519dce8c64a3047a0bd3 Mon Sep 17 00:00:00 2001 From: Michael Mueller <mich@elmueller.net> Date: Thu, 14 Nov 2024 14:37:38 +0100 Subject: [PATCH 1/3] Validate toolchains passed from external are valid --- crates/cargo-contract/Cargo.toml | 1 + crates/cargo-contract/src/cmd/verify.rs | 57 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml index 23b998883..bc88303ca 100644 --- a/crates/cargo-contract/Cargo.toml +++ b/crates/cargo-contract/Cargo.toml @@ -31,6 +31,7 @@ tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } which = "7.0.0" colored = "2.1.0" +regex = "1" serde_json = "1.0.117" serde = { version = "1.0.202", default-features = false, features = ["derive"] } url = { version = "2.5.3", features = ["serde"] } diff --git a/crates/cargo-contract/src/cmd/verify.rs b/crates/cargo-contract/src/cmd/verify.rs index d7d9fc9b9..8ad503882 100644 --- a/crates/cargo-contract/src/cmd/verify.rs +++ b/crates/cargo-contract/src/cmd/verify.rs @@ -37,6 +37,7 @@ use contract_metadata::{ ContractMetadata, }; +use regex::Regex; use std::{ fs::File, path::PathBuf, @@ -196,6 +197,9 @@ impl VerifyCommand { let rust_toolchain = contract_build::util::rust_toolchain() .expect("`rustc` always has a version associated with it."); + validate_toolchain_name(&expected_rust_toolchain)?; + validate_toolchain_name(&rust_toolchain)?; + let rustc_matches = rust_toolchain == expected_rust_toolchain; let mismatched_rustc = format!( "\nYou are trying to `verify` a contract using the `{rust_toolchain}` toolchain.\n\ @@ -325,3 +329,56 @@ impl VerificationResult { Ok(serde_json::to_string_pretty(self)?) } } + +/// Validates that the passed `toolchain` is a valid Rust toolchain. +/// +/// # Developers Note +/// +/// Strictly speaking Rust has not yet defined rules for legal toolchain +/// names. See https://github.com/rust-lang/rustup/issues/4059 for more +/// details. +/// +/// We took a "good enough" approach and restrict valid toolchain names +/// to established ones. +fn validate_toolchain_name(toolchain: &str) -> Result<()> { + let re = Regex::new(r"^[a-zA-Z._\-0-9]+$").expect("failed creating regex"); + if re.is_match(toolchain) { + return Ok(()); + } + anyhow::bail!("Invalid toolchain name: {}", toolchain) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn valid_toolchain_names() { + assert!(validate_toolchain_name("nightly").is_ok()); + assert!(validate_toolchain_name("stable").is_ok()); + assert!(validate_toolchain_name("beta").is_ok()); + + assert!(validate_toolchain_name("nightly-2023-01-01").is_ok()); + assert!(validate_toolchain_name("beta-2024-01-02").is_ok()); + assert!(validate_toolchain_name("stable-2022-03-03").is_ok()); + + assert!(validate_toolchain_name("1.56.0").is_ok()); + assert!(validate_toolchain_name("1.70").is_ok()); + + assert!(validate_toolchain_name("1.70-aarch64-apple-darwin").is_ok()); + assert!( + validate_toolchain_name("nightly-2024-11-05-aarch64-apple-darwin").is_ok() + ); + assert!(validate_toolchain_name("stable-x86_64-unknown-linux-gnu").is_ok()); + } + + #[test] + fn invalid_toolchain_names() { + assert!(validate_toolchain_name("https://sh.rust-toolchain.rs").is_err()); + assert!(validate_toolchain_name("_ $").is_err()); + assert!(validate_toolchain_name( + "nightly', please install https://sh.rust-toolchain.rs" + ) + .is_err()); + } +} From 7ae697944b311756cf54af6832c1e96269aed0f5 Mon Sep 17 00:00:00 2001 From: Michael Mueller <mich@elmueller.net> Date: Thu, 14 Nov 2024 14:38:32 +0100 Subject: [PATCH 2/3] Improve user output formatting --- crates/cargo-contract/src/cmd/verify.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/cargo-contract/src/cmd/verify.rs b/crates/cargo-contract/src/cmd/verify.rs index 8ad503882..cf264d4cc 100644 --- a/crates/cargo-contract/src/cmd/verify.rs +++ b/crates/cargo-contract/src/cmd/verify.rs @@ -202,10 +202,12 @@ impl VerifyCommand { let rustc_matches = rust_toolchain == expected_rust_toolchain; let mismatched_rustc = format!( - "\nYou are trying to `verify` a contract using the `{rust_toolchain}` toolchain.\n\ - However, the original contract was built using `{expected_rust_toolchain}`. Please\n\ - install the correct toolchain (`rustup install {expected_rust_toolchain}`) and\n\ - re-run the `verify` command.",); + "\nYou are trying to `verify` a contract using the following toolchain:\n\ + {rust_toolchain}\n\n\ + However, the original contract was built using this one:\n\ + {expected_rust_toolchain}\n\n\ + Please install the correct toolchain and re-run the `verify` command:\n\ + rustup install {expected_rust_toolchain}"); anyhow::ensure!(rustc_matches, mismatched_rustc.bright_yellow()); let expected_cargo_contract_version = build_info.cargo_contract_version; @@ -218,10 +220,11 @@ impl VerifyCommand { cargo_contract_version == expected_cargo_contract_version; let mismatched_cargo_contract = format!( "\nYou are trying to `verify` a contract using `cargo-contract` version \ - `{cargo_contract_version}`.\n\ - However, the original contract was built using `cargo-contract` version \ - `{expected_cargo_contract_version}`.\n\ - Please install the matching version and re-run the `verify` command.", + `{cargo_contract_version}`.\n\n\ + However, the original contract was built using `cargo-contract` version \ + `{expected_cargo_contract_version}`.\n\n\ + Please install the matching version and re-run the `verify` command.\n\ + cargo install --force --locked cargo-contract --version {expected_cargo_contract_version}", ); anyhow::ensure!( cargo_contract_matches, From 5e6a44e7d1f7886189d4028332a5696aa32d821f Mon Sep 17 00:00:00 2001 From: Michael Mueller <mich@elmueller.net> Date: Thu, 14 Nov 2024 14:46:56 +0100 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f23295d..f1ad9fee6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix "chain configuration not found" error - [#1786](https://github.com/paritytech/cargo-contract/pull/1786) +- Validate externally passed Rust toolchain identifiers - [#1817](https://github.com/paritytech/cargo-contract/pull/1817) ## [5.0.0-alpha]