Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate externally passed Rust toolchain identifiers #1817

Merged
merged 4 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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)
- Fix "chain configuration not found" error (Rust 1.79) - [#1821](https://github.com/paritytech/cargo-contract/pull/1821)
- Validate externally passed Rust toolchain identifiers - [#1817](https://github.com/paritytech/cargo-contract/pull/1817)

## [5.0.0-alpha]

Expand Down
1 change: 1 addition & 0 deletions crates/cargo-contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.133"
serde = { version = "1.0.202", default-features = false, features = ["derive"] }
url = { version = "2.5.3", features = ["serde"] }
Expand Down
76 changes: 68 additions & 8 deletions crates/cargo-contract/src/cmd/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use contract_metadata::{
ContractMetadata,
};

use regex::Regex;
use std::{
fs::File,
path::PathBuf,
Expand Down Expand Up @@ -196,12 +197,17 @@ 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\
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;
Expand All @@ -214,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,
Expand Down Expand Up @@ -325,3 +332,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());
}
}
Loading