Repository: near/cargo-near
Pull request #339: feat: `--variant <name>` flag
Author: login: vsavchyn-dev
Created: 2025-05-08T21:20:12Z | Merged: 2025-05-16T20:21:25Z

This pull request closes #312, introducing support for custom build variants in the reproducible build process for NEAR smart contracts. It allows developers to define named build variants in `Cargo.toml` with specific configurations, enabling more flexible and customizable build setups. Key changes include updates to the documentation, enhancements to the metadata parsing logic, and modifications to the build options to support the new `--variant` flag.

### Documentation Updates:
- Added a detailed explanation in `README.md` on how to define and use custom build variants via the `--variant <name>` flag. This includes examples of configuration in `Cargo.toml` and usage instructions for the command-line interface.

### Metadata and Build Logic Enhancements:
- Introduced a new `VariantReproducibleBuild` struct to parse and handle variant-specific configurations in `Cargo.toml`.
- Added logic in the `ReproducibleBuild` struct to inject and validate variant-specific configurations, ensuring they override default settings when a variant is specified.
- Updated the `parse` method in `ReproducibleBuild` to handle optional variant names and process the corresponding variant metadata.

### Command-Line Interface and Build Options:
- Added a `variant` field to `BuildOpts` and `DockerBuildOpts` to support specifying the desired build variant via the `--variant` flag.

Linked issue #312: feat: Support features setting for reproducible builds
There are use-cases where users want to specify feature flags to compile contracts for different environments, e.g. testnet vs mainnet

UPD: See the latest proposed design for this feature in the comment below: https://github.com/near/cargo-near/issues/312#issuecomment-2754134020
Linked issue comments: user: login: dj8yfo
created_at: 2025-03-03T11:08:16Z
body: This could be done. Alternatively, one could use https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-cfg in build script depending on a value from `passed_env` in manifest, but this says it only offers limited support of features (not enabling optional dependencies and sub-features, as far as i've understood), so just appending value from --features would be a simpler/more complete way to do this.
author_association: COLLABORATOR
user: login: dj8yfo
created_at: 2025-03-03T11:21:45Z
body: The --features flag of non-reproducible command may be made repeatable with `vec_multiple_opt` interactive clap option to better mirror behaviour of plain `cargo` command
author_association: COLLABORATOR
user: login: frol
created_at: 2025-03-06T22:17:20Z
body: I don't understand how to use build-scripts when I just want to build a simple contract.
author_association: CONTRIBUTOR
user: login: dj8yfo
created_at: 2025-03-08T04:55:24Z
body: > I don't understand

Well, that was me exploring a variant of containing all build parameters, not defined in source code, to `passed_env`. But that would be more complex and not support features completely, so just re-adding previously removed --features flag will be simple.
Doing this once per flag when needed makes more sense than just bulk adding a lot of options with no specific purpose in mind
author_association: COLLABORATOR
user: login: dj8yfo
created_at: 2025-03-16T22:30:45Z
body: @frol 
This can also be done with  (inline) tables in toml:
```toml
append_flags_if_env_is_set = { "TESTNET" = ["--features", "feat"],
"MAINNET" = [] }
```

which would have the benefit of persisting the logic of how the features are applied in source code (some paper trail for debug if needed). 

and would be used for arbitrary flags without the need of passing through each needed flag from build-reproducible-wasm command.

author_association: COLLABORATOR
user: login: frol
created_at: 2025-03-26T11:49:19Z
body: @dj8yfo While features seems to be more natural to Rust devs, let's indeed explore alternatives based on the use-cases. In Rust/Cargo there is also support for "profiles" (debug, release, and custom), which are configured through toml sections (`[profile.*]`), so we may consider profile overrides for `[package.metadata.near.reproducible_build]` sections, e.g.:

```toml
[package.metadata.near.reproducible_build]
image = "sourcescan/cargo-near:0.13.5-rust-1.85.1"
image_digest = "sha256:3b0272ecdbb91465f3e7348330d7f2d031d27901f26fb25b4eaf1560a60c20f3"
passed_env = []
container_build_command = [
    "cargo",
    "near",
    "build",
    "non-reproducible-wasm",
    "--locked",
]

[package.metadata.near.reproducible_build.variant.custom-name-eg-testnet]
container_build_command = [
    "cargo",
    "near",
    "build",
    "non-reproducible-wasm",
    "--locked",
    "--features",
    "my-custom-feature-for-testnet"
]
```

And then build it as:

```
cargo near build reproducible-wasm --variant custom-name-eg-testnet
```

(I would love to find a better name for `--variant` flag, I picked it up just to not overlap with `--profile` and `--features`, but I don't particularly like it)
author_association: CONTRIBUTOR
user: login: dj8yfo
created_at: 2025-03-27T21:19:32Z
body: > profile overrides for `[package.metadata.near.reproducible_build]` sections, e.g.:

this looks better than my suggestion of 
```toml 
append_flags_if_env_is_set = { "TESTNET" = ["--features", "feat"],
"MAINNET" = [] }
```
and is more natural/easy to understand
author_association: COLLABORATOR
user: login: dj8yfo
created_at: 2025-05-09T12:34:48Z
body: > I would love to find a better name for `--variant` flag

we could call it an `--overlay`, but `--variant` is simpler to understand 
author_association: COLLABORATOR

Diff:
diff --git a/README.md b/README.md
index 948c4d70..954d222d 100644
--- a/README.md
+++ b/README.md
@@ -165,6 +165,45 @@ Additional flags for build configuration can be looked up if needed by:
 cargo near build reproducible-wasm -h      # replace `-h` with `--help` for more details
 ```
 
+#### Custom `reproducible-wasm` build using `--variant <name>` flag
+
+Beyond your `[package.metadata.near.reproducible_build]` configuration, you can
+define **named variants of build** in your `Cargo.toml` under:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.<name>]
+```
+
+It supports all the same fields as `[package.metadata.near.reproducible_build]`:
+`image`, `image_digest`, `passed_env`, and `container_build_command`.
+
+**Note that every field is optional for variant build and will override
+corresponding field in `reproducible_build`!**
+
+For example, if you declare:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.testnet-features]
+container_build_command = [
+    "cargo",
+    "near",
+    "build",
+    "non-reproducible-wasm",
+    "--locked",
+    "--features",
+    "testnet"
+]
+```
+
+in `Cargo.toml`, and then:
+
+```bash
+cargo near build reproducible-wasm --variant testnet-features
+```
+
+will use `testnet-features` version of `container_build_command`,
+instead of one defined in `[package.metadata.near.reproducible_build]`.
+
 ---
 
 ```console
diff --git a/cargo-near-build/src/near/docker_build/mod.rs b/cargo-near-build/src/near/docker_build/mod.rs
index b7e74cc4..64128768 100644
--- a/cargo-near-build/src/near/docker_build/mod.rs
+++ b/cargo-near-build/src/near/docker_build/mod.rs
@@ -34,22 +34,45 @@ pub fn run(opts: DockerBuildOpts, quiet: bool) -> eyre::Result<CompilationArtifa
         },
     )?;
 
