diff --git a/.github/workflows/helm-build-chart.yml b/.github/workflows/helm-build-chart.yml index ae54a7236..2ba0d1115 100644 --- a/.github/workflows/helm-build-chart.yml +++ b/.github/workflows/helm-build-chart.yml @@ -6,6 +6,10 @@ on: branches: [main] workflow_dispatch: +env: + API_KEY: changeme + OPENVASD: 127.0.0.1:8080 + jobs: openvasd: runs-on: ubuntu-latest @@ -21,7 +25,19 @@ jobs: helm uninstall openvasd || true helm install openvasd charts/openvasd/ --values charts/openvasd/values.yaml kubectl rollout status --watch --timeout 600s deployment/openvasd - helm test openvasd + sleep 5 + #helm test openvasd + - id: smoketest + run: echo "POD_NAME=$(kubectl get pods |grep openvasd | awk '{print $1;}')" >> $GITHUB_OUTPUT + - name: forward port + run: | + echo "POD_NAME: ${{ steps.smoketest.outputs.POD_NAME }}" + echo "$(kubectl get pods)" + #kubectl --namespace default port-forward ${{ steps.smoketest.outputs.POD_NAME }} 8080:3000 & + - name: smoketest + working-directory: rust/smoketest + run: | + make build run - uses: greenbone/actions/helm-build-push@v3 if: github.event_name == 'workflow_dispatch' with: @@ -29,4 +45,4 @@ jobs: registry: ${{ vars.IMAGE_REGISTRY }} registry-subpath: helm-charts/ registry-user: ${{ secrets.GREENBONE_BOT }} - registry-token: ${{ secrets.GREENBONE_BOT_PACKAGES_WRITE_TOKEN }} \ No newline at end of file + registry-token: ${{ secrets.GREENBONE_BOT_PACKAGES_WRITE_TOKEN }} diff --git a/rust/Cargo.lock b/rust/Cargo.lock index fe11398ed..43d0f1ca5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -84,24 +84,23 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -123,9 +122,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -327,9 +326,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.23" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03aef18ddf7d879c15ce20f04826ef8418101c7e528014c3eeea13321047dca3" +checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" dependencies = [ "clap_builder", "clap_derive", @@ -338,9 +337,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.23" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ce6fffb678c9b80a70b6b6de0aad31df727623a70fd9a842c30cd573e2fa98" +checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" dependencies = [ "anstream", "anstyle", @@ -350,9 +349,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" dependencies = [ "heck", "proc-macro2", @@ -362,9 +361,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "cmac" @@ -564,6 +563,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -979,6 +987,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" + [[package]] name = "ipnetwork" version = "0.20.0" @@ -1138,6 +1152,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1845,6 +1865,45 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "reqwest" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + [[package]] name = "ring" version = "0.16.20" @@ -2009,18 +2068,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.185" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31" +checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.185" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec" +checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" dependencies = [ "proc-macro2", "quote", @@ -2047,6 +2106,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha1" version = "0.10.5" @@ -2108,6 +2179,20 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +[[package]] +name = "smoketest" +version = "0.1.0" +dependencies = [ + "clap", + "models", + "reqwest", + "serde", + "serde_json", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "socket2" version = "0.4.9" @@ -2566,6 +2651,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -2605,6 +2702,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + [[package]] name = "winapi" version = "0.3.9" @@ -2756,9 +2859,19 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d09770118a7eb1ccaf4a594a221334119a44a814fcb0d31c5b85e83e97227a97" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d76034b8c..ccc7da66a 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -24,4 +24,5 @@ members = [ "osp", "openvasd", "scanconfig", + "smoketest", ] diff --git a/rust/models/src/host_info.rs b/rust/models/src/host_info.rs index 073f9245a..59b7a01ad 100644 --- a/rust/models/src/host_info.rs +++ b/rust/models/src/host_info.rs @@ -23,8 +23,8 @@ pub struct HostInfo { pub finished: u32, #[cfg_attr( feature = "serde_support", - serde(skip_serializing_if = "Vec::is_empty") + serde(skip_serializing_if = "Option::is_none") )] /// IPs of hosts, that are currently scanned. - pub scanning: Vec, + pub scanning: Option>, } diff --git a/rust/osp/src/response.rs b/rust/osp/src/response.rs index 9bafea589..6e7982aa5 100644 --- a/rust/osp/src/response.rs +++ b/rust/osp/src/response.rs @@ -613,7 +613,7 @@ impl From for models::Status { - i.count_alive.content.0 - i.host.len() as u32, finished: i.count_alive.content.0, - scanning, + scanning: Some(scanning), }), } } diff --git a/rust/smoketest/Cargo.toml b/rust/smoketest/Cargo.toml new file mode 100644 index 000000000..d5e1cc625 --- /dev/null +++ b/rust/smoketest/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "smoketest" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +models = {path = "../models"} +clap = { version = "4.4.0", features = ["derive"] } +reqwest = { version = "0.11.20", features = ["rustls-tls", "blocking", "json"], default-features=false } +tokio = { version = "1.32.0", features = ["full"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +serde = {version = "1", features = ["derive"], optional = true} +serde_json = "1" + +[features] +default = ["serde_support"] +serde_support = ["serde"] + +[dev-dependencies] +serde_json = "1" diff --git a/rust/smoketest/Makefile b/rust/smoketest/Makefile new file mode 100644 index 000000000..0756bdaf5 --- /dev/null +++ b/rust/smoketest/Makefile @@ -0,0 +1,44 @@ +# SPDX-FileCopyrightText: 2023 Greenbone AG +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +.PHONY: build run-with-certs + +MAKEFILE_PATH := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +ifdef TARGET_HOSTNAME +TARGET := $(TARGET_HOSTNAME) +else +TARGET := 127.0.0.1 +endif + +ifdef OPENVASD +SERVER := $(OPENVASD) +else +SERVER := 127.0.0.1:3000 +endif + +ifndef CARGO + CARGO := cargo +endif + +ifndef TARGET_USERNAME + TARGET_USERNAME := noname + TARGET_PASSWORD := nopass +endif + +all: build run-with-certs + +build: prepare-scan + ${CARGO} build + +run: + ../target/debug/smoketest --openvasd http://$(SERVER) --api-key $(API_KEY) --scan-config ./simple_scan_ssh_only.json + +run-with-certs: + ../target/debug/smoketest --openvasd https://$(SERVER) --cert $(CLIENT_CERT) --key $(CLIENT_KEY) --api-key $(API_KEY) --scan-config ./simple_scan_ssh_only.json + +prepare-scan: + sed -i 's||'$(TARGET_USERNAME)'|' simple_scan_ssh_only.json + sed -i 's||'$(TARGET_PASSWORD)'|' simple_scan_ssh_only.json + sed -i 's||'$(TARGET)'|' simple_scan_ssh_only.json diff --git a/rust/smoketest/README.md b/rust/smoketest/README.md new file mode 100644 index 000000000..01177d1e9 --- /dev/null +++ b/rust/smoketest/README.md @@ -0,0 +1,48 @@ +# smoke-test + +Contains a small subset of functionality tests for openvasd within a controlled environment. + +To build and run the tests a Makefile is provided: +- make build - builds the smoketest binary +- make run - runs a scan against an scanner API listening on http://127.0.0.1:3000 using the API KEY authentication method +- make run-with-certs - runs a scan against an scanner API listening on https://127.0.0.1:3000 using the mTLS authentication method plus API KEY + +## Configuration +Independent of the usage of the certificates, the api-key is required. Therefore, `openvasd` must have an api-key set. For details on how to configure it, see the [openvasd documentation](../openvasd/README.md). + +In case of running the test against a mTLS enabled `openvasd`, you need to configure the client key and cert as well in the smoke test environment. For details on how to configure it, see the [openvasd documentation](../openvasd/README.md). + +For creation of the key/cert pair for mTLS authentication, see the tls section in the [openvasd documentation](../openvasd/README.md). Also, you find certificate generators in the [examples](../examples/tls) + +For authenticated scans, you can set a custom target (default is 127.0.0.1), username and password. + +All settings for running the smoke-tests are set via environmental variables. The next table summarize the settings availables: + +|Variable|Description|Default|Mandatory|Comment| +|--------|-----------|-------|---------|-------| +|TARGET_HOSTNAME|Custom target|127.0.0.1|no|Necessary for authenticated scans| +|TARGET_USERNAME|Username for login in the target during the authenticated scan|empty string|no|Necessary for authenticated scans| +|TARGET_PASSWORD|Password for login in the target during the authenticated scan|empty string|no|Necessary for authenticated scans| +|API_KEY|API Key for authenticated communication with `openvasd`|mtls_is_preferred|yes|| +|OPENVASD|Socket where openvasd listen on|127.0.0.1:3000|no|Must be specified with port| +|CLIENT_CERT|PEM file combinating public certificate and any 3rd party intermediate certificates ||yes for mTLS|Necessary for mTLS enabled| +|CLIENT_KEY|Client private key||yes for mTLS|Necessary for mTLS enabled| + + +## Usage + +``` bash +# set env variables +export CLIENT_CERT=/tmp/cert.pem +export CLIENT_KEY=/tmp/key.pem +export OPENVASD=192.168.0.1:3000 +export TARGET_HOSTNAME=192.168.10.10 +export TARGET_USERNAME=user +export TARGET_PASSWORD=pass +export API_KEY=mtls_is_preferred + +#build and run +make build +make run-with-certs +``` + diff --git a/rust/smoketest/simple_scan_ssh_only.json b/rust/smoketest/simple_scan_ssh_only.json new file mode 100644 index 000000000..dad15bed2 --- /dev/null +++ b/rust/smoketest/simple_scan_ssh_only.json @@ -0,0 +1,29 @@ +{"target": {"hosts": [""], + "ports": [ + { + "protocol": "tcp", + "range": [ + { + "start": 22, + "end": 22 + } + ] + } + ], + "credentials": [ + { + "service": "ssh", + "port": 22, + "up": { + "username": "", + "password": "" + } + } + ] + }, + "vts": [ + { + "oid": "1.3.6.1.4.1.25623.1.0.90022" + } + ] +} diff --git a/rust/smoketest/src/config.rs b/rust/smoketest/src/config.rs new file mode 100644 index 000000000..935f52afc --- /dev/null +++ b/rust/smoketest/src/config.rs @@ -0,0 +1,39 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Args { + /// openvasd + #[arg(short, long)] + openvasd: String, + /// Scan Config + #[arg(short, long)] + scan_config: String, + /// API KEY + #[arg(short, long)] + api_key: Option, + /// Client certificate + #[arg(short, long)] + cert: Option, + /// Client private key + #[arg(short, long)] + key: Option, +} + +impl Args { + pub fn openvasd(&self) -> &String { + &self.openvasd + } + pub fn scan_config(&self) -> &String { + &self.scan_config + } + pub fn api_key(&self) -> &Option { + &self.api_key + } + pub fn key(&self) -> &Option { + &self.key + } + pub fn cert(&self) -> &Option { + &self.cert + } +} diff --git a/rust/smoketest/src/config/config.rs b/rust/smoketest/src/config/config.rs new file mode 100644 index 000000000..8c3005beb --- /dev/null +++ b/rust/smoketest/src/config/config.rs @@ -0,0 +1,17 @@ + +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Args { + /// openvasd + #[arg(short, long)] + openvasd: String, + + /// Scan Config + #[arg(short, long)] + scan_config: String, + /// Scan Config + #[arg(short, long)] + api_key: Option, +} diff --git a/rust/smoketest/src/lib.rs b/rust/smoketest/src/lib.rs new file mode 100644 index 000000000..c382c0495 --- /dev/null +++ b/rust/smoketest/src/lib.rs @@ -0,0 +1,171 @@ +use models::{Phase, Result as ScanResult, Status}; +use reqwest::header; + +use std::collections::HashMap; +use std::fs::File; +use std::io::prelude::*; + +/// Creates a new client setting the header, API-KEY and Certs if existing +pub fn new_client( + apikey: &Option, + cert: &Option, + key: &Option, +) -> reqwest::Client { + let mut headers = header::HeaderMap::new(); + if let Some(k) = apikey { + headers.insert("X-API-KEY", header::HeaderValue::from_str(k).unwrap()); + } + headers.insert( + "Content-Type", + header::HeaderValue::from_static("application/json"), + ); + let cli = reqwest::Client::builder().default_headers(headers); + + // There are key-cert credentials + if let Some(k) = key { + if let Some(c) = cert { + let mut file = File::open(k).unwrap(); + let mut ident = String::new(); + file.read_to_string(&mut ident).unwrap(); + + let mut file = File::open(c).unwrap(); + let mut aux = String::new(); + file.read_to_string(&mut aux).unwrap(); + + ident.push_str(&aux); + let identity = reqwest::Identity::from_pem(&ident.into_bytes()).unwrap(); + return cli + .identity(identity) + .danger_accept_invalid_certs(true) + .build() + .unwrap(); + } + } + + cli.build().unwrap() +} + +/// Stores the Scan Config and returns the received ScanID, to be used in further requests. +pub async fn create_scan( + cli: &reqwest::Client, + server: &String, + scan_config: &String, +) -> Option { + let mut file = File::open(scan_config).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + + let mut path = String::from(server); + path.push_str("/scans"); + let res = cli.post(path).body(content).send().await.unwrap(); + + if res.status().is_success() { + tracing::info!("\tCreating scan config OK"); + let id = res.json().await.unwrap(); + return Some(id); + } + + tracing::info!("\tCreating scan config '{scan_config}' FAILED"); + None +} + +/// Sends an action for the given ScanID. +pub async fn scan_action( + cli: &reqwest::Client, + server: &String, + id: &String, + action: String, +) -> bool { + let mut path = String::from(server); + path.push_str("/scans/"); + path.push_str(id.as_str()); + + let mut data = HashMap::new(); + data.insert("action", action.as_str()); + let res = cli.post(path).json(&data).send().await.unwrap(); + + if res.status().is_success() { + tracing::info!("\tSend scan action {action} OK"); + return true; + } + + tracing::info!("\tSend scan action {action} FAILED"); + false +} + +/// Given an ScanID, it fetches the current scan status. +pub async fn scan_status(cli: &reqwest::Client, server: &String, id: &String) -> Option { + let mut path = String::from(server); + path.push_str("/scans/"); + path.push_str(id.as_str()); + path.push_str("/status"); + + let res = cli.get(path).send().await.unwrap(); + + if res.status().is_success() { + let data = res.text().await.unwrap(); + if data.is_empty() { + return None; + } + let status: Result = serde_json::from_str(data.as_str()); + match status { + Ok(st) => { + return Some(st.status); + } + Err(err) => { + println!("{:?}", err); + return None; + } + } + } + tracing::info!("\tGet scan status FAILED"); + None +} + +/// Given an ScanID, it fetches the current scan results. +pub async fn scan_results( + cli: &reqwest::Client, + server: &String, + id: &String, +) -> Option> { + let mut path = String::from(server); + path.push_str("/scans/"); + path.push_str(id.as_str()); + path.push_str("/results"); + + let res = cli.get(path).send().await.unwrap(); + + if res.status().is_success() { + let data = res.text().await.unwrap(); + if data.is_empty() { + return None; + } + let results: Result, _> = serde_json::from_str(data.as_str()); + match results { + Ok(res) => { + return Some(res); + } + Err(err) => { + println!("{:?}", err); + return None; + } + } + } + tracing::info!("\tGet scan results FAILED"); + None +} + +pub async fn delete_scan(cli: &reqwest::Client, server: &String, id: &String) -> bool { + let mut path = String::from(server); + path.push_str("/scans/"); + path.push_str(id.as_str()); + + let res = cli.delete(path).send().await.unwrap(); + + if res.status().is_success() { + tracing::info!("\tDelete scan OK"); + return true; + } + tracing::info!("\tDelete scan FAILED"); + false +} diff --git a/rust/smoketest/src/main.rs b/rust/smoketest/src/main.rs new file mode 100644 index 000000000..e42956d7e --- /dev/null +++ b/rust/smoketest/src/main.rs @@ -0,0 +1,32 @@ +mod config; +mod tests; + +use std::process::ExitCode; + +use crate::tests::*; +use clap::Parser; +use config::Args; +use smoketest::new_client; + +#[tokio::main] +async fn main() -> ExitCode{ + let args = Args::parse(); + let filter = tracing_subscriber::EnvFilter::builder() + .with_default_directive(tracing::metadata::LevelFilter::INFO.into()) + .parse_lossy("INFO"); + tracing_subscriber::fmt().with_env_filter(filter).init(); + + let cli = new_client(args.api_key(), args.cert(), args.key()); + tracing::info!("Starting smoke test"); + tracing::info!("\n\nTEST 1: Check server connection:"); + if !test1::check_server(&cli, args.openvasd()).await { + tracing::info!("TEST 1: FAILED:"); + return ExitCode::FAILURE; + } + tracing::info!("\n\nTEST 2: Running successful scan:"); + if !test2::run_scan(&cli, args.openvasd(), args.scan_config()).await { + tracing::info!("TEST 2: FAILED"); + return ExitCode::FAILURE; + } + ExitCode::SUCCESS +} diff --git a/rust/smoketest/src/tests/mod.rs b/rust/smoketest/src/tests/mod.rs new file mode 100644 index 000000000..9b6bd980d --- /dev/null +++ b/rust/smoketest/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod test1; +pub mod test2; diff --git a/rust/smoketest/src/tests/mods.rs b/rust/smoketest/src/tests/mods.rs new file mode 100644 index 000000000..e69de29bb diff --git a/rust/smoketest/src/tests/test1.rs b/rust/smoketest/src/tests/test1.rs new file mode 100644 index 000000000..5f98fcf6c --- /dev/null +++ b/rust/smoketest/src/tests/test1.rs @@ -0,0 +1,18 @@ +/// Check the server sending the HEAD request +pub async fn check_server(cli: &reqwest::Client, server: &String) -> bool { + match cli.head(server).send().await { + Ok(res) => { + if res.status().is_success() { + tracing::info!("\tChecking openvasd server OK"); + true + } else { + tracing::info!("\tChecking openvasd server FAILED"); + false + } + } + Err(e) => { + tracing::info!("\tChecking openvasd server FAILED\n {}", e); + false + } + } +} diff --git a/rust/smoketest/src/tests/test2.rs b/rust/smoketest/src/tests/test2.rs new file mode 100644 index 000000000..df5b5055d --- /dev/null +++ b/rust/smoketest/src/tests/test2.rs @@ -0,0 +1,46 @@ +use models::Phase; +use smoketest::*; + +/// Run a successful scan. Get results and delete the scan +pub async fn run_scan(cli: &reqwest::Client, server: &String, scan_config: &String) -> bool { + if let Some(id) = create_scan(cli, server, scan_config).await { + if !scan_action(cli, server, &id, "start".to_string()).await { + return false; + } + std::thread::sleep(std::time::Duration::from_secs(1)); + let mut counter = 0; + loop { + match scan_status(cli, server, &id).await { + Some(Phase::Succeeded) => { + tracing::info!("\tRun scan succeeded OK"); + + if let Some(results) = scan_results(cli, server, &id).await { + if results.is_empty() { + tracing::info!("\tScan results FAILED"); + } else { + tracing::info!("\tScan results {} OK", results.len()); + } + } else { + tracing::info!("\tScan results FAILED"); + } + + delete_scan(cli, server, &id).await; + return true; + } + None => { + tracing::info!("\tRun scan succeeded FAILED"); + return false; + } + _ => { + std::thread::sleep(std::time::Duration::from_secs(10)); + counter += 1; + if counter >= 360 { + tracing::info!("\tRun scan timeout FAILED"); + return false; + } + } + } + } + } + false +}