diff --git a/rust/Cargo.lock b/rust/Cargo.lock index a04ccec6a..5e87aff49 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1718,6 +1718,7 @@ checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" name = "notus" version = "0.1.0" dependencies = [ + "clap", "models", "regex", "serde", diff --git a/rust/notus/Cargo.toml b/rust/notus/Cargo.toml index 030566817..58eaabc87 100644 --- a/rust/notus/Cargo.toml +++ b/rust/notus/Cargo.toml @@ -8,5 +8,7 @@ edition = "2021" [dependencies] regex = "1.10.2" serde_json = "1.0.96" -serde = { version = "1.0.163", features = ["derive"] } +serde = { version = "1.0.163" } +clap = { version = "~4" } + models = { path = "../models" } diff --git a/rust/notus/src/loader/json.rs b/rust/notus/src/loader/json.rs index c072d1ae2..735ae5151 100644 --- a/rust/notus/src/loader/json.rs +++ b/rust/notus/src/loader/json.rs @@ -15,14 +15,14 @@ use crate::error::Error; use super::AdvisoriesLoader; #[derive(Debug)] -pub struct JSONAdvisoriesLoader

+pub struct JSONAdvisoryLoader

where P: AsRef, { path: P, } -impl

JSONAdvisoriesLoader

+impl

JSONAdvisoryLoader

where P: AsRef, { @@ -43,7 +43,7 @@ where } } -impl

AdvisoriesLoader for JSONAdvisoriesLoader

+impl

AdvisoriesLoader for JSONAdvisoryLoader

where P: AsRef, { @@ -75,13 +75,13 @@ mod tests { use crate::{error::Error, loader::AdvisoriesLoader}; - use super::JSONAdvisoriesLoader; + use super::JSONAdvisoryLoader; #[test] fn test_load_advisories() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path).unwrap(); + let loader = JSONAdvisoryLoader::new(path).unwrap(); let _ = loader.load_package_advisories("debian_10").unwrap(); } @@ -90,7 +90,7 @@ mod tests { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data_foo"); assert!( - matches!(JSONAdvisoriesLoader::new(path.clone()).expect_err("Should fail"), Error::MissingAdvisoryDir(p) if p == path) + matches!(JSONAdvisoryLoader::new(path.clone()).expect_err("Should fail"), Error::MissingAdvisoryDir(p) if p == path) ); } @@ -99,7 +99,7 @@ mod tests { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data/debian_10.notus"); assert!( - matches!(JSONAdvisoriesLoader::new(path.clone()).expect_err("Should fail"), Error::AdvisoryDirIsFile(p) if p == path) + matches!(JSONAdvisoryLoader::new(path.clone()).expect_err("Should fail"), Error::AdvisoryDirIsFile(p) if p == path) ); } @@ -107,7 +107,7 @@ mod tests { fn test_err_unknown_os() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path).unwrap(); + let loader = JSONAdvisoryLoader::new(path).unwrap(); let os = "foo"; assert!( @@ -119,7 +119,7 @@ mod tests { fn test_err_json_parse() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path.clone()).unwrap(); + let loader = JSONAdvisoryLoader::new(path.clone()).unwrap(); let os = "debian_10_json_parse_err"; assert!( diff --git a/rust/notus/src/main.rs b/rust/notus/src/main.rs new file mode 100644 index 000000000..dc2d12f4f --- /dev/null +++ b/rust/notus/src/main.rs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2023 Greenbone AG +// +// SPDX-License-Identifier: GPL-2.0-or-later + +use std::{fs::File, io::Read, path::PathBuf}; + +use clap::{arg, value_parser, ArgAction, Command}; +use notus::{loader::json::JSONAdvisoryLoader, notus::Notus}; + +fn main() { + let matches = Command::new("nasl-cli") + .version("1.0") + .about("Is a CLI tool around Notus.") + .arg( + arg!(-p --path "Path to the notus advisories.") + .required(true) + .value_parser(value_parser!(PathBuf)), + ) + .arg(arg!(-s --os "To the packages corresponding operating system").required(true)) + .arg( + arg!(-f --"pkg-file" "Path to the notus packages to check for vulnerabilities, the file should contain a comma separated list of packages") + .required_unless_present("pkg-list") + .conflicts_with("pkg-list") + .value_parser(value_parser!(PathBuf)), + ) + .arg( + arg!(-l --"pkg-list" "A comma separated list of packages to check for vulnerabilities") + .required_unless_present("pkg-file"), + ) + .arg( + arg!(-n --pretty "Enables pretty printing for the result").action(ArgAction::SetTrue) + ) + .get_matches(); + + let advisory_path = matches.get_one::("path").unwrap(); + let loader = match JSONAdvisoryLoader::new(advisory_path) { + Ok(loader) => loader, + Err(err) => { + eprintln!("{err}"); + return; + } + }; + + let packages = match matches.get_one::("pkg-file") { + Some(path) => { + let mut buf = String::new(); + File::open(path).unwrap().read_to_string(&mut buf).unwrap(); + buf.split(",").map(str::to_string).collect::>() + } + None => { + let list = matches.get_one::("pkg-list").unwrap(); + list.split(",").map(str::to_string).collect::>() + } + }; + + let os = matches.get_one::("os").unwrap(); + + let mut notus = Notus::new(loader); + match notus.scan(os, &packages) { + Ok(results) => { + let json = match matches.contains_id("pretty") { + true => serde_json::to_string_pretty(&results).unwrap(), + false => serde_json::to_string(&results).unwrap(), + }; + + println!("{json}"); + } + Err(err) => eprintln!("{err}"), + } +} diff --git a/rust/notus/tests/notus.rs b/rust/notus/tests/notus.rs index 5830bbe6a..e6bd44275 100644 --- a/rust/notus/tests/notus.rs +++ b/rust/notus/tests/notus.rs @@ -6,13 +6,13 @@ mod tests { use models::{FixedPackage, FixedVersion, Specifier}; - use notus::{error::Error, loader::json::JSONAdvisoriesLoader, notus::Notus}; + use notus::{error::Error, loader::json::JSONAdvisoryLoader, notus::Notus}; #[test] fn test_notus() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path.clone()).unwrap(); + let loader = JSONAdvisoryLoader::new(path.clone()).unwrap(); let mut notus = Notus::new(loader); let packages = vec![ @@ -65,7 +65,7 @@ mod tests { fn test_err_package_parse_error() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path.clone()).unwrap(); + let loader = JSONAdvisoryLoader::new(path.clone()).unwrap(); let mut notus = Notus::new(loader); let pkg_name = "wepofkewf~.124.sdefpo3-_~s#"; @@ -82,7 +82,7 @@ mod tests { fn test_err_advisory_parse_error() { let mut path = env!("CARGO_MANIFEST_DIR").to_string(); path.push_str("/data"); - let loader = JSONAdvisoriesLoader::new(path.clone()).unwrap(); + let loader = JSONAdvisoryLoader::new(path.clone()).unwrap(); let mut notus = Notus::new(loader); let packages = vec![];