-    let docker_build_meta = pretty_print::handle_step(
-        &format!(
-            "Parsing and validating `{}` section of contract's `Cargo.toml` ...",
-            "[package.metadata.near.reproducible_build]".magenta()
-        ),
-        || metadata::ReproducibleBuild::parse(cloned_repo.crate_metadata()),
-    )?;
+    let applied_build_meta = {
+        let docker_build_meta_parsed = pretty_print::handle_step(
+            &format!(
+                "Parsing `{}` section of contract's `Cargo.toml` ...",
+                "[package.metadata.near.reproducible_build]".magenta()
+            ),
+            || metadata::parse::ReproducibleBuild::parse(cloned_repo.crate_metadata()),
+        )?;
+
+        let section_name = metadata::section_name(opts.variant.as_ref());
+        pretty_print::handle_step(
+            &format!(
+                "Applying and validating `{}` section of contract's `Cargo.toml` ...",
+                section_name.magenta()
+            ),
+            || {
+                let applied_variant =
+                    docker_build_meta_parsed.apply_variant_or_default(opts.variant.as_deref())?;
+                applied_variant.validate()?;
+                println!();
+                println!(
+                    "{} {}",
+                    "applied reproducible build metadata:".green(),
+                    applied_variant
+                );
+                Ok(applied_variant)
+            },
+        )?
+    };
+
     let near_sdk_support =
         warn_versions_upgrades::suggest_near_sdk_checks(cloned_repo.crate_metadata());
     warn_versions_upgrades::suggest_cargo_near_build_checks(
         cloned_repo.crate_metadata(),
-        &docker_build_meta,
+        &applied_build_meta,
         near_sdk_support,
     );
     let contract_source_metadata = {
-        let local_crate_info = BuildInfoMixed::new(&opts, &docker_build_meta, &cloned_repo)?;
+        let local_crate_info = BuildInfoMixed::new(&opts, &applied_build_meta, &cloned_repo)?;
         near_verify_rs::types::contract_source_metadata::ContractSourceMetadata::from(
             local_crate_info,
         )
@@ -64,8 +87,8 @@ pub fn run(opts: DockerBuildOpts, quiet: bool) -> eyre::Result<CompilationArtifa
                 "Performing check that current HEAD has been pushed to remote...",
                 || {
                     git_checks::pushed_to_remote::check(
-                        // this unwrap depends on `metadata::ReproducibleBuild::validate` logic
-                        &docker_build_meta.repository.clone().unwrap(),
+                        // this unwrap depends on `metadata::AppliedReproducibleBuild::validate` logic
+                        &applied_build_meta.repository.clone().unwrap(),
                         crate_in_repo.head,
                     )
                 },
@@ -85,7 +108,7 @@ pub fn run(opts: DockerBuildOpts, quiet: bool) -> eyre::Result<CompilationArtifa
         })?;
 
         pretty_print::handle_step("Checking that specified image is available...", || {
-            let docker_image = docker_build_meta.concat_image();
+            let docker_image = applied_build_meta.concat_image();
             docker_checks::pull_image::check(&docker_image, quiet)
         })?;
     }
diff --git a/cargo-near-build/src/near/docker_build/warn_versions_upgrades.rs b/cargo-near-build/src/near/docker_build/warn_versions_upgrades.rs
index d799861b..551d428e 100644
--- a/cargo-near-build/src/near/docker_build/warn_versions_upgrades.rs
+++ b/cargo-near-build/src/near/docker_build/warn_versions_upgrades.rs
@@ -2,7 +2,7 @@ use cargo_metadata::DependencyKind;
 use colored::Colorize;
 
 use crate::types::{
-    cargo::metadata::CrateMetadata, near::docker_build::metadata::ReproducibleBuild,
+    cargo::metadata::CrateMetadata, near::docker_build::metadata::AppliedReproducibleBuild,
 };
 use std::{str::FromStr, time::Duration};
 
