-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
57 pragma declarations and version control (#64)
* Add soroban-version detector with test cases
- Loading branch information
Showing
9 changed files
with
245 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "soroban-version" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
dylint_linting = { workspace = true } | ||
if_chain = { workspace = true } | ||
semver = "1.0.4" | ||
serde_json = "1.0" | ||
toml = "0.8.8" | ||
ureq = { version = "2.7.1", features = ["json"] } | ||
|
||
scout-audit-internal = { workspace = true } | ||
|
||
[dev-dependencies] | ||
dylint_testing = { workspace = true } | ||
|
||
[package.metadata.rust-analyzer] | ||
rustc_private = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#![feature(rustc_private)] | ||
|
||
extern crate rustc_ast; | ||
extern crate rustc_hir; | ||
extern crate rustc_span; | ||
|
||
use std::{env, fs, io::Error, path::Path}; | ||
|
||
use rustc_ast::Crate; | ||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; | ||
use scout_audit_internal::Detector; | ||
use semver::*; | ||
|
||
dylint_linting::declare_early_lint! { | ||
/// ### What it does | ||
/// Checks the soroban version of the contract | ||
/// | ||
/// ### Why is this bad? | ||
/// Using an outdated version of soroban could lead to security vulnerabilities, bugs, and other issues. | ||
pub CHECK_SOROBAN_VERSION, | ||
Warn, | ||
Detector::SorobanVersion.get_lint_message() | ||
} | ||
|
||
impl EarlyLintPass for CheckSorobanVersion { | ||
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) { | ||
let latest_version = match get_version() { | ||
Ok(version) => version, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!("Failed to get the latest Soroban version: {}", e)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let manifest_dir = match env::var("CARGO_MANIFEST_DIR") { | ||
Ok(dir) => dir, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!( | ||
"Environment variable CARGO_MANIFEST_DIR not found: {}", | ||
e | ||
)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let cargo_toml_path = Path::new(&manifest_dir).join("Cargo.toml"); | ||
let cargo_toml = match fs::read_to_string(cargo_toml_path) { | ||
Ok(content) => content, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!("Unable to read Cargo.toml: {}", e)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let toml: toml::Value = match toml::from_str(&cargo_toml) { | ||
Ok(value) => value, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!("Error parsing Cargo.toml: {}", e)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let soroban_version = match toml | ||
.get("dependencies") | ||
.and_then(|d| d.get("soroban-sdk").and_then(|i| i.get("version"))) | ||
{ | ||
Some(version) => version.to_string(), | ||
None => { | ||
cx.sess() | ||
.struct_warn("Soroban dependency not found in Cargo.toml") | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let req = match Version::parse(&latest_version.replace('\"', "")) { | ||
Ok(version) => version, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!("Error parsing latest Soroban version: {}", e)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
let soroban_version = match VersionReq::parse(&soroban_version.replace('\"', "")) { | ||
Ok(version) => version, | ||
Err(e) => { | ||
cx.sess() | ||
.struct_warn(format!("Error parsing project's Soroban version: {}", e)) | ||
.emit(); | ||
return; | ||
} | ||
}; | ||
|
||
if !soroban_version.matches(&req) { | ||
Detector::SorobanVersion.span_lint_and_help( | ||
cx, | ||
CHECK_SOROBAN_VERSION, | ||
rustc_span::DUMMY_SP, | ||
&format!(r#"The latest Soroban version is {latest_version}, and your version is "{soroban_version}""#), | ||
); | ||
} | ||
} | ||
} | ||
|
||
fn get_version() -> Result<String, String> { | ||
let response = ureq::get("https://crates.io/api/v1/crates/soroban-sdk") | ||
.set("User-Agent", "Scout/1.0") | ||
.call(); | ||
|
||
match response { | ||
Ok(resp) => { | ||
let json: Result<serde_json::Value, Error> = resp.into_json(); | ||
match json { | ||
Ok(json) => json | ||
.get("crate") | ||
.and_then(|c| c.get("max_stable_version")) | ||
.map(|v| v.to_string()) | ||
.ok_or_else(|| "Failed to parse Soroban version from response".to_string()), | ||
Err(_) => Err("Failed to parse response from crates.io".to_string()), | ||
} | ||
} | ||
Err(_) => Err("Failed to get Soroban version from crates.io".to_string()), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "soroban-version-remediated-1" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
soroban-sdk = { version = "=20.0.3" } | ||
|
||
[dev_dependencies] | ||
soroban-sdk = { version = "=20.0.3", features = ["testutils"] } | ||
|
||
[features] | ||
testutils = ["soroban-sdk/testutils"] | ||
|
||
[profile.release] | ||
opt-level = "z" | ||
overflow-checks = true | ||
debug = 0 | ||
strip = "symbols" | ||
debug-assertions = false | ||
panic = "abort" | ||
codegen-units = 1 | ||
lto = true | ||
|
||
[profile.release-with-logs] | ||
inherits = "release" | ||
debug-assertions = true |
11 changes: 11 additions & 0 deletions
11
test-cases/soroban-version/soroban-version-1/remediated-example/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#![no_std] | ||
|
||
use soroban_sdk::{contract, contractimpl}; | ||
|
||
#[contract] | ||
pub struct Contract; | ||
|
||
#[contractimpl] | ||
impl Contract { | ||
// Empty contract - vulnerability is in the Cargo.toml | ||
} |
31 changes: 31 additions & 0 deletions
31
test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
[package] | ||
name = "soroban-version-vulnerable-1" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
soroban-sdk = { version = "=20.0.0" } | ||
|
||
[dev_dependencies] | ||
soroban-sdk = { version = "=20.0.0", features = ["testutils"] } | ||
|
||
[features] | ||
testutils = ["soroban-sdk/testutils"] | ||
|
||
[profile.release] | ||
opt-level = "z" | ||
overflow-checks = true | ||
debug = 0 | ||
strip = "symbols" | ||
debug-assertions = false | ||
panic = "abort" | ||
codegen-units = 1 | ||
lto = true | ||
|
||
[profile.release-with-logs] | ||
inherits = "release" | ||
debug-assertions = true |
11 changes: 11 additions & 0 deletions
11
test-cases/soroban-version/soroban-version-1/vulnerable-example/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#![no_std] | ||
|
||
use soroban_sdk::{contract, contractimpl}; | ||
|
||
#[contract] | ||
pub struct Contract; | ||
|
||
#[contractimpl] | ||
impl Contract { | ||
// Empty contract - vulnerability is in the Cargo.toml | ||
} |