From 26220ca2c0164e465d9e47c5e6315b8d90ce1561 Mon Sep 17 00:00:00 2001 From: JimFuller-RedHat Date: Wed, 26 Nov 2025 12:59:26 +0100 Subject: [PATCH] latest endpoints: investigations. --- entity/src/sbom_package.rs | 7 ++ .../src/endpoints/tests/latest_filters.rs | 96 ++++++++++++++++++- modules/analysis/src/service/load.rs | 2 +- 3 files changed, 103 insertions(+), 2 deletions(-) diff --git a/entity/src/sbom_package.rs b/entity/src/sbom_package.rs index 879ed6f7f..1c82947a3 100644 --- a/entity/src/sbom_package.rs +++ b/entity/src/sbom_package.rs @@ -34,6 +34,13 @@ pub enum Relation { )] Cpe, + #[sea_orm( + belongs_to = "super::sbom_package_cpe_ref::Entity", + from = "(Column::SbomId)", + to = "(super::sbom_package_cpe_ref::Column::SbomId)" + )] + CpeSbomId, + #[sea_orm( belongs_to = "super::sbom_package_license::Entity", from = "(Column::SbomId, Column::NodeId)", diff --git a/modules/analysis/src/endpoints/tests/latest_filters.rs b/modules/analysis/src/endpoints/tests/latest_filters.rs index 8c155fb97..afec842ca 100644 --- a/modules/analysis/src/endpoints/tests/latest_filters.rs +++ b/modules/analysis/src/endpoints/tests/latest_filters.rs @@ -1,7 +1,7 @@ use super::req::*; use crate::test::caller; use rstest::*; -use serde_json::json; +use serde_json::{Value, json}; use test_context::test_context; use trustify_test_context::{TrustifyContext, subset::ContainsSubset}; @@ -470,3 +470,97 @@ async fn test_tc2578( Ok(()) } + +#[test_context(TrustifyContext)] +#[test_log::test(actix_web::test)] +async fn tc_3170_3a(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { + let app = caller(ctx).await?; + + ctx.ingest_documents([ + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-product.json", + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-image-index.json", + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-amd64.json", + ]) + .await?; + + let req = Req { + what: What::Q("purl~pkg:oci/quay-builder-qemu-rhcos-rhel8"), + ancestors: Some(10), + ..Default::default() + }; + + // request latest + let latest_response = app + .req(Req { + latest: true, + ..req + }) + .await?; + log::info!("{:?}", latest_response); + + assert_eq!(latest_response["total"], 8); + + Ok(()) +} +#[test_context(TrustifyContext)] +#[test_log::test(actix_web::test)] +async fn tc_3170_3b(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { + let app = caller(ctx).await?; + + ctx.ingest_documents([ + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-product.json", + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-image-index.json", + "cyclonedx/rh/latest_filters/container/quay_builder_qemu_rhcos_rhel8_2025-02-24/quay-builder-qemu-rhcos-rhel-8-amd64.json", + ]) + .await?; + + let req = Req { + what: What::Q("purl~pkg:oci/quay-builder-qemu-rhcos-rhel8"), + ancestors: Some(10), + ..Default::default() + }; + + // request latest + let mut latest_response = app + .req(Req { + latest: true, + ..req + }) + .await?; + + sort(&mut latest_response["items"]); + + // request all + let mut response = app + .req(Req { + latest: false, + ..req + }) + .await?; + + sort(&mut response["items"]); + + // must yield the same result + + assert_eq!(response, latest_response); + + Ok(()) +} + +/// sort all entries by node_id. This includes recursive sorting of ancestors/descendants. +fn sort(json: &mut Value) { + let Value::Array(items) = json else { + return; + }; + + // sort list + + items.sort_unstable_by(|a, b| a["node_id"].as_str().cmp(&b["node_id"].as_str())); + + // now sort child entries + + for item in items { + sort(&mut item["ancestors"]); + sort(&mut item["descendants"]); + } +} diff --git a/modules/analysis/src/service/load.rs b/modules/analysis/src/service/load.rs index a8c098d0f..9362f05c3 100644 --- a/modules/analysis/src/service/load.rs +++ b/modules/analysis/src/service/load.rs @@ -409,7 +409,7 @@ impl InnerService { .column(cpe::Column::Id) .column_as(Expr::cust(rank_sql), "rank") // Use the selected SQL string .join(JoinType::LeftJoin, sbom_package_relation.def()) - .join(JoinType::LeftJoin, sbom_package::Relation::Cpe.def()) + .join(JoinType::LeftJoin, sbom_package::Relation::CpeSbomId.def()) .join( JoinType::LeftJoin, sbom_package_cpe_ref::Relation::Cpe.def(),