@@ -221,7 +221,7 @@ mod output_wasm_path {
 
 pub fn suggest_cargo_near_build_checks(
     crate_metadata: &CrateMetadata,
-    reproducible_build: &ReproducibleBuild,
+    reproducible_build: &AppliedReproducibleBuild,
     near_sdk_support: NearSdkFeatureSupport,
 ) {
     let cargo_near = find_cargo_near_in_docker_img_tag(reproducible_build);
@@ -242,7 +242,7 @@ const PROD_IMAGE: &str = "sourcescan/cargo-near";
 const DEV_IMAGE: &str = "dj8yfo/sourcescan";
 
 fn find_cargo_near_in_docker_img_tag(
-    reproducible_build: &ReproducibleBuild,
+    reproducible_build: &AppliedReproducibleBuild,
 ) -> Option<cargo_metadata::semver::Version> {
     let regex = regex::Regex::new(DOCKER_IMAGE_REGEX_PATTERN).expect("no error");
     let image_match = regex
diff --git a/cargo-near-build/src/types/near/docker_build/compute_command.rs b/cargo-near-build/src/types/near/docker_build/compute_command.rs
index 7bb88143..1a05f9ad 100644
--- a/cargo-near-build/src/types/near/docker_build/compute_command.rs
+++ b/cargo-near-build/src/types/near/docker_build/compute_command.rs
@@ -5,22 +5,24 @@ use super::metadata;
 impl super::Opts {
     pub fn get_cli_build_command_in_docker(
         &self,
-        docker_build_meta: &metadata::ReproducibleBuild,
+        applied_build_meta: &metadata::AppliedReproducibleBuild,
     ) -> eyre::Result<Vec<String>> {
-        let Some(manifest_command) = docker_build_meta.container_build_command.as_ref() else {
+        let Some(manifest_command) = applied_build_meta.container_build_command.as_ref() else {
             return Err(eyre::eyre!(
                 "`container_build_command` is expected to be non-empty (after validation)"
             ));
         };
+
+        let section_name = metadata::section_name(self.variant.as_ref());
         println!(
             "{}`{}`{}",
             "using `container_build_command` from ".cyan(),
-            "[package.metadata.near.reproducible_build]".magenta(),
+            section_name.magenta(),
             " in Cargo.toml".cyan()
         );
         self.append_env_suffix(
             manifest_command.clone(),
-            docker_build_meta.passed_env.clone(),
+            applied_build_meta.passed_env.clone(),
         )
     }
 
@@ -47,11 +49,12 @@ impl super::Opts {
                 .collect::<Vec<_>>();
 
             if !suffix_env.is_empty() {
+                let section_name = metadata::section_name(self.variant.as_ref());
                 println!(
                     "{}{}{}",
                     "(listed in `".cyan(),
                     "passed_env".yellow(),
-                    "` from `[package.metadata.near.reproducible_build]` in Cargo.toml)".cyan(),
+                    format!("` from `{}` in Cargo.toml)", section_name).cyan(),
                 );
                 println!();
             }
diff --git a/cargo-near-build/src/types/near/docker_build/metadata.rs b/cargo-near-build/src/types/near/docker_build/metadata.rs
index 43c58563..948b403d 100644
--- a/cargo-near-build/src/types/near/docker_build/metadata.rs
+++ b/cargo-near-build/src/types/near/docker_build/metadata.rs
@@ -1,33 +1,51 @@
 use colored::Colorize;
-use serde::Deserialize;
 
 use serde_json::Value;
-use std::{collections::BTreeMap as Map, str::FromStr, thread, time::Duration};
+use std::{collections::BTreeMap, thread, time::Duration};
 
-use crate::types::cargo::metadata::CrateMetadata;
+pub(crate) mod parse;
+mod validate;
 
-#[derive(Deserialize, Debug)]
-/// parsed from `[package.metadata.near.reproducible_build]` in Cargo.toml
-pub struct ReproducibleBuild {
+pub struct AppliedReproducibleBuild {
     pub image: String,
     pub image_digest: String,
     pub passed_env: Option<Vec<String>>,
     pub container_build_command: Option<Vec<String>>,
+
     /// a cloneable git remote url,
     /// currently, only ones, starting with `https://`, are supported;
     /// parsed from `package.repository`
-    #[serde(skip)]
     pub repository: Option<url::Url>,
 
-    #[serde(flatten)]
-    unknown_keys: Map<String, Value>,
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    pub selected_variant: Option<String>,
+
+    unknown_keys: BTreeMap<String, Value>,
+}
+
+pub(crate) fn section_name(variant: Option<&String>) -> String {
+    let variant_suffix = variant
+        .map(|name| format!(".variant.{}", name))
+        .unwrap_or_default();
+
+    format!(
+        "[package.metadata.near.reproducible_build{}]",
+        variant_suffix
+    )
 }
 
 #[allow(clippy::write_literal)]
-impl std::fmt::Display for ReproducibleBuild {
+impl std::fmt::Display for AppliedReproducibleBuild {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         writeln!(f)?;
 
+        if let Some(ref variant_name) = self.selected_variant {
+            writeln!(f, "    {}: {}", "build variant", variant_name.yellow())?;
+        } else {
+            writeln!(f, "    {}: {}", "build variant", "<DEFAULT>")?;
+        }
+
         writeln!(f, "    {}: {}", "image", self.image)?;
         writeln!(f, "    {}: {}", "image digest", self.image_digest)?;
         if let Some(ref passed_env) = self.passed_env {
@@ -59,196 +77,147 @@ impl std::fmt::Display for ReproducibleBuild {
             "    {}: {}",
             "cloneable remote of git repository",
             self.repository
-                .clone()
-                .map(|url| format!("{}", url))
-                .unwrap_or("<empty>".to_string())
+                .as_ref()
+                .map(|url| url.as_ref())
+                .unwrap_or("<empty>")
         )?;
         Ok(())
     }
 }
 
-impl ReproducibleBuild {
-    fn validate_image(&self) -> eyre::Result<()> {
-        if self
-            .image
-            .chars()
-            .any(|c| !c.is_ascii() || c.is_ascii_control() || c.is_ascii_whitespace())
-        {
-            return Err(eyre::eyre!(
-                "{}: `{}`\n{}",
-                "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml",
-                self.image,
-                "`image`: string contains invalid characters",
-            ));
+impl AppliedReproducibleBuild {
+    pub fn new(reproducible_build_parsed: &parse::ReproducibleBuild) -> Self {
+        Self {
+            image: reproducible_build_parsed.image.clone(),
+            image_digest: reproducible_build_parsed.image_digest.clone(),
+            passed_env: reproducible_build_parsed.passed_env.clone(),
+            container_build_command: reproducible_build_parsed.container_build_command.clone(),
+            repository: reproducible_build_parsed.repository.clone(),
+            selected_variant: None,
+            unknown_keys: reproducible_build_parsed.unknown_keys.clone(),
         }
-        Ok(())
     }
-    fn validate_image_digest(&self) -> eyre::Result<()> {
-        if self
-            .image_digest
-            .chars()
-            .any(|c| !c.is_ascii() || c.is_ascii_control() || c.is_ascii_whitespace())
-        {
-            return Err(eyre::eyre!(
-                "{}: `{}`\n{}",
-                "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml",
-                self.image_digest,
-                "`image_digest`: string contains invalid characters",
-            ));
-        }
-        Ok(())
-    }
-    fn validate_container_build_command(&self) -> eyre::Result<()> {
-        let build_command = self.container_build_command.clone().ok_or(eyre::eyre!(
-            "`container_build_command` field not found! It is required since 0.13.0 version of `cargo-near`"
-        ))?;
-        let is_cargo_near = {
-            Some("cargo") == build_command.first().map(AsRef::as_ref)
-                && Some("near") == build_command.get(1).map(AsRef::as_ref)
-        };
-        for command_token in build_command {
-            if command_token
-                .chars()
-                .any(|c| !c.is_ascii() || c.is_ascii_control())
-            {
-                return Err(eyre::eyre!(
-                    "{}: `{}`\n{}",
-                    "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml",
-                    command_token,
-                    "`container_build_command`: string token contains invalid characters",
-                ));
-            }
-            // for versions of cargo-near inside of container <0.13
-            // versions >=0.13 require `--locked` flag instead, but this isn't validated
-            if is_cargo_near && command_token == "--no-locked" {
-                return Err(eyre::eyre!(
-                    "{}:\n{}",
-                    "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml",
-                    "`container_build_command`: `--no-locked` forbidden for `cargo near` build command",
-                ));
-            }
-            if is_cargo_near && command_token == "--manifest-path" {
-                return Err(eyre::eyre!(
-                    "{}:\n{}\n{}",
-                    "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml",
-                    "`container_build_command`: `--manifest-path` isn't allowed to be specified \
-                    in manifest itself.",
-                    "`--manifest-path ./Cargo.toml` is implied in all such cases",
-                ));
-            }
+
+    fn inject_variant_build(
+        &mut self,
+        variant_name: &str,
+        variant_build: &parse::VariantReproducibleBuild,
+    ) {
+        println!();
+        println!(
+            "{}{}{}",
+            "Injecting variant build `.variant.".yellow(),
+            variant_name.yellow(),
+            "`:".yellow()
+        );
+
+        self.selected_variant = Some(variant_name.to_string());
+
+        if let Some(new_image) = &variant_build.image {
+            println!("    {}", "Changing image:".yellow());
+            println!("        {} `{}`", "default:".red(), self.image);
+            println!("        {} `{}`", "override:".green(), new_image);
+            println!();
+
+            self.image.clone_from(new_image);
         }
-        Ok(())
-    }
 
-    fn validate_if_unknown_keys_present(&self) -> eyre::Result<()> {
-        if !self.unknown_keys.is_empty() {
-            let keys = self
-                .unknown_keys
-                .keys()
-                .map(|element| element.as_str())
-                .collect::<Vec<_>>();
-            return Err(eyre::eyre!(
-                "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml, contains unknown keys: `{}`",
-                keys.join(",")
-            ));
+        if let Some(new_image_digest) = &variant_build.image_digest {
+            println!("    {}", "Changing image_digest:".yellow());
+            println!("        {} `{}`", "default:".red(), self.image_digest);
+            println!("        {} `{}`", "override:".green(), new_image_digest);
+            println!();
+
+            self.image_digest.clone_from(new_image_digest);
         }
-        Ok(())
-    }
 
-    fn validate_repository(&self) -> eyre::Result<()> {
-        match self.repository {
-            Some(ref repository) => {
-                if repository.scheme() != "https" {
-                    return Err(eyre::eyre!(
-                        "{}: {}\n{}",
-                        "Malformed NEP330 metadata in Cargo.toml:",
-                        repository,
-                        "`[package.repository]`: only `https` scheme is supported at the moment",
-                    ));
-                }
+        if let Some(new_passed_env) = &variant_build.passed_env {
+            println!("    {}", "Changing passed_env:".yellow());
+
+            if let Some(original_passed_env) = &self.passed_env {
+                println!("        {} `{:?}`", "default:".red(), original_passed_env);
+            } else {
+                println!("        {} `{}`", "default:".red(), "<ABSENT>".green());
             }
-            None => {
-                return Err(eyre::eyre!(
-                    "{}: \n{}",
-                    "Malformed NEP330 metadata in Cargo.toml",
-                    "`[package.repository]`: should not be empty",
-                ));
+
+            println!("        {} `{:?}`", "override:".green(), new_passed_env);
+            println!();
+
+            self.passed_env = Some(new_passed_env.clone());
+        }
+
+        if let Some(new_container_command) = &variant_build.container_build_command {
+            println!("    {}", "Changing container_build_command:".yellow());
+
+            if let Some(original_build_command) = &self.container_build_command {
+                println!(
+                    "        {} `{:?}`",
+                    "default:".red(),
+                    original_build_command
+                );
+            } else {
+                println!("        {} `{}`", "default:".red(), "<ABSENT>".yellow());
             }
+
+            println!(
+                "        {} `{:?}`",
+                "override:".green(),
+                new_container_command
+            );
+            println!();
+
+            self.container_build_command = Some(new_container_command.clone());
         }
-        Ok(())
-    }
 
-    fn validate(&self) -> eyre::Result<()> {
-        self.validate_image()?;
-        self.validate_image_digest()?;
-        self.validate_container_build_command()?;
-        self.validate_if_unknown_keys_present()?;
-        self.validate_repository()?;
+        self.unknown_keys.extend(variant_build.unknown_keys.clone());
+    }
 
-        Ok(())
+    pub fn concat_image(&self) -> String {
+        let mut result = String::new();
+        result.push_str(&self.image);
+        result.push('@');
+        result.push_str(&self.image_digest);
+        result
     }
-    pub fn parse(cargo_metadata: &CrateMetadata) -> eyre::Result<Self> {
-        let build_meta_value = cargo_metadata
-            .root_package
-            .metadata
-            .get("near")
-            .and_then(|value| value.get("reproducible_build"));
-
-        let mut build_meta: ReproducibleBuild = match build_meta_value {
-            None => {
+}
+
+impl parse::ReproducibleBuild {
+    /// Apply the variant of `[package.metadata.near.reproducible_build]` using the `variant_name`;
+    /// if `variant_name` is empty - return default `[package.metadata.near.reproducible_build]`
+    pub fn apply_variant_or_default(
+        self,
+        variant_name: Option<&str>,
+    ) -> eyre::Result<AppliedReproducibleBuild> {
+        let mut applied_variant = AppliedReproducibleBuild::new(&self);
+        if let Some(name) = variant_name {
+            if let Some(variant) = self.variants_map.get(name) {
+                applied_variant.inject_variant_build(name, variant);
+            } else {
                 println!(
-                    "{}",
-                    "Metadata section in contract's Cargo.toml, \
-                    that is prerequisite for reproducible builds, has not been found..."
-                        .yellow()
+                    "{}{}{}",
+                    "Build variant called `".yellow(),
+                    name.yellow(),
+                    "` was not found in Cargo.toml...".yellow()
                 );
                 thread::sleep(Duration::new(7, 0));
                 println!();
                 println!(
-                    "{}{}{}",
+                    "{}{}{}{}{}",
                     "You can add and commit ".cyan(),
-                    "`[package.metadata.near.reproducible_build]` ".magenta(),
+                    "`[package.metadata.near.reproducible_build.variant.".magenta(),
+                    name.magenta(),
+                    "]` ".magenta(),
                     "to your contract's Cargo.toml:".cyan()
                 );
-                println!("{}{}", "- default values for the section can be found at ".cyan(), 
-                    "https://github.com/near/cargo-near/blob/main/cargo-near/src/commands/new/new-project-template/Cargo.template.toml#L14-L29".magenta());
-                println!(
-                    "{}{}",
-                    "- the same can also be found in Cargo.toml of template project, generated by "
-                        .cyan(),
-                    "`cargo near new`".magenta()
-                );
 
                 thread::sleep(Duration::new(12, 0));
 
                 return Err(eyre::eyre!(
-                    "Missing `[package.metadata.near.reproducible_build]` in Cargo.toml"
+                    "Missing `[package.metadata.near.reproducible_build.variant.{}]` in Cargo.toml",
+                    name
                 ));
             }
-            Some(build_meta_value) => {
-                serde_json::from_value(build_meta_value.clone()).map_err(|err| {
-                    eyre::eyre!(
-                        "Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml: {}",
-                        err
-                    )
-                })?
-            }
-        };
-        build_meta.repository = cargo_metadata
-            .root_package
-            .repository
-            .clone()
-            .map(|url| <url::Url as FromStr>::from_str(&url))
-            .transpose()?;
-        build_meta.validate()?;
-        println!("{} {}", "reproducible build metadata:".green(), build_meta);
-        Ok(build_meta)
-    }
-    pub fn concat_image(&self) -> String {
-        let mut result = String::new();
-        result.push_str(&self.image);
-        result.push('@');
-        result.push_str(&self.image_digest);
-        result
+        }
+        Ok(applied_variant)
     }
 }
diff --git a/cargo-near-build/src/types/near/docker_build/metadata/parse.rs b/cargo-near-build/src/types/near/docker_build/metadata/parse.rs
new file mode 100644
index 00000000..a07029c1
--- /dev/null
+++ b/cargo-near-build/src/types/near/docker_build/metadata/parse.rs
@@ -0,0 +1,92 @@
+use colored::Colorize;
+use eyre::Context;
+use serde::Deserialize;
+use serde_json::Value;
+use std::{collections::BTreeMap, thread, time::Duration};
+
+use std::str::FromStr;
+
+use crate::types::cargo::metadata::CrateMetadata;
+
+#[derive(Deserialize, Debug)]
+/// parsed from `[package.metadata.near.reproducible_build]` in Cargo.toml
+pub struct ReproducibleBuild {
+    pub image: String,
+    pub image_digest: String,
+    pub passed_env: Option<Vec<String>>,
+    pub container_build_command: Option<Vec<String>>,
+    /// a cloneable git remote url,
+    /// currently, only ones, starting with `https://`, are supported;
+    /// parsed from `package.repository`
+    #[serde(skip)]
+    pub repository: Option<url::Url>,
+
+    #[serde(rename = "variant", default)]
+    pub variants_map: BTreeMap<String, VariantReproducibleBuild>,
+
+    #[serde(flatten)]
+    pub unknown_keys: BTreeMap<String, Value>,
+}
+
+#[derive(Deserialize, Debug)]
+/// parsed from `[package.metadata.near.reproducible_build.variant.name]` in Cargo.toml
+pub struct VariantReproducibleBuild {
+    pub image: Option<String>,
+    pub image_digest: Option<String>,
+    pub passed_env: Option<Vec<String>>,
+    pub container_build_command: Option<Vec<String>>,
+
+    #[serde(flatten)]
+    pub unknown_keys: BTreeMap<String, Value>,
+}
+
+impl ReproducibleBuild {
+    pub fn parse(cargo_metadata: &CrateMetadata) -> eyre::Result<Self> {
+        let Some(build_meta_value) = cargo_metadata
+            .root_package
+            .metadata
+            .get("near")
+            .and_then(|value| value.get("reproducible_build"))
+        else {
+            println!(
+                "{}",
+                "Metadata section in contract's Cargo.toml, \
+                    that is prerequisite for reproducible builds, has not been found..."
+                    .yellow()
+            );
+            thread::sleep(Duration::new(7, 0));
+            println!();
+            println!(
+                "{}{}{}",
+                "You can add and commit ".cyan(),
+                "`[package.metadata.near.reproducible_build]` ".magenta(),
+                "to your contract's Cargo.toml:".cyan()
+            );
+            println!("{}{}", "- default values for the section can be found at ".cyan(),
+                "https://github.com/near/cargo-near/blob/main/cargo-near/src/commands/new/new-project-template/Cargo.template.toml#L14-L29".magenta());
+            println!(
+                "{}{}",
+                "- the same can also be found in Cargo.toml of template project, generated by "
+                    .cyan(),
+                "`cargo near new`".magenta()
+            );
+
+            thread::sleep(Duration::new(12, 0));
+
+            return Err(eyre::eyre!(
+                "Missing `[package.metadata.near.reproducible_build]` in Cargo.toml"
+            ));
+        };
+        let mut build_meta: Self = serde_json::from_value(build_meta_value.clone())
+            .wrap_err("Malformed `[package.metadata.near.reproducible_build]` in Cargo.toml")?;
+
+        build_meta.repository = cargo_metadata
+            .root_package
+            .repository
+            .as_deref()
+            .map(<url::Url as FromStr>::from_str)
+            .transpose()?;
+
+        Ok(build_meta)
+    }
+}
diff --git a/cargo-near-build/src/types/near/docker_build/metadata/validate.rs b/cargo-near-build/src/types/near/docker_build/metadata/validate.rs
new file mode 100644
index 00000000..c2cd722e
--- /dev/null
+++ b/cargo-near-build/src/types/near/docker_build/metadata/validate.rs
@@ -0,0 +1,130 @@
+use super::section_name;
+
+impl super::AppliedReproducibleBuild {
+    pub fn validate(&self) -> eyre::Result<()> {
+        self.validate_image()?;
+        self.validate_image_digest()?;
+        self.validate_container_build_command()?;
+        self.validate_if_unknown_keys_present()?;
+        self.validate_repository()?;
+
+        Ok(())
+    }
+
+    fn validate_image(&self) -> eyre::Result<()> {
+        if self
+            .image
+            .chars()
+            .any(|c| !c.is_ascii() || c.is_ascii_control() || c.is_ascii_whitespace())
+        {
+            let section_name = section_name(self.selected_variant.as_ref());
+            return Err(eyre::eyre!(
+                "Malformed `{}` in Cargo.toml: `{}`\n{}",
+                section_name,
+                self.image,
+                "`image`: string contains invalid characters",
+            ));
+        }
+        Ok(())
+    }
+    fn validate_image_digest(&self) -> eyre::Result<()> {
+        if self
+            .image_digest
+            .chars()
+            .any(|c| !c.is_ascii() || c.is_ascii_control() || c.is_ascii_whitespace())
+        {
+            let section_name = section_name(self.selected_variant.as_ref());
+            return Err(eyre::eyre!(
+                "Malformed `{}` in Cargo.toml: `{}`\n{}",
+                section_name,
+                self.image_digest,
+                "`image_digest`: string contains invalid characters",
+            ));
+        }
+        Ok(())
+    }
+
+    fn validate_container_build_command(&self) -> eyre::Result<()> {
+        let build_command = self.container_build_command.clone().ok_or(eyre::eyre!(
+        "`container_build_command` field not found! It is required since 0.13.0 version of `cargo-near`"
+    ))?;
+        let is_cargo_near = {
+            Some("cargo") == build_command.first().map(AsRef::as_ref)
+                && Some("near") == build_command.get(1).map(AsRef::as_ref)
+        };
+
+        let section_name = section_name(self.selected_variant.as_ref());
+
+        for command_token in build_command {
+            if command_token
+                .chars()
+                .any(|c| !c.is_ascii() || c.is_ascii_control())
+            {
+                return Err(eyre::eyre!(
+                    "Malformed `{}` in Cargo.toml: `{}`\n{}",
+                    section_name,
+                    command_token,
+                    "`container_build_command`: string token contains invalid characters",
+                ));
+            }
+            // for versions of cargo-near inside of container <0.13
+            // versions >=0.13 require `--locked` flag instead, but this isn't validated
+            if is_cargo_near && command_token == "--no-locked" {
+                return Err(eyre::eyre!(
+                "Malformed `{}` in Cargo.toml:\n{}",
+                section_name,
+                "`container_build_command`: `--no-locked` forbidden for `cargo near` build command",
+            ));
+            }
+            if is_cargo_near && command_token == "--manifest-path" {
+                return Err(eyre::eyre!(
+                    "Malformed `{}` in Cargo.toml:\n{}\n{}",
+                    section_name,
+                    "`container_build_command`: `--manifest-path` isn't allowed to be specified \
+                    in manifest itself.",
+                    "`--manifest-path ./Cargo.toml` is implied in all such cases",
+                ));
+            }
+        }
+        Ok(())
+    }
+
+    fn validate_if_unknown_keys_present(&self) -> eyre::Result<()> {
+        if !self.unknown_keys.is_empty() {
+            let keys = self
+                .unknown_keys
+                .keys()
+                .map(String::as_str)
+                .collect::<Vec<_>>();
+
+            let section_name = section_name(self.selected_variant.as_ref());
+            return Err(eyre::eyre!(
+                "Malformed `{}` in Cargo.toml, contains unknown keys: `{}`",
+                section_name,
+                keys.join(",")
+            ));
+        }
+        Ok(())
+    }
+
+    fn validate_repository(&self) -> eyre::Result<()> {
+        if let Some(ref repository) = self.repository {
+            if repository.scheme() != "https" {
+                Err(eyre::eyre!(
+                    "{}: {}\n{}",
+                    "Malformed NEP330 metadata in Cargo.toml:",
+                    repository,
+                    "`[package.repository]`: only `https` scheme is supported at the moment",
+                ))
+            } else {
+                Ok(())
+            }
+        } else {
+            Err(eyre::eyre!(
+                "{}: \n{}",
+                "Malformed NEP330 metadata in Cargo.toml",
+                "`[package.repository]`: should not be empty",
+            ))
+        }
+    }
+}
diff --git a/cargo-near-build/src/types/near/docker_build/mod.rs b/cargo-near-build/src/types/near/docker_build/mod.rs
index a981377b..0b73208d 100644
--- a/cargo-near-build/src/types/near/docker_build/mod.rs
+++ b/cargo-near-build/src/types/near/docker_build/mod.rs
@@ -22,6 +22,8 @@ pub struct Opts {
     /// Coloring: auto, always, never;
     /// assumed to be auto when `None`
     pub color: Option<ColorPreference>,
+    /// Variant of the reproducible-wasm build
+    pub variant: Option<String>,
     #[builder(default)]
     pub context: BuildContext,
 }
diff --git a/cargo-near-build/src/types/near/docker_build/subprocess/nep330_build_info.rs b/cargo-near-build/src/types/near/docker_build/subprocess/nep330_build_info.rs
index 5ede56b9..f5a6b76e 100644
--- a/cargo-near-build/src/types/near/docker_build/subprocess/nep330_build_info.rs
+++ b/cargo-near-build/src/types/near/docker_build/subprocess/nep330_build_info.rs
@@ -17,10 +17,10 @@ pub struct BuildInfoMixed {
     pub build_command: Vec<String>,
 }
 fn compute_repo_link_hint(
-    docker_build_meta: &metadata::ReproducibleBuild,
+    applied_build_meta: &metadata::AppliedReproducibleBuild,
     cloned_repo: &cloned_repo::ClonedRepo,
 ) -> Option<String> {
-    let repo_link_url = docker_build_meta.repository.clone().expect(
+    let repo_link_url = applied_build_meta.repository.clone().expect(
         "expected to be [Option::Some] due to [metadata::ReproducibleBuild::validate_repository] rule"
     );
     let revision = cloned_repo.initial_crate_in_repo.head.to_string();
@@ -47,10 +47,10 @@ fn compute_repo_link_hint(
 impl BuildInfoMixed {
     pub fn new(
         opts: &DockerBuildOpts,
-        docker_build_meta: &metadata::ReproducibleBuild,
+        applied_build_meta: &metadata::AppliedReproducibleBuild,
         cloned_repo: &cloned_repo::ClonedRepo,
     ) -> eyre::Result<Self> {
-        let build_environment = docker_build_meta.concat_image();
+        let build_environment = applied_build_meta.concat_image();
         let contract_path = cloned_repo
             .initial_crate_in_repo
             .unix_relative_path()?
@@ -60,13 +60,13 @@ impl BuildInfoMixed {
 
         let source_code_snapshot = source_id::SourceId::for_git(
             // this unwrap depends on `metadata::ReproducibleBuild::validate` logic
-            docker_build_meta.repository.as_ref().unwrap(),
+            applied_build_meta.repository.as_ref().unwrap(),
             source_id::GitReference::Rev(cloned_repo.initial_crate_in_repo.head.to_string()),
         )
         .map_err(|err| eyre::eyre!("compute SourceId {}", err))?;
 
-        let link = compute_repo_link_hint(docker_build_meta, cloned_repo);
-        let build_command = opts.get_cli_build_command_in_docker(docker_build_meta)?;
+        let link = compute_repo_link_hint(applied_build_meta, cloned_repo);
+        let build_command = opts.get_cli_build_command_in_docker(applied_build_meta)?;
 
         Ok(Self {
             build_environment,
diff --git a/cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs b/cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
index bfbc5b3b..2939bd55 100644
--- a/cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
+++ b/cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
@@ -51,6 +51,42 @@ pub struct BuildOpts {
     #[interactive_clap(value_enum)]
     #[interactive_clap(skip_interactive_input)]
     pub color: Option<crate::types::color_preference_cli::ColorPreferenceCli>,
+    /// Specify which named variant of `reproducible-wasm` you want to use from `Cargo.toml`
+    ///
+    /// This flag will allow you to replace settings specified in default
+    /// `[package.metadata.near.reproducible_build]`
+    /// with ones defined in
+    /// `[package.metadata.near.reproducible_build.variant.<VARIANT>]`.
+    ///
+    ///
+    /// Note that all fields in `.variant.<VARIANT>` table are optional and
+    /// will override default ones only if they are defined.
+    ///
+    /// Example:
+    /// You have developed a feature in your contract that should work only for testnet.
+    /// You could add this to your `Cargo.toml` (assuming you have already defined `testnet=[]` under `[features]`):
+    /// ```toml
+    /// [package.metadata.near.reproducible_build.variant.testnet]
+    /// container_build_command = [
+    ///     "cargo",
+    ///     "near",
+    ///     "build",
+    ///     "non-reproducible-wasm",
+    ///     "--locked",
+    ///     "--features",
+    ///     "testnet",
+    /// ]
+    /// ```
+    /// This will only replace `container_build_command` of original `reproducible_build` with
+    /// one from `.variant.testnet`.
+    ///
+    /// See also [variant flag explanation](variant-feature-explanation).
+    ///
+    /// [variant-feature-explanation]: https://github.com/near/cargo-near/tree/main?tab=readme-ov-file#custom-reproducible-wasm-build-using---variant-name-flag
+    #[interactive_clap(long)]
+    #[interactive_clap(skip_interactive_input)]
+    #[interactive_clap(verbatim_doc_comment)]
+    pub variant: Option<String>,
 }
 
 impl From<CliBuildOpts> for BuildOpts {
@@ -60,6 +96,7 @@ impl From<CliBuildOpts> for BuildOpts {
             out_dir: value.out_dir,
             manifest_path: value.manifest_path,
             color: value.color,
+            variant: value.variant,
         }
     }
 }
@@ -78,6 +115,7 @@ mod context {
                 out_dir: scope.out_dir.clone(),
                 manifest_path: scope.manifest_path.clone(),
                 color: scope.color.clone(),
+                variant: scope.variant.clone(),
             };
             super::run(opts, previous_context)?;
             Ok(Self)
@@ -94,6 +132,7 @@ fn docker_opts_from(value: (BuildOpts, BuildContext)) -> docker::DockerBuildOpts
         out_dir: value.0.out_dir.map(Into::into),
         manifest_path: value.0.manifest_path.map(Into::into),
         color: value.0.color.map(Into::into),
+        variant: value.0.variant,
         context: value.1,
     }
 }
diff --git a/cargo-near/src/main.rs b/cargo-near/src/main.rs
index b85eb012..bf32e3bd 100644
--- a/cargo-near/src/main.rs
+++ b/cargo-near/src/main.rs
@@ -44,7 +44,7 @@ fn main() -> CliResult {
         offline: false,
     };
 
-    let cli_opts = match cli_cmd.clone().opts {
+    let cli_opts = match cli_cmd.opts {
         Some(cli_opts) => cli_opts,
         None => match Opts::choose_variant(global_context.clone()) {
             interactive_clap::ResultFromCli::Ok(cli_opts) => cli_opts,
@@ -59,9 +59,9 @@ fn main() -> CliResult {
     let console_command_path = if env::var("CARGO_HOME").is_ok() {
         "cargo".to_string()
     } else if let Ok(value) = env::var("CARGO") {
-        value.clone()
+        value
     } else {
-        env::args().next().unwrap_or("./cargo".to_string())
+        env::args().next().unwrap_or_else(|| "./cargo".to_string())
     };
 
     let console_command_path = console_command_path.yellow();
diff --git a/cargo-near/src/posthog_tracking.rs b/cargo-near/src/posthog_tracking.rs
index 678fb7eb..1256d073 100644
--- a/cargo-near/src/posthog_tracking.rs
+++ b/cargo-near/src/posthog_tracking.rs
@@ -50,7 +50,7 @@ pub(crate) fn track_usage() {
         )
         .is_err()
     {
-        debug!(SEND_TRACKING_REQUEST_ERROR)
+        debug!(SEND_TRACKING_REQUEST_ERROR);
     }
 }
 


Reviews:
user: login: frol
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T18:57:29Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T20:14:00Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-09T22:30:13Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-09T22:39:34Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-10T07:12:07Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-10T07:22:48Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T12:16:06Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T12:21:14Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-10T22:06:41Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-11T21:37:27Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-13T18:15:27Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-13T18:38:23Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T03:51:15Z
user: login: vsavchyn-dev
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T03:55:15Z
user: login: frol
body: It looks good to me now. I have also tested it locally and works as expected.

@vsavchyn-dev Thank you for your contribution!

@race-of-sloths score 8
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T14:27:37Z
user: login: dj8yfo
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-16T16:35:06Z

Review comments:
diff_hunk: @@ -137,6 +137,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
+Beyond defaults in your `[package.metadata.near.reproducible_build]`, you can now
+define **named build variants** in your `Cargo.toml` under:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.<name>]
+image                   = "<your-docker-image>"
+image_digest            = "<sha256:...>"
+passed_env              = ["RUSTFLAGS",...]
+container_build_command = ["cargo", "build", "--locked", ...]
+```
+
+At build time, simply add `--variant <name>` to overlay variant's settings over
+the `reproducible_build` options. For example, if you declare:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.custom-variant-name]
+container_build_command = [
+    "cargo",
+    "near",
+    "build",
+    "non-reproducible-wasm",
+    "--locked",
+    "--features",
+    "my-custom-feature"
+]
+```
+
+in `Cargo.toml`, and then:
+
+```bash
+cargo near build reproducible_build --variant custom-variant-name
path: README.md
user: login: frol
body: I think there is a typo:

```suggestion
cargo near build reproducible-wasm --variant custom-variant-name
```
created_at: 2025-05-09T08:02:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: frol
body: Have you considered parsing it with:

```rust
variant: HashMap<String, VariantReproducibleBuild>
```

?
created_at: 2025-05-09T18:57:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: vsavchyn-dev
body: Yes, I did. It worked.

Despite that, two things made me use `Option<String>` instead of `HashMap` or `BTreeMap`:

1. I wanted to indicate what variant was used when you run `cargo near build reproducible-wasm --variant <name>` without adding unnecessary parameters to [`get_cli_build_command_in_docker` function in `compute_command.rs`](https://github.com/vsavchyn-dev/cargo-near/blob/17582f939d6e061f3ac5b106d707902d066106ef/cargo-near-build/src/types/near/docker_build/compute_command.rs#L6-L9) and [any of the `validate_*` functions lower in this PR](https://github.com/vsavchyn-dev/cargo-near/blob/17582f939d6e061f3ac5b106d707902d066106ef/cargo-near-build/src/types/near/docker_build/metadata.rs#L162-L181). Therefore, `HashMap` or `BTreeMap` didn't satisfy my needs.
2. I thought that carrying the whole `HashMap` in the `ReproducibleBuild` struct would be inefficient and that I wouldn't need it later in the code. 
created_at: 2025-05-09T20:14:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: dj8yfo
body: 1. Yeah, well, it still can be a separate `#[serde(skip)] selected_variant: Option<String>` field, can't it? And parsing done through this `HashMap<...>.` thing, which appears to be more straightforward, than removing a key from `unknown_keys`, and then parsing that into a map. 
2. Indeed, there's no use for all the parsed variants. Current `ReproducibleBuild` can be used for only parsing and holding all possible variants and the selected variant, and yet one more type `AppliedReproducibleBuild` can be obtained from `ReproducibleBuild` by applying selected variant to default config.
It would be a bit more clear imo where the logic lives, if it were `ReproducibleBuild::apply_selected_variant(self) -> AppliedReproducibleBuild`. 
Having one more state transition might simplify code a little, as `ReproducibleBuild` has all the possible duties it has to do, parsing input + combining values into eventual result +storing the result
created_at: 2025-05-09T22:30:12Z
author_association: COLLABORATOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: dj8yfo
body: It would look even cleaner to me, if it were `ReproducibleBuild::apply_variant(self, variant: Option<String>) -> AppliedReproducibleBuild` , as the `variant` comes as a cli parameter and isn't parsed from toml (which is represented by `ReproducibleBuild`)
created_at: 2025-05-09T22:39:33Z
author_association: COLLABORATOR
diff_hunk: @@ -137,6 +137,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
+Beyond defaults in your `[package.metadata.near.reproducible_build]`, you can now
+define **named build variants** in your `Cargo.toml` under:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.<name>]
+image                   = "<your-docker-image>"
+image_digest            = "<sha256:...>"
+passed_env              = ["RUSTFLAGS",...]
+container_build_command = ["cargo", "build", "--locked", ...]
+```
+
+At build time, simply add `--variant <name>` to overlay variant's settings over
+the `reproducible_build` options. For example, if you declare:
+
+```yaml
+[package.metadata.near.reproducible_build.variant.custom-variant-name]
+container_build_command = [
+    "cargo",
+    "near",
+    "build",
+    "non-reproducible-wasm",
+    "--locked",
+    "--features",
+    "my-custom-feature"
+]
+```
+
+in `Cargo.toml`, and then:
+
+```bash
+cargo near build reproducible_build --variant custom-variant-name
path: README.md
user: login: vsavchyn-dev
body: Thanks for noticing that! I straight up committed your suggestion.
created_at: 2025-05-10T07:12:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: vsavchyn-dev
body: > 1\. Yeah, well, it still can be a separate `#[serde(skip)] selected_variant: Option<String>` field, can't it? And parsing done through this `HashMap<...>.` thing, which appears to be more straightforward, than removing a key from `unknown_keys`, and then parsing that into a map.

Ofc, it can be in its own field. But, as I said, I thought it would be inefficient. Looking back at it, realistically, there would be 2-4 "variants" (or 5-6 in extreme cases), so maybe it's quite a small memory/efficiency tradeoff to use `Option<String>` instead of `HashMap<...>` @frol @dj8yfo?

> 2\. Indeed, there's no use for all the parsed variants. Current `ReproducibleBuild` can be used for only parsing and holding all possible variants and the selected variant, and yet one more type `AppliedReproducibleBuild` can be obtained from `ReproducibleBuild` by applying selected variant to default config.
>     It would be a bit more clear imo where the logic lives, if it were `ReproducibleBuild::apply_selected_variant(self) -> AppliedReproducibleBuild`.

As far as I understand you want to have two separate steps in this process:
1. **Parse** `Cargo.toml` file into `ReproducibleBuild`
2. **Apply** selected variant (or use default) to produce `AppliedReproducibleBuild`

and then we pass `AppliedReproducibleBuild` instead of `ReproducibleBuild` for later stages of `cargo near build reproducible-wasm`, right @dj8yfo? This makes sense to me - especially if I will use `HashMap<...>` and want to simplify logic.

In general, I agree that this separation approach would simplify the logic and it is better. Not only that, it will be easier to expand this later. But, if I go in this route of adding another struct, should validation of fields (aka `validate_image`, `validate_build_command`, and other checks) be moved into methods on `AppliedReproducibleBuild`, so that all post-merge checks live in the "applied" type?
created_at: 2025-05-10T07:22:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: dj8yfo
body: Yeap, validation should be in the final result `AppliedReproducibleBuild`. `ReproducibleBuild` now mostly becomes a private type (not used by other modules in crate), used only for parsing input from toml. It can be renamed accordingly, like `ReproducibleBuildFromToml`. 

Also, when printing the applied result, i would change labels from "old" -> "default", "new" -> "override from variant".

And i'd remove all introduced `thread::sleep`-s, unless those are used for error/warning condition indication. If the computation of default+variant combination was successful, there's no need to pause to draw attention.
created_at: 2025-05-10T12:16:06Z
author_association: COLLABORATOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: dj8yfo
body: The `selected_variant` field should live, if present, in `AppliedRe...` and not in `ReproducibleBuildFromToml` according to this logic. 
created_at: 2025-05-10T12:21:14Z
author_association: COLLABORATOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: vsavchyn-dev
body: > Also, when printing the applied result, i would change labels from "old" -> "default", "new" -> "override from variant".

How about "default" and simple "override"?  It would be readable imo (considering it will be mentioned that `variant.<name>`s build was used build, right before insertion of "variant" metadata).

> And i'd remove all introduced `thread::sleep`-s, unless those are used for error/warning condition indication. If the computation of default+variant combination was successful, there's no need to pause to draw attention.

Noted, will remove them.
created_at: 2025-05-10T22:06:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -19,6 +19,23 @@ pub struct ReproducibleBuild {
     #[serde(skip)]
     pub repository: Option<url::Url>,
 
+    /// indicator for used variant of reproducible build;
+    /// present if the variant of build was used
+    #[serde(skip)]
+    pub variant: Option<String>,
+
+    #[serde(flatten)]
+    unknown_keys: Map<String, Value>,
path: cargo-near-build/src/types/near/docker_build/metadata.rs
user: login: vsavchyn-dev
body: @dj8yfo fixed in 8295cf6eec13f82e0f481ac0f76c26b9026bd5aa
created_at: 2025-05-11T21:37:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,6 +51,10 @@ pub struct BuildOpts {
     #[interactive_clap(value_enum)]
     #[interactive_clap(skip_interactive_input)]
     pub color: Option<crate::types::color_preference_cli::ColorPreferenceCli>,
+    /// Specify which named variant of `reproducible_build` you want to use from Cargo.toml
path: cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
user: login: dj8yfo
body: i'd add more verbose documentation about about this flag for `-h/--help` commands.  It can even be a complete example of metadata which the flag is supposed to be used with. 

By adding  ` #[interactive_clap(verbatim_doc_comment)]`  you'll preserve line breaks as they happen in doc comment. 

```rust
/// Specify which named variant of `reproducible_build` you want to use from Cargo.toml
///
/// Everything after the blank line above together with first line will be displayed for this flag with long `--help`
/// ...
```
Only the first line `Specify which named variant ...` will be displayed for this flag with `-h` . 
created_at: 2025-05-13T18:15:20Z
author_association: COLLABORATOR
diff_hunk: @@ -139,6 +139,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
path: README.md
user: login: dj8yfo
body: this should become a `####` heading, so that it can be an anchor
created_at: 2025-05-13T18:20:30Z
author_association: COLLABORATOR
diff_hunk: @@ -51,6 +51,10 @@ pub struct BuildOpts {
     #[interactive_clap(value_enum)]
     #[interactive_clap(skip_interactive_input)]
     pub color: Option<crate::types::color_preference_cli::ColorPreferenceCli>,
+    /// Specify which named variant of `reproducible_build` you want to use from Cargo.toml
path: cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
user: login: dj8yfo
body: this can feature a full example of metadata with `testnet`/`mainnet` variant names, which i believe would be the most obvious example of when it may be needed. 

This can end with a link to the newly created `#### --variant flag` anchor in README markdown in destination (`main`) branch in `near` origin, e.g. https://github.com/vsavchyn-dev/cargo-near/tree/main?tab=readme-ov-file#reproducible-wasm (testable with `vsavchyn-dev` origin, then replaced `vsavchyn-dev` -> `near` origin to be included in current pr). 
created_at: 2025-05-13T18:24:31Z
author_association: COLLABORATOR
diff_hunk: @@ -139,6 +139,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
path: README.md
user: login: dj8yfo
body: I'd remove 
![image](https://github.com/user-attachments/assets/f73c0f38-dc8a-41ae-adc3-01c6a156c427)
, as that section describes each field of `[package.metadata.near.reproducible_build]` , not cli flags. 
created_at: 2025-05-13T18:29:54Z
author_association: COLLABORATOR
diff_hunk: @@ -139,6 +139,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
path: README.md
user: login: dj8yfo
body: i'd move 
![image](https://github.com/user-attachments/assets/bea693d1-5400-412e-999c-71e2e38fccf9)
back up before this newly created `####` `--variant` anchor, so that it becomes part of `### reproducible-wasm` anchor
created_at: 2025-05-13T18:32:25Z
author_association: COLLABORATOR
diff_hunk: @@ -139,6 +139,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
+Beyond defaults in your `[package.metadata.near.reproducible_build]`, you can now
+define **named build variants** in your `Cargo.toml` under:
+
path: README.md
user: login: dj8yfo
body: This should state that it supports all the same fields as `[package.metadata.near.reproducible_build]`, 
listing all them (`image`, `image_digest`, `container_build_command`, `passed_env`) and mentioning that every field is optional. 
created_at: 2025-05-13T18:35:37Z
author_association: COLLABORATOR
diff_hunk: @@ -51,6 +51,10 @@ pub struct BuildOpts {
     #[interactive_clap(value_enum)]
     #[interactive_clap(skip_interactive_input)]
     pub color: Option<crate::types::color_preference_cli::ColorPreferenceCli>,
+    /// Specify which named variant of `reproducible_build` you want to use from Cargo.toml
path: cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
user: login: vsavchyn-dev
body: Resolved in 854f0cfa307daeb82b961f61c1ce0d04e7c15f0b
created_at: 2025-05-14T03:51:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -139,6 +139,43 @@ This variant runs a reproducible build in a [Docker](https://docs.docker.com/) c
 **What's a reproducible build in context of NEAR?**
 Why is it needed? Explanation of these points and a step-by-step tutorial is present at [SourceScan/verification-guide](https://github.com/SourceScan/verification-guide).
 
+**Custom build variant via `--variant <name>`**
path: README.md
user: login: vsavchyn-dev
body: Resolved in 854f0cfa307daeb82b961f61c1ce0d04e7c15f0b

P.S.
> back up before this newly created `####` `--variant` anchor, so that it becomes part of `### reproducible-wasm` anchor

I am not sure if I got what you meant right, but I moved whole section about `--variant` flag under `Additional flag for build...`, as it made more sense.
created_at: 2025-05-14T03:55:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -51,6 +51,41 @@ pub struct BuildOpts {
     #[interactive_clap(value_enum)]
     #[interactive_clap(skip_interactive_input)]
     pub color: Option<crate::types::color_preference_cli::ColorPreferenceCli>,
+    /// Specify which named variant of `reproducible-wasm` you want to use from `Cargo.toml`
+    ///
+    /// This flag will allow you to replace settings specified in default
+    /// `[package.metadata.near.reproducible_build]`
+    /// with ones defined in
+    /// `[package.metadata.near.reproducible_build.variant.<VARIANT>]`.
+    ///
+    ///
+    /// Note that all fields in `.variant.<VARIANT>` table are optional and
+    /// will override default ones only if they are defined.
+    ///
+    /// Example:
+    /// You have developed a feature in your contract that should work only for testnet.
+    /// You could add this to your `Cargo.toml` (assuming you have already defined `testnet=[]` under `[features]`):
+    /// ```toml
+    /// [package.metadata.near.reproducible_build.variant.testnet]
+    /// container_build_command = [
+    ///     "cargo",
+    ///     "near",
+    ///     "build",
+    ///     "non-reproducible-wasm",
+    ///     "--locked",
+    ///     "--features",
+    ///     "testnet",
+    /// ]
+    /// ```
+    /// This will only replace `container_build_command` of original `reproducible_build` with
+    /// one from `.variant.testnet`.
+    ///
+    /// See also [variant flag explanation](variant-feature-explanation).
+    ///
+    /// [variant-feature-explanation]: https://github.com/near/cargo-near/tree/main?tab=readme-ov-file#custom-reproducible-wasm-build-using---variant-name-flag
+    #[interactive_clap(skip_interactive_input)]
path: cargo-near/src/commands/build/actions/reproducible_wasm/mod.rs
user: login: dj8yfo
body: oops, i accidentally deleted an `#[interactive_clap(long)]` attr, 
re-adding it back ...
created_at: 2025-05-16T16:35:06Z
author_association: COLLABORATOR

PR comments:
user: login: race-of-sloths
created_at: 2025-05-16T14:28:46Z
body: @frol Thank you for calling!
    
@vsavchyn-dev Thank you for the contribution! Join [Race of Sloths](https://race-of-sloths.com) by simply mentioning me in your comment/PRs description and start collecting Sloth Points through contributions to open source projects.

<details><summary>What is the Race of Sloths</summary>
<p>
Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

- Tag @race-of-sloths inside your pull requests
- Wait for the maintainer to review and score your pull request
- Check out your position in the [Leaderboard](https://race-of-sloths.com/leaderboard)
- Keep weekly and monthly streaks to reach higher positions
- Boast your contributions with a dynamic picture of your [Profile](https://race-of-sloths.com/profile/vsavchyn-dev)

For maintainers:
- Score pull requests that participate in the Race of Sloths and receive a reward
- Engage contributors with fair scoring and fast responses so they keep their streaks
- Promote the Race to the point where the Race starts promoting you
- Grow the community of your contributors

Feel free to check [our website](https://race-of-sloths.com) for additional details!
</p>
</details> 

<details>
<summary>Bot commands</summary>

- For contributors
  - **Include a PR:** `@race-of-sloths include` to enter the Race with your PR
- For maintainers:
  - **Invite contributor** `@race-of-sloths invite` to invite the contributor to participate in a race or include it, if it's already a runner.
  - **Assign points:** `@race-of-sloths score [1/2/3/5/8/13]` to award points based on your assessment.
  - **Reject this PR:** `@race-of-sloths exclude` to send this PR back to the drawing board.
  - **Exclude repo:** `@race-of-sloths pause` to stop bot activity in this repo until `@race-of-sloths unpause` command is called

</details>


author_association: NONE
user: login: dj8yfo
created_at: 2025-05-16T16:11:48Z
body: will add a few minor edits
author_association: COLLABORATOR
user: login: dj8yfo
created_at: 2025-05-16T19:33:44Z
body: @race-of-sloths score 13
author_association: COLLABORATOR
user: login: race-of-sloths
created_at: 2025-05-16T19:34:47Z
body: @dj8yfo Thank you for calling!
    
@vsavchyn-dev Thank you for the contribution! Join [Race of Sloths](https://race-of-sloths.com) by simply mentioning me in your comment/PRs description and start collecting Sloth Points through contributions to open source projects.

<details><summary>What is the Race of Sloths</summary>
<p>
Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

- Tag @race-of-sloths inside your pull requests
- Wait for the maintainer to review and score your pull request
- Check out your position in the [Leaderboard](https://race-of-sloths.com/leaderboard)
- Keep weekly and monthly streaks to reach higher positions
- Boast your contributions with a dynamic picture of your [Profile](https://race-of-sloths.com/profile/vsavchyn-dev)

For maintainers:
- Score pull requests that participate in the Race of Sloths and receive a reward
- Engage contributors with fair scoring and fast responses so they keep their streaks
- Promote the Race to the point where the Race starts promoting you
- Grow the community of your contributors

Feel free to check [our website](https://race-of-sloths.com) for additional details!
</p>
</details> 

<details>
<summary>Bot commands</summary>

- For contributors
  - **Include a PR:** `@race-of-sloths include` to enter the Race with your PR
- For maintainers:
  - **Invite contributor** `@race-of-sloths invite` to invite the contributor to participate in a race or include it, if it's already a runner.
  - **Assign points:** `@race-of-sloths score [1/2/3/5/8/13]` to award points based on your assessment.
  - **Reject this PR:** `@race-of-sloths exclude` to send this PR back to the drawing board.
  - **Exclude repo:** `@race-of-sloths pause` to stop bot activity in this repo until `@race-of-sloths unpause` command is called

</details>


author_association: NONE