Skip to content

Commit

Permalink
Merge pull request #22 from CoinFabrik/detector-info
Browse files Browse the repository at this point in the history
Detector info
  • Loading branch information
faculerena authored Apr 11, 2024
2 parents bd008bb + 8d430cd commit 27c7941
Show file tree
Hide file tree
Showing 18 changed files with 1,120 additions and 1,427 deletions.
1,446 changes: 865 additions & 581 deletions apps/cargo-scout-audit/Cargo.lock

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions apps/cargo-scout-audit/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cargo-scout-audit"
version = "0.2.4"
version = "0.2.6"
edition = "2021"
authors = [
"Agustin Aon <agustin.aon@coinfabrik.com>",
Expand All @@ -27,16 +27,18 @@ name = "cargo-scout-audit"
[dependencies]
ansi_term = "0.12.1"
anyhow = "1"
cargo = "0.72.2"
cargo = "0.76.0"
cargo_metadata = "0.18.1"
chrono = { version = "0.4.34", features = ["serde"] }
clap = { version = "4.3.0", features = ["derive"] }
current_platform = "0.2.0"
dunce = "1.0.4"
dylint = { version = "2.3.0"}
env_logger = "0.11.2"
home = { version = "0.5.5" }
itertools = "0.12.1"
lazy_static = "=1.4.0"
libloading = "0.8"
log = "0.4"
regex = { version = "1.5", features = ["unicode"] }
serde = { version = "1.0.163", features = ["derive"] }
Expand All @@ -45,8 +47,12 @@ tempfile = "3.8"
toml = { version = "0.8.0" }
tera = {version = "=1.19.1", features=["builtins"]}
webbrowser = "=0.8.12"
<<<<<<< HEAD
pulldown-cmark = "0.10.0"
=======

scout-audit-internal = { version = "0.2.3", path = "../../scout-audit-internal", features = ["detector"] }
>>>>>>> main

[dev-dependencies]
colored = "2.0.0"
Expand Down
9 changes: 6 additions & 3 deletions apps/cargo-scout-audit/src/detectors/source/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use std::path::PathBuf;

use anyhow::{anyhow, bail, ensure, Result};
use cargo::{
core::{source::MaybePackage, Dependency, Package, PackageId, QueryKind, Source},
core::{Dependency, Package, PackageId},
sources::source::{MaybePackage, QueryKind, Source},
util::cache_lock::CacheLockMode,
Config,
};

/// Downloads git repo using cargo native cache and returns its path.
pub fn download_git_repo(dependency: &Dependency, config: &Config) -> Result<PathBuf> {
let _lock = config.acquire_package_cache_lock()?;
let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
let mut source = dependency.source_id().load(config, &Default::default())?;
let package_id = sample_package_id(dependency, &mut *source)?;

Expand Down Expand Up @@ -48,7 +50,8 @@ fn git_dependency_root_from_package<'a>(

if source.source_id().is_git() {
let git_path = config.git_path();
let git_path = config.assert_package_cache_locked(&git_path);
let git_path =
config.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &git_path);
ensure!(
package_root.starts_with(git_path.join("checkouts")),
"Unexpected path: {}",
Expand Down
1 change: 0 additions & 1 deletion apps/cargo-scout-audit/src/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ pub mod markdown;
pub mod pdf;
pub mod report;
pub mod utils;
pub mod vulnerabilities;
162 changes: 52 additions & 110 deletions apps/cargo-scout-audit/src/output/report.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use anyhow::Result;
use chrono::offset::Local;
use core::panic;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::Path;
use std::{collections::HashMap, os::unix::process::CommandExt};

use super::{html, markdown, pdf, vulnerabilities::*};
use super::{html, markdown, pdf};

#[derive(Serialize, Deserialize, Debug)]
pub struct Report {
Expand Down Expand Up @@ -97,32 +96,27 @@ impl Report {
}
}

pub struct RawVulnerability {
pub id: &'static str,
pub name: &'static str,
pub short_message: &'static str,
pub long_message: &'static str,
pub severity: &'static str,
pub help: &'static str,
pub vulnerability_class: &'static str,
}

impl From<RawVulnerability> for Vulnerability {
fn from(finding: RawVulnerability) -> Self {
impl From<&LintInfo> for Vulnerability {
fn from(lint_info: &LintInfo) -> Self {
Vulnerability {
id: finding.id.to_string(),
name: finding.name.to_string(),
short_message: finding.short_message.to_string(),
long_message: finding.long_message.to_string(),
severity: finding.severity.to_string(),
help: finding.help.to_string(),
id: lint_info.id.clone(),
name: lint_info.name.clone(),
short_message: lint_info.short_message.clone(),
long_message: lint_info.long_message.clone(),
severity: lint_info.severity.clone(),
help: lint_info.help.clone(),
}
}
}

use crate::startup::ProjectInfo;
use crate::utils::detectors_info::LintInfo;

pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: BlockChain) -> Report {
pub fn generate_report(
scout_output: String,
info: ProjectInfo,
detector_info: HashMap<String, LintInfo>,
) -> Report {
let scout_findings = scout_output
.lines()
.map(|line| serde_json::from_str::<serde_json::Value>(line).unwrap())
Expand All @@ -131,17 +125,12 @@ pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: Bloc
.get("message")
.and_then(|message| message.get("code"))
.and_then(|code| code.get("code"))
.and_then(|code| code.as_str())
.filter(|code| blockchain.get_array_of_vulnerability_names().contains(code))
.is_some()
})
.collect::<Vec<Value>>();

let mut det_map: HashMap<_, _> = blockchain
.get_array_of_vulnerability_names()
.iter()
.map(|&detector| (detector.to_string(), 0))
.collect();
let mut id: u32 = 0;
let mut det_map: HashMap<String, u32> = HashMap::new();

let mut findings: Vec<Finding> = Vec::new();

Expand Down Expand Up @@ -207,10 +196,11 @@ pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: Bloc
let fndg = Finding {
id: id as u32,
occurrence_index: *v,
category_id: blockchain
.get_raw_vuln_from_name(&category)
.vulnerability_class
.to_string(),
category_id: detector_info
.get(&category)
.map_or("Local detector".to_owned(), |f| {
f.vulnerability_class.clone()
}),
vulnerability_id: category,
error_message,
span,
Expand All @@ -230,10 +220,24 @@ pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: Bloc

let mut categories: Vec<Category> = Vec::new();

for vuln in summary_map.keys() {
let raw_vuln = blockchain.get_raw_vuln_from_name(vuln);
let id = raw_vuln.vulnerability_class.to_string();
let vuln = Vulnerability::from(raw_vuln);
for (vuln_id, _) in &summary_map {
let info = detector_info.get::<String>(vuln_id);
let vuln = match info {
Some(lint_info) => Vulnerability::from(lint_info),
None => Vulnerability {
id: vuln_id.to_string(),
name: "Local detector:".to_owned() + vuln_id,
short_message: "".to_owned(),
long_message: "".to_owned(),
severity: "unknown".to_owned(),
help: "".to_owned(),
},
};
let id = detector_info
.get::<String>(vuln_id)
.map_or("Local detector".to_owned(), |f| {
f.vulnerability_class.clone()
});

if categories.iter().any(|cat| cat.id == id) {
let cat = categories.iter_mut().find(|cat| cat.id == id).unwrap();
Expand All @@ -251,25 +255,28 @@ pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: Bloc
}
}

let mut vulns_by_severity = vec![
let mut by_severity: HashMap<String, u32> = [
("critical".to_string(), 0),
("medium".to_string(), 0),
("minor".to_string(), 0),
("enhancement".to_string(), 0),
];
("unknown".to_string(), 0),
]
.iter()
.cloned()
.collect();

for (vuln, count) in &summary_map {
let severity = blockchain.get_raw_vuln_from_name(vuln).severity.to_string();
let severity_count = vulns_by_severity
.iter_mut()
.find(|(s, _)| s.to_lowercase() == severity.to_lowercase())
.unwrap();
severity_count.1 += count;
let severity = detector_info
.get(vuln)
.map_or("unknown".to_owned(), |f| f.severity.clone());
let severity_count = by_severity.get_mut(&severity.to_lowercase()).unwrap();
*severity_count += count;
}

let summary = Summary {
total_vulnerabilities: findings.len() as u32,
by_severity: vulns_by_severity.into_iter().collect(),
by_severity,
};

let date = format!(
Expand All @@ -288,68 +295,3 @@ pub fn generate_report(scout_output: String, info: ProjectInfo, blockchain: Bloc
findings,
)
}

use crate::startup::BlockChain;

trait GetRawVulnerabilities {
fn get_raw_vuln_from_name(&self, name: &str) -> RawVulnerability;
fn get_array_of_vulnerability_names(&self) -> Vec<&'static str>;
}

impl GetRawVulnerabilities for BlockChain {
fn get_raw_vuln_from_name(&self, name: &str) -> RawVulnerability {
match &self {
BlockChain::Ink => match name {
"assert_violation" => INK_ASSERT_VIOLATION,
"avoid_std_core_mem_forget" => INK_AVOID_STD_CORE_MEM_FORGET,
"avoid_format_string" => INK_AVOID_FORMAT_STRING,
"delegate_call" => INK_DELEGATE_CALL,
"divide_before_multiply" => INK_DIVIDE_BEFORE_MULTIPLY,
"dos_unbounded_operation" => INK_DOS_UNBOUNDED_OPERATION,
"unexpected_revert_warn" => INK_UNEXPECTED_REVERT_WARN,
"check_ink_version" => INK_CHECK_INK_VERSION,
"insufficiently_random_values" => INK_INSUFFICIENTLY_RANDOM_VALUES,
"integer_overflow_underflow" => INK_INTEGER_OVERFLOW_UNDERFLOW,
"iterator_over_indexing" => INK_ITERATOR_OVER_INDEXING,
"lazy_delegate" => INK_LAZY_DELEGATE,
"panic_error" => INK_PANIC_ERROR,
"reentrancy_1" => INK_REENTRANCY,
"reentrancy_2" => INK_REENTRANCY,
"unprotected_set_code_hash" => INK_UNPROTECTED_SET_CODE_HASH,
"set_storage_warn" => INK_SET_STORAGE_WARN,
"unprotected_mapping_operation" => INK_UNPROTECTED_MAPPING_OPERATION,
"unprotected_self_destruct" => INK_UNPROTECTED_SELF_DESTRUCT,
"unrestricted_transfer_from" => INK_UNRESTRICTED_TRANSFER_FROM,
"unsafe_expect" => INK_UNSAFE_EXPECT,
"unsafe_unwrap" => INK_UNSAFE_UNWRAP,
"unused_return_enum" => INK_UNUSED_RETURN_ENUM,
"zero_or_test_address" => INK_ZERO_OR_TEST_ADDRESS,
_ => panic!("Unknown vulnerability name: {}", name),
},
BlockChain::Soroban => match name {
"avoid_core_mem_forget" => SOROBAN_AVOID_CORE_MEM_FORGET,
"avoid_panic_error" => SOROBAN_AVOID_PANIC_ERROR,
"avoid_unsafe_block" => SOROBAN_AVOID_UNSAFE_BLOCK,
"divide_before_multiply" => SOROBAN_DIVIDE_BEFORE_MULTIPLY,
"dos_unbounded_operation" => SOROBAN_DOS_UNBOUNDED_OPERATION,
"insufficiently_random_values" => SOROBAN_INSUFFICIENTLY_RANDOM_VALUES,
"overflow_check" => SOROBAN_OVERFLOW_CHECK,
"set_contract_storage" => SOROBAN_SET_CONTRACT_STORAGE,
"soroban_version" => SOROBAN_SOROBAN_VERSION,
"unprotected_update_current_contract_wasm" => {
SOROBAN_UNPROTECTED_UPDATE_CURRENT_CONTRACT_WASM
}
"unsafe_expect" => SOROBAN_UNSAFE_EXPECT,
"unsafe_unwrap" => SOROBAN_UNSAFE_UNWRAP,
"unused_return_enum" => SOROBAN_UNUSED_RETURN_ENUM,
_ => panic!("Unknown vulnerability name: {}", name),
},
}
}
fn get_array_of_vulnerability_names(&self) -> std::vec::Vec<&'static str> {
match &self {
BlockChain::Ink => INK_DETECTORS.to_vec(),
BlockChain::Soroban => SOROBAN_DETECTORS.to_vec(),
}
}
}
Loading

0 comments on commit 27c7941

Please sign in to comment.