diff --git a/Cargo.lock b/Cargo.lock index 0cf8e029..6b7c54a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8568,6 +8568,7 @@ dependencies = [ "osv", "packageurl", "regex", + "roxmltree", "sea-orm", "sea-query", "semver", diff --git a/modules/fundamental/Cargo.toml b/modules/fundamental/Cargo.toml index d88cebb6..79b5bfb1 100644 --- a/modules/fundamental/Cargo.toml +++ b/modules/fundamental/Cargo.toml @@ -53,6 +53,7 @@ log = { workspace = true } osv = { workspace = true } packageurl = { workspace = true } regex = { workspace = true } +roxmltree = { workspace = true } semver = { workspace = true } serde_json = { workspace = true } serde_yml = { workspace = true } diff --git a/modules/fundamental/tests/fundamental.rs b/modules/fundamental/tests/fundamental.rs index 4dba2d4c..4f61d09b 100644 --- a/modules/fundamental/tests/fundamental.rs +++ b/modules/fundamental/tests/fundamental.rs @@ -1,2 +1,3 @@ mod advisory; mod sbom; +mod weakness; diff --git a/modules/fundamental/tests/weakness/mod.rs b/modules/fundamental/tests/weakness/mod.rs new file mode 100644 index 00000000..1119e6ec --- /dev/null +++ b/modules/fundamental/tests/weakness/mod.rs @@ -0,0 +1,99 @@ +#![allow(clippy::expect_used)] + +use roxmltree::Document; +use std::io::Read; +use test_context::test_context; +use test_log::test; +use trustify_common::{hashing::HashingRead, model::Paginated}; +use trustify_entity::labels::Labels; +use trustify_module_fundamental::weakness::service::WeaknessService; +use trustify_module_ingestor::{graph::Graph, service::weakness::CweCatalogLoader}; +use trustify_test_context::{document_read, TrustifyContext}; +use zip::ZipArchive; + +#[test_context(TrustifyContext)] +#[test(tokio::test)] +async fn simple(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { + const TOTAL_ITEMS_FOUND: u64 = 964; + + let graph = Graph::new(ctx.db.clone()); + let loader = CweCatalogLoader::new(&graph); + let service = WeaknessService::new(ctx.db.clone()); + + // extract document from zip file + + let zip = document_read("cwec_latest.xml.zip").await?; + + let mut archive = ZipArchive::new(zip)?; + + let entry = archive.by_index(0)?; + + let mut hashing = HashingRead::new(entry); + let mut xml = String::new(); + hashing.read_to_string(&mut xml)?; + let digests = hashing.finish()?; + + // load + + let doc = Document::parse(&xml)?; + loader.load(Labels::default(), &doc, &digests).await?; + + // fetch data + + let all = service + .list_weaknesses( + Default::default(), + Paginated { + offset: 0, + limit: 10, + }, + ) + .await?; + + assert_eq!(TOTAL_ITEMS_FOUND, all.total); + + let w = service + .get_weakness("CWE-1004") + .await? + .expect("must be found"); + + assert_eq!(w.head.description.as_deref(), Some("The product uses a cookie to store sensitive information, but the cookie is not marked with the HttpOnly flag.")); + + // now update (poor man's XML update) + + let xml = xml.replace("The product uses a cookie to store sensitive information, but the cookie is not marked with the HttpOnly flag.", "Foo Bar Update"); + + // load again + + let doc = Document::parse(&xml)?; + loader.load(Labels::default(), &doc, &digests).await?; + + // fetch data again + + let all = service + .list_weaknesses( + Default::default(), + Paginated { + offset: 0, + limit: 10, + }, + ) + .await?; + + // must be the same number of items + + assert_eq!(964, all.total); + + let w = service + .get_weakness("CWE-1004") + .await? + .expect("must be found"); + + // but a different description + + assert_eq!(w.head.description.as_deref(), Some("Foo Bar Update")); + + // done + + Ok(()) +}