diff --git a/modules/ingestor/src/graph/sbom/clearly_defined.rs b/modules/ingestor/src/graph/sbom/clearly_defined.rs index 6864c5f79..452924edc 100644 --- a/modules/ingestor/src/graph/sbom/clearly_defined.rs +++ b/modules/ingestor/src/graph/sbom/clearly_defined.rs @@ -1,10 +1,15 @@ use crate::graph::purl::creator::PurlCreator; use crate::graph::sbom::{LicenseCreator, LicenseInfo, SbomContext, SbomInformation}; -use sea_orm::ConnectionTrait; +use sea_orm::{ConnectionTrait, EntityTrait, Set}; +use sea_query::OnConflict; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use tracing::instrument; use trustify_common::purl::Purl; +use trustify_entity::sbom_package_license; +use uuid::Uuid; + +const CLEARLY_DEFINED_CURATION: &str = "ClearlyDefinedCuration"; impl SbomContext { #[instrument(skip(db, curation), err)] @@ -12,24 +17,24 @@ impl SbomContext { &self, curation: Curation, db: &C, + sbom_id: Uuid, ) -> Result<(), anyhow::Error> { let mut purls = PurlCreator::new(); let mut licenses = LicenseCreator::new(); - // TODO: Since the node id cannot be obtained here, it’s not possible to replace purl_license_assertion with sbom_package_license. - // let mut assertions = Vec::new(); + let mut sbom_package_license_list = Vec::new(); for (purl, license) in curation.iter() { let license_info = LicenseInfo { license: license.clone(), }; - // assertions.push(purl_license_assertion::ActiveModel { - // id: Default::default(), - // license_id: Set(license_info.uuid()), - // versioned_purl_id: Set(purl.version_uuid()), - // sbom_id: Set(self.sbom.sbom_id), - // }); + sbom_package_license_list.push(sbom_package_license::ActiveModel { + sbom_id: Set(self.sbom.sbom_id), + node_id: Set(CLEARLY_DEFINED_CURATION.to_string()), + license_id: Set(license_info.uuid()), + license_type: Set(sbom_package_license::LicenseCategory::Declared), + }); purls.add(purl); licenses.add(&license_info); @@ -37,19 +42,20 @@ impl SbomContext { purls.create(db).await?; licenses.create(db).await?; - // purl_license_assertion::Entity::insert_many(assertions) - // .on_conflict( - // OnConflict::columns([ - // purl_license_assertion::Column::SbomId, - // purl_license_assertion::Column::LicenseId, - // purl_license_assertion::Column::VersionedPurlId, - // ]) - // .do_nothing() - // .to_owned(), - // ) - // .do_nothing() - // .exec(db) - // .await?; + sbom_package_license::Entity::insert_many(sbom_package_license_list) + .on_conflict( + OnConflict::columns([ + sbom_package_license::Column::SbomId, + sbom_package_license::Column::NodeId, + sbom_package_license::Column::LicenseId, + sbom_package_license::Column::LicenseType, + ]) + .do_nothing() + .to_owned(), + ) + .do_nothing() + .exec(db) + .await?; Ok(()) } diff --git a/modules/ingestor/src/service/sbom/clearly_defined.rs b/modules/ingestor/src/service/sbom/clearly_defined.rs index 1e66083cc..32ac05b3d 100644 --- a/modules/ingestor/src/service/sbom/clearly_defined.rs +++ b/modules/ingestor/src/service/sbom/clearly_defined.rs @@ -99,11 +99,19 @@ mod test { use crate::graph::Graph; use crate::service::{Cache, Error, Format, IngestorService}; use anyhow::anyhow; + use sea_orm::{EntityTrait, FromQueryResult, QuerySelect, RelationTrait}; + use sea_query::JoinType; use test_context::test_context; use test_log::test; use trustify_common::purl::Purl; - use trustify_test_context::TrustifyContext; - use trustify_test_context::document_bytes; + use trustify_entity::{license, sbom_package_license}; + use trustify_test_context::{TrustifyContext, document_bytes}; + + #[derive(Debug, FromQueryResult)] + struct PackageLicenseInfo { + pub node_id: String, + pub license_expression: String, + } fn coordinates_to_purl(coords: &str) -> Result { let parts = coords.split('/').collect::>(); @@ -179,6 +187,25 @@ mod test { .await .expect("must ingest"); + let result: Vec = sbom_package_license::Entity::find() + .join( + JoinType::Join, + sbom_package_license::Relation::License.def(), + ) + .select_only() + .column_as(sbom_package_license::Column::NodeId, "node_id") + .column_as(license::Column::Text, "license_expression") + .into_model::() + .all(&ctx.db) + .await?; + + assert_eq!(1, result.len()); + assert_eq!("OTHER", result[0].license_expression); + assert_eq!( + "nuget/nuget/-/microsoft.aspnet.mvc/4.0.40804", + result[0].node_id + ); + Ok(()) } } diff --git a/modules/ingestor/src/service/sbom/clearly_defined_curation.rs b/modules/ingestor/src/service/sbom/clearly_defined_curation.rs index 271f1eef1..8630900b5 100644 --- a/modules/ingestor/src/service/sbom/clearly_defined_curation.rs +++ b/modules/ingestor/src/service/sbom/clearly_defined_curation.rs @@ -26,20 +26,15 @@ impl<'g> ClearlyDefinedCurationLoader<'g> { ) -> Result { let tx = self.graph.db.begin().await?; + let document_id = curation.document_id().clone(); let sbom = match self .graph - .ingest_sbom( - labels, - digests, - Some(curation.document_id()), - &curation, - &tx, - ) + .ingest_sbom(labels, digests, Some(document_id.clone()), &curation, &tx) .await? { Outcome::Existed(sbom) => sbom, Outcome::Added(sbom) => { - sbom.ingest_clearly_defined_curation(curation, &tx) + sbom.ingest_clearly_defined_curation(curation, &tx, sbom.sbom.sbom_id) .await .map_err(Error::Generic)?; @@ -61,10 +56,17 @@ impl<'g> ClearlyDefinedCurationLoader<'g> { mod test { use crate::graph::Graph; use crate::service::{Cache, Format, IngestorService}; + use sea_orm::{EntityTrait, FromQueryResult, QuerySelect, RelationTrait}; + use sea_query::JoinType; use test_context::test_context; use test_log::test; - use trustify_test_context::TrustifyContext; - use trustify_test_context::document_bytes; + use trustify_entity::{license, sbom_package_license}; + use trustify_test_context::{TrustifyContext, document_bytes}; + #[derive(Debug, FromQueryResult)] + struct PackageLicenseInfo { + pub node_id: String, + pub license_expression: String, + } #[test_context(TrustifyContext)] #[test(tokio::test)] @@ -85,6 +87,22 @@ mod test { .await .expect("must ingest"); + let result: Vec = sbom_package_license::Entity::find() + .join( + JoinType::Join, + sbom_package_license::Relation::License.def(), + ) + .select_only() + .column_as(sbom_package_license::Column::NodeId, "node_id") + .column_as(license::Column::Text, "license_expression") + .into_model::() + .all(&ctx.db) + .await?; + + assert_eq!(1, result.len()); + assert_eq!("Apache-2.0 OR MIT", result[0].license_expression); + assert_eq!("ClearlyDefinedCuration", result[0].node_id); + Ok(()) } }