diff --git a/.clippy.toml b/.clippy.toml index 0358cdb50..7547bef08 100644 --- a/.clippy.toml +++ b/.clippy.toml @@ -1,2 +1,3 @@ allow-unwrap-in-tests = true allow-expect-in-tests = true +absolute-paths-max-segments = 3 diff --git a/CONVENTIONS.md b/CONVENTIONS.md index 9730150b4..0856b6a7e 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -36,6 +36,44 @@ use sea_orm::{ConnectionTrait, TransactionTrait}; This is a manual convention — `rustfmt`'s `imports_granularity = "Crate"` option is not available on the stable channel. Reviewers should flag un-nested imports during code review. +### Import Style — Absolute Paths + +Fully-qualified paths with 4+ segments are enforced by the `clippy::absolute_paths` lint +(configured in `.clippy.toml` with `absolute-paths-max-segments = 3`). Paths exceeding the +threshold must be replaced with `use` imports: + +```rust +// Good — imported +use crate::graph::db_context::parse_status; +parse_status(value)?; + +// Lint error — 4+ segment absolute path +crate::graph::db_context::parse_status(value)?; +``` + +3-segment paths (e.g. `std::fmt::Result`, `entity::advisory_vulnerability::Model`) are not +flagged by the lint and are acceptable. + +### Import Style — Qualified Names for Common Types + +Common or ambiguous names should stay qualified with a 2-segment path, even when there is +no conflict in the current file. This keeps the code self-documenting and avoids confusion +when reviewing: + +```rust +// Good — qualified with module prefix +let model: advisory_vulnerability::Model = ...; +let result: std::fmt::Result = ...; +let value = serde_json::from_value(...); + +// Avoid — bare name is ambiguous across modules +let model: Model = ...; +``` + +Names that benefit from qualification include `Model`, `Entity`, `Column`, `ActiveModel`, +`Relation`, `from_value`, `info`, and similar names that appear in many modules. This is a +reviewer convention, not lint-enforced. + ## Naming Conventions - Structs: PascalCase (`SbomService`, `AdvisoryService`, `SbomSummary`) diff --git a/common/auth/src/authenticator/user.rs b/common/auth/src/authenticator/user.rs index e2b0a3b4e..c47422099 100644 --- a/common/auth/src/authenticator/user.rs +++ b/common/auth/src/authenticator/user.rs @@ -1,6 +1,6 @@ //! Structures to work with users and identities. -use crate::authenticator::error::AuthorizationError; +use crate::authenticator::error::{AuthenticationError, AuthorizationError}; /// Details of an authenticated user. /// @@ -101,9 +101,7 @@ impl actix_web::FromRequest for UserDetails { log::debug!("Anonymous user, returning failure"); core::future::ready(Err(AuthorizationError::Failed.into())) } - None => core::future::ready(Err( - crate::authenticator::error::AuthenticationError::Failed.into(), - )), + None => core::future::ready(Err(AuthenticationError::Failed.into())), } } } diff --git a/common/auth/src/client/provider/mod.rs b/common/auth/src/client/provider/mod.rs index abe8dfd27..e5ab11955 100644 --- a/common/auth/src/client/provider/mod.rs +++ b/common/auth/src/client/provider/mod.rs @@ -105,9 +105,12 @@ impl TokenProvider for String { } } +#[cfg(feature = "actix")] +use actix_web_httpauth::extractors::bearer::BearerAuth; + #[cfg(feature = "actix")] #[async_trait] -impl TokenProvider for actix_web_httpauth::extractors::bearer::BearerAuth { +impl TokenProvider for BearerAuth { async fn provide_access_token(&self) -> Result, Error> { Ok(Some(Credentials::Bearer(self.token().to_string()))) } diff --git a/common/infrastructure/src/app/mod.rs b/common/infrastructure/src/app/mod.rs index dfaca238a..61fa4cb85 100644 --- a/common/infrastructure/src/app/mod.rs +++ b/common/infrastructure/src/app/mod.rs @@ -13,7 +13,10 @@ use actix_web_httpauth::{extractors::bearer::BearerAuth, middleware::HttpAuthent use futures::{FutureExt, future::LocalBoxFuture}; use opentelemetry_instrumentation_actix_web::{RequestMetrics, RequestTracing}; use std::sync::Arc; -use trustify_auth::{authenticator::Authenticator, authorizer::Authorizer}; +use trustify_auth::{ + authenticator::{Authenticator, actix::openid_validator}, + authorizer::Authorizer, +}; use trustify_common::middleware::StdMiddleware; #[derive(Default)] @@ -42,11 +45,7 @@ pub fn new_auth( Condition::from_option(auth.map(move |authenticator| { HttpAuthentication::bearer(move |req, auth| { let authenticator = authenticator.clone(); - Box::pin(async move { - trustify_auth::authenticator::actix::openid_validator(req, auth, authenticator) - .await - }) - .boxed_local() + Box::pin(async move { openid_validator(req, auth, authenticator).await }).boxed_local() }) })) } diff --git a/common/src/decompress.rs b/common/src/decompress.rs index 194d2dd56..15d526626 100644 --- a/common/src/decompress.rs +++ b/common/src/decompress.rs @@ -1,5 +1,6 @@ use actix_web::http::header; use anyhow::anyhow; +use async_compression::tokio::bufread::{GzipDecoder, LzmaDecoder}; use bytes::Bytes; use std::{io::Read, path::Path, pin::Pin}; use tokio::{ @@ -109,8 +110,8 @@ pub async fn decompress_async_read( let source = BufReader::new(source); Ok(match path.extension().and_then(|ext| ext.to_str()) { - Some("xz") => Box::pin(async_compression::tokio::bufread::LzmaDecoder::new(source)), - Some("gz") => Box::pin(async_compression::tokio::bufread::GzipDecoder::new(source)), + Some("xz") => Box::pin(LzmaDecoder::new(source)), + Some("gz") => Box::pin(GzipDecoder::new(source)), // Anything else could be .sql, .tar, or an unsupported compression format. // In that case, the following code would fail to understand the compressed content. None | Some(_) => Box::pin(source), diff --git a/common/src/uuid.rs b/common/src/uuid.rs index d0ecc6be8..e60489899 100644 --- a/common/src/uuid.rs +++ b/common/src/uuid.rs @@ -4,13 +4,14 @@ pub mod serde { use serde::{Deserialize, Deserializer, Serializer, de::Error}; use uuid::Uuid; + use uuid::serde::urn::serialize as uuid_urn_serialize; pub fn serialize(value: &Option, serializer: S) -> Result where S: Serializer, { match value { - Some(uuid) => uuid::serde::urn::serialize(uuid, serializer), + Some(uuid) => uuid_urn_serialize(uuid, serializer), None => serializer.serialize_none(), } } diff --git a/migration/src/data/document/sbom.rs b/migration/src/data/document/sbom.rs index 9bf1d2e90..822e33e26 100644 --- a/migration/src/data/document/sbom.rs +++ b/migration/src/data/document/sbom.rs @@ -5,6 +5,7 @@ use sea_orm::{ prelude::*, sea_query::{Expr, extension::postgres::PgExpr}, }; +use serde_cyclonedx::cyclonedx::v_1_6::CycloneDx; use trustify_entity::{labels::Labels, sbom}; use trustify_module_storage::service::StorageBackend; @@ -16,7 +17,7 @@ pub struct Id { #[allow(clippy::large_enum_variant)] pub enum Sbom { - CycloneDx(serde_cyclonedx::cyclonedx::v_1_6::CycloneDx), + CycloneDx(CycloneDx), Spdx(spdx_rs::models::SPDX), Other(Bytes), } diff --git a/migration/src/m0002000_add_sbom_properties.rs b/migration/src/m0002000_add_sbom_properties.rs index 656577160..6a33b51ca 100644 --- a/migration/src/m0002000_add_sbom_properties.rs +++ b/migration/src/m0002000_add_sbom_properties.rs @@ -1,4 +1,6 @@ -use crate::data::{MigrationTraitWithData, SchemaDataManager, sbom::Sbom as SbomDoc}; +use crate::data::{ + MigrationTraitWithData, SchemaDataManager, sbom::Id as SbomId, sbom::Sbom as SbomDoc, +}; use sea_orm::{ActiveModelBehavior, ActiveModelTrait, DatabaseTransaction, Set}; use sea_orm_migration::prelude::*; use trustify_common::advisory::cyclonedx::extract_properties_json; @@ -68,7 +70,7 @@ impl MigrationTraitWithData for Migration { manager .process( self, - async |sbom: SbomDoc, id: crate::data::sbom::Id, tx: &DatabaseTransaction| { + async |sbom: SbomDoc, id: SbomId, tx: &DatabaseTransaction| { let mut model = legacy::ActiveModel::new(); model.sbom_id = Set(id.sbom); match sbom { diff --git a/modules/analysis/src/error.rs b/modules/analysis/src/error.rs index 8d408aff2..c63e43628 100644 --- a/modules/analysis/src/error.rs +++ b/modules/analysis/src/error.rs @@ -5,6 +5,7 @@ use cpe::uri::OwnedUri; use sea_orm::DbErr; use std::str::FromStr; use trustify_auth::authenticator::error::AuthorizationError; +use trustify_common::db::query::Error as QueryError; use trustify_common::db::{DatabaseErrors, DbError}; use trustify_common::error::ErrorInformation; use trustify_common::id::IdError; @@ -17,7 +18,7 @@ pub enum Error { #[error(transparent)] Database(DbErr), #[error(transparent)] - Query(#[from] trustify_common::db::query::Error), + Query(#[from] QueryError), #[error(transparent)] Purl(#[from] PurlErr), #[error(transparent)] diff --git a/modules/fundamental/src/advisory/endpoints/test.rs b/modules/fundamental/src/advisory/endpoints/test.rs index 9bd083b44..16bdad9b4 100644 --- a/modules/fundamental/src/advisory/endpoints/test.rs +++ b/modules/fundamental/src/advisory/endpoints/test.rs @@ -1,6 +1,9 @@ use crate::{ advisory::model::{AdvisoryDetails, AdvisorySummary}, - test::{caller, caller_with, label::Api}, + test::{ + caller, caller_with, label::Api, label::update_labels as do_update_labels, + label::update_labels_not_found as do_update_labels_not_found, + }, }; use actix_http::StatusCode; use actix_web::{body::MessageBody, test::TestRequest}; @@ -18,7 +21,10 @@ use trustify_common::{ }; use trustify_entity::{advisory_vulnerability_score, labels::Labels}; use trustify_module_ingestor::{ - graph::{advisory::AdvisoryInformation, cvss::ScoreCreator}, + graph::{ + advisory::AdvisoryInformation, + cvss::{ScoreCreator, ScoreInformation}, + }, model::IngestResult, service::Format, }; @@ -56,7 +62,7 @@ async fn all_advisories(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { // Use ScoreCreator to write to advisory_vulnerability_score table let mut score_creator = ScoreCreator::new(advisory.advisory.id); - score_creator.add(trustify_module_ingestor::graph::cvss::ScoreInformation { + score_creator.add(ScoreInformation { vulnerability_id: "CVE-123".to_string(), r#type: advisory_vulnerability_score::ScoreType::V3_0, vector: "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N".to_string(), @@ -180,7 +186,7 @@ async fn one_advisory(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { // Use ScoreCreator to write to advisory_vulnerability_score table let mut score_creator = ScoreCreator::new(advisory2.advisory.id); - score_creator.add(trustify_module_ingestor::graph::cvss::ScoreInformation { + score_creator.add(ScoreInformation { vulnerability_id: "CVE-123".to_string(), r#type: advisory_vulnerability_score::ScoreType::V3_0, vector: "CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N".to_string(), @@ -286,7 +292,7 @@ async fn one_advisory_by_uuid(ctx: &TrustifyContext) -> Result<(), anyhow::Error // Use ScoreCreator to write to advisory_vulnerability_score table let mut score_creator = ScoreCreator::new(advisory.advisory.id); - score_creator.add(trustify_module_ingestor::graph::cvss::ScoreInformation { + score_creator.add(ScoreInformation { vulnerability_id: "CVE-123".to_string(), r#type: advisory_vulnerability_score::ScoreType::V3_0, vector: "CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N".to_string(), @@ -595,14 +601,14 @@ async fn download_advisory_by_id(ctx: &TrustifyContext) -> Result<(), anyhow::Er #[test_context(TrustifyContext)] #[test(actix_web::test)] async fn update_labels(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { - crate::test::label::update_labels(ctx, Api::Advisory, DOC, "csaf").await + do_update_labels(ctx, Api::Advisory, DOC, "csaf").await } /// Test updating labels, for a document that does not exist #[test_context(TrustifyContext)] #[test(actix_web::test)] async fn update_labels_not_found(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { - crate::test::label::update_labels_not_found(ctx, Api::Advisory, DOC).await + do_update_labels_not_found(ctx, Api::Advisory, DOC).await } /// Test deleing an advisory diff --git a/modules/fundamental/src/advisory/service/test.rs b/modules/fundamental/src/advisory/service/test.rs index 2dd159ae4..2e0f4c86b 100644 --- a/modules/fundamental/src/advisory/service/test.rs +++ b/modules/fundamental/src/advisory/service/test.rs @@ -20,9 +20,11 @@ use trustify_module_ingestor::graph::{ Outcome, advisory::{ AdvisoryContext, AdvisoryInformation, + advisory_vulnerability::AdvisoryVulnerabilityContext, version::{VersionInfo, VersionSpec}, }, cvss::{ScoreCreator, ScoreInformation}, + error::Error as GraphError, }; use trustify_test_context::TrustifyContext; @@ -30,7 +32,7 @@ pub async fn ingest_sample_advisory<'a>( ctx: &'a TrustifyContext, id: &'a str, title: &'a str, -) -> Result, trustify_module_ingestor::graph::error::Error> { +) -> Result, GraphError> { ctx.graph .ingest_advisory( title, @@ -101,8 +103,8 @@ async fn single_advisory(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { let advisory = ingest_sample_advisory(ctx, "RHSA-1", "RHSA-1").await?; - let advisory_vuln: trustify_module_ingestor::graph::advisory::advisory_vulnerability::AdvisoryVulnerabilityContext<'_> = advisory - .link_to_vulnerability("CVE-123", None,&ctx.db) + let advisory_vuln: AdvisoryVulnerabilityContext<'_> = advisory + .link_to_vulnerability("CVE-123", None, &ctx.db) .await?; let mut creator = ScoreCreator::new(advisory_vuln.advisory.advisory.id); creator.add(ScoreInformation { diff --git a/modules/fundamental/src/endpoints.rs b/modules/fundamental/src/endpoints.rs index 44a99849a..72028865c 100644 --- a/modules/fundamental/src/endpoints.rs +++ b/modules/fundamental/src/endpoints.rs @@ -1,11 +1,16 @@ use actix_web::web; use trustify_common::db::{self, pagination_cache::PaginationCache}; use trustify_module_analysis::service::AnalysisService; +use trustify_module_ingestor::common; use trustify_module_ingestor::graph::Graph; use trustify_module_ingestor::service::IngestorService; use trustify_module_storage::service::dispatch::DispatchBackend; use utoipa::{IntoParams, ToSchema}; +use crate::{ + advisory, license, organization, product, purl, sbom, sbom_group, vulnerability, weakness, +}; + #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct Config { pub sbom_upload_limit: usize, @@ -27,32 +32,32 @@ pub fn configure( let ingestor_service = IngestorService::new(graph, storage, Some(analysis)); svc.app_data(web::Data::new(ingestor_service.clone())); - crate::advisory::endpoints::configure( + advisory::endpoints::configure( svc, db_rw.clone(), db_ro.clone(), config.advisory_upload_limit, cache.clone(), ); - crate::license::endpoints::configure(svc, db_ro.clone()); - crate::organization::endpoints::configure(svc, db_ro.clone(), cache.clone()); - crate::purl::endpoints::configure(svc, db_ro.clone(), cache.clone()); - crate::product::endpoints::configure(svc, db_rw.clone(), db_ro.clone(), cache.clone()); - crate::sbom::endpoints::configure( + license::endpoints::configure(svc, db_ro.clone()); + organization::endpoints::configure(svc, db_ro.clone(), cache.clone()); + purl::endpoints::configure(svc, db_ro.clone(), cache.clone()); + product::endpoints::configure(svc, db_rw.clone(), db_ro.clone(), cache.clone()); + sbom::endpoints::configure( svc, db_rw.clone(), db_ro.clone(), config.sbom_upload_limit, cache.clone(), ); - crate::vulnerability::endpoints::configure(svc, db_ro.clone(), cache.clone()); - crate::weakness::endpoints::configure(svc, db_ro.clone(), cache.clone()); - crate::sbom_group::endpoints::configure(svc, db_rw, db_ro, config.max_group_name_length, cache); + vulnerability::endpoints::configure(svc, db_ro.clone(), cache.clone()); + weakness::endpoints::configure(svc, db_ro.clone(), cache.clone()); + sbom_group::endpoints::configure(svc, db_rw, db_ro, config.max_group_name_length, cache); } #[derive(Clone, Debug, PartialEq, Eq, Default, ToSchema, serde::Deserialize, IntoParams)] pub struct Deprecation { #[serde(default)] #[param(inline)] - pub deprecated: trustify_module_ingestor::common::Deprecation, + pub deprecated: common::Deprecation, } diff --git a/modules/fundamental/src/error.rs b/modules/fundamental/src/error.rs index 0d1d3ab84..2a9fe92e8 100644 --- a/modules/fundamental/src/error.rs +++ b/modules/fundamental/src/error.rs @@ -4,7 +4,7 @@ use sea_orm::DbErr; use std::borrow::Cow; use trustify_auth::authenticator::error::AuthorizationError; use trustify_common::{ - db::{DatabaseErrors, DbError, limiter::LimiterError, pagination_cache::LimitError}, + db::{DatabaseErrors, DbError, limiter::LimiterError, pagination_cache::LimitError, query}, decompress, error::ErrorInformation, id::IdError, @@ -22,7 +22,7 @@ pub enum Error { #[error(transparent)] Database(DbErr), #[error(transparent)] - Query(#[from] trustify_common::db::query::Error), + Query(#[from] query::Error), #[error(transparent)] Ingestor(#[from] trustify_module_ingestor::service::Error), #[error(transparent)] diff --git a/modules/fundamental/src/organization/endpoints/test.rs b/modules/fundamental/src/organization/endpoints/test.rs index 8e571b214..b549aa3aa 100644 --- a/modules/fundamental/src/organization/endpoints/test.rs +++ b/modules/fundamental/src/organization/endpoints/test.rs @@ -1,3 +1,4 @@ +use crate::organization::service::OrganizationService; use crate::test::caller; use actix_web::{cookie::time::OffsetDateTime, test::TestRequest}; use jsonpath_rust::JsonPath; @@ -98,8 +99,7 @@ async fn one_organization(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { .link_to_vulnerability("CVE-123", None, &ctx.db) .await?; - let service = - crate::organization::service::OrganizationService::new(PaginationCache::for_test()); + let service = OrganizationService::new(PaginationCache::for_test()); let orgs = service .fetch_organizations( diff --git a/modules/fundamental/src/organization/service/test.rs b/modules/fundamental/src/organization/service/test.rs index 52da8c9bc..444dd3d00 100644 --- a/modules/fundamental/src/organization/service/test.rs +++ b/modules/fundamental/src/organization/service/test.rs @@ -1,3 +1,4 @@ +use crate::organization::service::OrganizationService; use actix_web::cookie::time::OffsetDateTime; use test_context::test_context; use test_log::test; @@ -29,8 +30,7 @@ async fn all_organizations(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { ) .await?; - let service = - crate::organization::service::OrganizationService::new(PaginationCache::for_test()); + let service = OrganizationService::new(PaginationCache::for_test()); let orgs = service .fetch_organizations( diff --git a/modules/fundamental/src/product/endpoints/test.rs b/modules/fundamental/src/product/endpoints/test.rs index b4cb9e7a1..0643cc8da 100644 --- a/modules/fundamental/src/product/endpoints/test.rs +++ b/modules/fundamental/src/product/endpoints/test.rs @@ -1,3 +1,4 @@ +use crate::product::service::ProductService; use crate::test::caller; use actix_http::StatusCode; use actix_web::{body::MessageBody, test::TestRequest}; @@ -70,7 +71,7 @@ async fn one_product(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { ) .await?; - let service = crate::product::service::ProductService::new(PaginationCache::for_test()); + let service = ProductService::new(PaginationCache::for_test()); let products = service .fetch_products( @@ -117,7 +118,7 @@ async fn delete_product(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { ) .await?; - let service = crate::product::service::ProductService::new(PaginationCache::for_test()); + let service = ProductService::new(PaginationCache::for_test()); let products = service .fetch_products( diff --git a/modules/fundamental/src/product/service/test.rs b/modules/fundamental/src/product/service/test.rs index 723cc6f8a..9a76943bc 100644 --- a/modules/fundamental/src/product/service/test.rs +++ b/modules/fundamental/src/product/service/test.rs @@ -1,3 +1,4 @@ +use crate::product::service::ProductService; use std::str::FromStr; use test_context::test_context; use test_log::test; @@ -39,7 +40,7 @@ async fn all_products(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { .ingest_product_version("1.0.0".to_string(), Some(sbom.sbom.sbom_id), &ctx.db) .await?; - let service = crate::product::service::ProductService::new(PaginationCache::for_test()); + let service = ProductService::new(PaginationCache::for_test()); let prods = service .fetch_products( @@ -137,7 +138,7 @@ async fn delete_product(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { ) .await?; - let service = crate::product::service::ProductService::new(PaginationCache::for_test()); + let service = ProductService::new(PaginationCache::for_test()); let prods = service .fetch_products( diff --git a/modules/fundamental/src/sbom/endpoints/test.rs b/modules/fundamental/src/sbom/endpoints/test.rs index 6422643bf..d6d86011f 100644 --- a/modules/fundamental/src/sbom/endpoints/test.rs +++ b/modules/fundamental/src/sbom/endpoints/test.rs @@ -5,7 +5,10 @@ use crate::{ }, purl::model::summary::purl::PurlSummary, sbom::model::{SbomPackage, SbomSummary}, - test::{caller, label::Api}, + test::{ + caller, label::Api, label::update_labels as do_update_labels, + label::update_labels_not_found as do_update_labels_not_found, + }, }; use actix_http::StatusCode; use actix_web::{ @@ -1214,7 +1217,7 @@ async fn filter_packages(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { #[test_context(TrustifyContext)] #[test(actix_web::test)] async fn update_labels(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { - crate::test::label::update_labels( + do_update_labels( ctx, Api::Sbom, "quarkus-bom-2.13.8.Final-redhat-00004.json", @@ -1227,12 +1230,7 @@ async fn update_labels(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { #[test_context(TrustifyContext)] #[test(actix_web::test)] async fn update_labels_not_found(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { - crate::test::label::update_labels_not_found( - ctx, - Api::Sbom, - "quarkus-bom-2.13.8.Final-redhat-00004.json", - ) - .await + do_update_labels_not_found(ctx, Api::Sbom, "quarkus-bom-2.13.8.Final-redhat-00004.json").await } /// Test deleting an sbom diff --git a/modules/fundamental/src/sbom_group/endpoints/test/list.rs b/modules/fundamental/src/sbom_group/endpoints/test/list.rs index de2d62d47..e0c67835b 100644 --- a/modules/fundamental/src/sbom_group/endpoints/test/list.rs +++ b/modules/fundamental/src/sbom_group/endpoints/test/list.rs @@ -1,6 +1,6 @@ use crate::{ common::test::{Group, UpdateAssignments, create_groups, locate_id, read_assignments}, - sbom_group::model::{GroupDetails, GroupListResult}, + sbom_group::model::{Group as SbomGroupModel, GroupDetails, GroupListResult}, test::caller, }; use actix_http::body::to_bytes; @@ -365,7 +365,7 @@ fn into_actual( }); GroupDetails { - group: crate::sbom_group::model::Group { + group: SbomGroupModel { id, parent, name: item.name.to_string(), diff --git a/modules/fundamental/src/vulnerability/endpoints/test.rs b/modules/fundamental/src/vulnerability/endpoints/test.rs index 68a516844..e3bf4baa2 100644 --- a/modules/fundamental/src/vulnerability/endpoints/test.rs +++ b/modules/fundamental/src/vulnerability/endpoints/test.rs @@ -4,6 +4,7 @@ use rstest::rstest; use serde_json::{Value, json}; use test_context::test_context; use time::{OffsetDateTime, macros::datetime}; +use trustify_common::db::pagination_cache::PaginationCache; use trustify_common::hashing::Digests; use trustify_entity::advisory_vulnerability_score::{ScoreType, Severity}; use trustify_module_ingestor::graph::{ @@ -565,7 +566,7 @@ async fn cvss_v4_score_after_migration( db_ro.clone(), storage, analysis.clone(), - trustify_common::db::pagination_cache::PaginationCache::for_test(), + PaginationCache::for_test(), trustify_module_ingestor::graph::Graph::new(), ); trustify_module_analysis::endpoints::configure(svc, db_ro, analysis); diff --git a/modules/fundamental/src/vulnerability/service/test.rs b/modules/fundamental/src/vulnerability/service/test.rs index 21957ee83..fe5219428 100644 --- a/modules/fundamental/src/vulnerability/service/test.rs +++ b/modules/fundamental/src/vulnerability/service/test.rs @@ -1,5 +1,8 @@ use crate::{ - purl::{model::summary::remediation::RemediationSummary, service::PurlService}, + purl::{ + model::{details::purl::StatusContext, summary::remediation::RemediationSummary}, + service::PurlService, + }, sbom::service::SbomService, vulnerability::{model::BaseScore, service::VulnerabilityService}, }; @@ -1004,8 +1007,8 @@ async fn analyze_purls_product_status(ctx: &TrustifyContext) -> Result<(), anyho .context .clone() .map(|context| match context { - crate::purl::model::details::purl::StatusContext::Purl(_) => false, - crate::purl::model::details::purl::StatusContext::Cpe(cpe) => { + StatusContext::Purl(_) => false, + StatusContext::Cpe(cpe) => { cpe == "cpe:/a:redhat:jboss_fuse_service_works:6:*:*:*" } }) @@ -1070,10 +1073,8 @@ async fn analyze_purls_product_status_0044(ctx: &TrustifyContext) -> Result<(), .context .clone() .map(|context| match context { - crate::purl::model::details::purl::StatusContext::Purl(_) => false, - crate::purl::model::details::purl::StatusContext::Cpe(cpe) => { - cpe == "cpe:/a:redhat:quarkus:2:*:*:*" - } + StatusContext::Purl(_) => false, + StatusContext::Cpe(cpe) => cpe == "cpe:/a:redhat:quarkus:2:*:*:*", }) .unwrap_or(false) }) diff --git a/modules/fundamental/tests/advisory/csaf/reingest.rs b/modules/fundamental/tests/advisory/csaf/reingest.rs index 19034e7b9..a71b8e63e 100644 --- a/modules/fundamental/tests/advisory/csaf/reingest.rs +++ b/modules/fundamental/tests/advisory/csaf/reingest.rs @@ -12,6 +12,7 @@ use trustify_module_fundamental::advisory::model::AdvisoryHead; use trustify_module_fundamental::common::model::ScoreType; use trustify_module_fundamental::common::model::Severity; use trustify_module_fundamental::common::model::{Score, ScoredVector}; +use trustify_module_fundamental::organization::model::{OrganizationHead, OrganizationSummary}; use trustify_module_fundamental::purl::model::details::version_range::VersionRange; use trustify_module_fundamental::{ purl::{ @@ -209,16 +210,14 @@ async fn change_ps_list_vulns(ctx: &TrustifyContext) -> anyhow::Result<()> { uuid: blank_uuid, identifier: "https://www.redhat.com/#CVE-2023-33201".into(), document_id: "CVE-2023-33201".into(), - issuer: Some( - trustify_module_fundamental::organization::model::OrganizationSummary { - head: trustify_module_fundamental::organization::model::OrganizationHead { - id: blank_uuid, - name: "Red Hat Product Security".into(), - cpe_key: None, - website: None - } + issuer: Some(OrganizationSummary { + head: OrganizationHead { + id: blank_uuid, + name: "Red Hat Product Security".into(), + cpe_key: None, + website: None } - ), + }), published: Some(OffsetDateTime::from_unix_timestamp(1686873600)?), modified: Some(OffsetDateTime::from_unix_timestamp(1696623810)?), withdrawn: None, @@ -369,16 +368,14 @@ async fn change_ps_list_vulns_all(ctx: &TrustifyContext) -> anyhow::Result<()> { uuid: blank_uuid, identifier: "https://www.redhat.com/#CVE-2023-33201".into(), document_id: "CVE-2023-33201".into(), - issuer: Some( - trustify_module_fundamental::organization::model::OrganizationSummary { - head: trustify_module_fundamental::organization::model::OrganizationHead { - id: blank_uuid, - name: "Red Hat Product Security".into(), - cpe_key: None, - website: None - } + issuer: Some(OrganizationSummary { + head: OrganizationHead { + id: blank_uuid, + name: "Red Hat Product Security".into(), + cpe_key: None, + website: None } - ), + }), published: Some(OffsetDateTime::from_unix_timestamp(1686873600)?), modified: Some(OffsetDateTime::from_unix_timestamp(1696537410)?), withdrawn: None, @@ -436,16 +433,14 @@ async fn change_ps_list_vulns_all(ctx: &TrustifyContext) -> anyhow::Result<()> { uuid: blank_uuid, identifier: "https://www.redhat.com/#CVE-2023-33201".into(), document_id: "CVE-2023-33201".into(), - issuer: Some( - trustify_module_fundamental::organization::model::OrganizationSummary { - head: trustify_module_fundamental::organization::model::OrganizationHead { - id: blank_uuid, - name: "Red Hat Product Security".into(), - cpe_key: None, - website: None - } + issuer: Some(OrganizationSummary { + head: OrganizationHead { + id: blank_uuid, + name: "Red Hat Product Security".into(), + cpe_key: None, + website: None } - ), + }), published: Some(OffsetDateTime::from_unix_timestamp(1686873600)?), modified: Some(OffsetDateTime::from_unix_timestamp(1696623810)?), withdrawn: None, diff --git a/modules/fundamental/tests/sbom/cyclonedx/mod.rs b/modules/fundamental/tests/sbom/cyclonedx/mod.rs index 980de63d6..831aebce4 100644 --- a/modules/fundamental/tests/sbom/cyclonedx/mod.rs +++ b/modules/fundamental/tests/sbom/cyclonedx/mod.rs @@ -6,6 +6,7 @@ mod purl; mod reingest; use super::*; +use serde_cyclonedx::cyclonedx::v_1_6::CycloneDx; use std::str::FromStr; use test_context::test_context; use test_log::test; @@ -148,11 +149,7 @@ where test_with( ctx, sbom, - |data| { - Ok(serde_json::from_slice::< - serde_cyclonedx::cyclonedx::v_1_6::CycloneDx, - >(data)?) - }, + |data| Ok(serde_json::from_slice::(data)?), async move |ctx, sbom, tx| { Ok(ctx .ingest_cyclonedx(Box::new(sbom.clone()), &Discard, tx) diff --git a/modules/importer/src/service.rs b/modules/importer/src/service.rs index fece8f357..bd361406f 100644 --- a/modules/importer/src/service.rs +++ b/modules/importer/src/service.rs @@ -12,8 +12,8 @@ use trustify_common::{ db::{ DatabaseErrors, ReadWrite, limiter::{LimitedResult, LimiterTrait}, - pagination_cache::PaginationCache, - query::{Filtering, Query}, + pagination_cache::{LimitError, PaginationCache}, + query::{Error as QueryError, Filtering, Query}, }, error::ErrorInformation, model::{PaginatedResults, Pagination, Revisioned}, @@ -36,11 +36,11 @@ pub enum Error { #[error(transparent)] Json(#[from] serde_json::Error), #[error(transparent)] - Query(#[from] trustify_common::db::query::Error), + Query(#[from] QueryError), #[error(transparent)] Label(#[from] labels::Error), #[error(transparent)] - Limit(#[from] trustify_common::db::pagination_cache::LimitError), + Limit(#[from] LimitError), } impl From for Error { diff --git a/modules/ingestor/benches/detect.rs b/modules/ingestor/benches/detect.rs index bc9917c7d..a67f1888e 100644 --- a/modules/ingestor/benches/detect.rs +++ b/modules/ingestor/benches/detect.rs @@ -1,6 +1,7 @@ #![allow(clippy::expect_used)] use criterion::{Criterion, criterion_group, criterion_main}; +use serde_cyclonedx::cyclonedx::v_1_6::CycloneDx; use std::hint::black_box; use trustify_module_ingestor::service::{DocumentDetector, Format}; use trustify_test_context::document_bytes; @@ -23,7 +24,7 @@ fn try_parse_direct(bytes: &[u8]) -> Option { if serde_json::from_slice::(bytes).is_ok() { return Some(Format::OSV); } - if serde_json::from_slice::(bytes).is_ok() { + if serde_json::from_slice::(bytes).is_ok() { return Some(Format::CycloneDX); } if serde_json::from_slice::(bytes) diff --git a/modules/ingestor/src/graph/db_context.rs b/modules/ingestor/src/graph/db_context.rs index e2ae3b60c..3390d0ed9 100644 --- a/modules/ingestor/src/graph/db_context.rs +++ b/modules/ingestor/src/graph/db_context.rs @@ -44,7 +44,7 @@ impl DbContext { self.status_cache .get(status) .cloned() - .ok_or_else(|| crate::graph::error::Error::InvalidStatus(status.to_string())) + .ok_or_else(|| Error::InvalidStatus(status.to_string())) } } diff --git a/modules/ingestor/src/graph/sbom/common/checksum.rs b/modules/ingestor/src/graph/sbom/common/checksum.rs index 135a2c0f0..ccf3fa923 100644 --- a/modules/ingestor/src/graph/sbom/common/checksum.rs +++ b/modules/ingestor/src/graph/sbom/common/checksum.rs @@ -1,4 +1,4 @@ -use serde_cyclonedx::cyclonedx::v_1_6::HashAlg; +use serde_cyclonedx::cyclonedx::v_1_6::{Hash, HashAlg}; use spdx_rs::models::Algorithm; use std::borrow::Cow; @@ -13,8 +13,8 @@ impl Checksum { pub const NONE: [Self; 0] = []; } -impl From for Checksum { - fn from(value: serde_cyclonedx::cyclonedx::v_1_6::Hash) -> Self { +impl From for Checksum { + fn from(value: Hash) -> Self { Self { r#type: match value.alg { HashAlg::Md5 => "MD5", diff --git a/modules/ingestor/src/graph/sbom/common/relationship.rs b/modules/ingestor/src/graph/sbom/common/relationship.rs index 9bad6ba3b..4648d3df2 100644 --- a/modules/ingestor/src/graph/sbom/common/relationship.rs +++ b/modules/ingestor/src/graph/sbom/common/relationship.rs @@ -3,7 +3,7 @@ use anyhow::bail; use sea_orm::{ActiveValue::Set, ConnectionTrait, DbErr, EntityTrait}; use sea_query::OnConflict; use spdx_rs::models::{Algorithm, ExternalDocumentReference}; -use std::collections::HashSet; +use std::collections::{HashSet, hash_set}; use tracing::instrument; use trustify_common::db::chunk::EntityChunkedIter; use trustify_entity::sbom_external_node::{DiscriminatorType, ExternalType}; @@ -219,7 +219,7 @@ pub struct References<'a> { impl<'a> IntoIterator for References<'a> { type Item = &'a str; - type IntoIter = std::collections::hash_set::IntoIter<&'a str>; + type IntoIter = hash_set::IntoIter<&'a str>; fn into_iter(self) -> Self::IntoIter { self.refs.into_iter() diff --git a/modules/ingestor/src/service/advisory/csaf/creator.rs b/modules/ingestor/src/service/advisory/csaf/creator.rs index dbb43565a..c1602aae8 100644 --- a/modules/ingestor/src/service/advisory/csaf/creator.rs +++ b/modules/ingestor/src/service/advisory/csaf/creator.rs @@ -2,7 +2,7 @@ use crate::{ graph::{ Graph, advisory::{ - product_status::ProductVersionRange, + product_status::{ProductStatus as GraphProductStatus, ProductVersionRange}, purl_status::PurlStatus, version::{Version, VersionInfo, VersionSpec}, }, @@ -216,7 +216,7 @@ impl<'a> StatusCreator<'a> { let csaf_product_ids = product_to_csaf_ids.get(&product).cloned(); for package in packages { - let product_status = crate::graph::advisory::product_status::ProductStatus { + let product_status = GraphProductStatus { cpe: product.cpe.clone(), package, status: status_id, diff --git a/modules/ingestor/src/service/detect.rs b/modules/ingestor/src/service/detect.rs index 731d9b460..f46bae5e7 100644 --- a/modules/ingestor/src/service/detect.rs +++ b/modules/ingestor/src/service/detect.rs @@ -20,6 +20,7 @@ use cve::Cve; use osv::schema::Vulnerability; use quick_xml::{Reader, events::Event}; use sea_orm::{ConnectionTrait, TransactionTrait}; +use serde_cyclonedx::cyclonedx::v_1_6::CycloneDx; use std::io::Cursor; use tracing::instrument; use trustify_common::hashing::Digests; @@ -52,7 +53,7 @@ pub enum DetectedDocument { Osv(Box), /// SPDX keeps the raw Value because the loader applies license fixups before ingestion. Spdx(serde_json::Value), - CycloneDx(Box), + CycloneDx(Box), ClearlyDefined(serde_json::Value), ClearlyDefinedCuration(Box), /// XML kept as raw bytes; the loader parses with roxmltree internally. diff --git a/modules/ingestor/src/service/mod.rs b/modules/ingestor/src/service/mod.rs index ca2640306..007c3c87d 100644 --- a/modules/ingestor/src/service/mod.rs +++ b/modules/ingestor/src/service/mod.rs @@ -11,12 +11,14 @@ pub use format::Format; pub use json::JsonSource; use crate::graph::Graph; +use crate::graph::error::Error as GraphError; use crate::{ model::IngestResult, service::dataset::{DatasetIngestResult, DatasetLoader}, }; use actix_web::{HttpResponse, ResponseError, body::BoxBody}; use anyhow::anyhow; +use jsonpath_rust::parser::errors::JsonPathError; use parking_lot::Mutex; use sbom_walker::report::ReportSink; use sea_orm::error::DbErr; @@ -40,13 +42,13 @@ pub enum Error { #[error(transparent)] Json(#[from] serde_json::Error), #[error(transparent)] - JsonPath(#[from] jsonpath_rust::parser::errors::JsonPathError), + JsonPath(#[from] JsonPathError), #[error(transparent)] Xml(#[from] roxmltree::Error), #[error(transparent)] Yaml(#[from] serde_yml::Error), #[error(transparent)] - Graph(#[from] crate::graph::error::Error), + Graph(#[from] GraphError), #[error(transparent)] Db(DbErr), #[error("storage error: {0}")] diff --git a/modules/ingestor/src/service/sbom/cyclonedx.rs b/modules/ingestor/src/service/sbom/cyclonedx.rs index b97b3ac06..4488bb672 100644 --- a/modules/ingestor/src/service/sbom/cyclonedx.rs +++ b/modules/ingestor/src/service/sbom/cyclonedx.rs @@ -4,7 +4,7 @@ use crate::{ service::{Error, JsonSource, Warnings}, }; use sea_orm::{ConnectionTrait, TransactionTrait}; -use serde_cyclonedx::cyclonedx::v_1_6::Component; +use serde_cyclonedx::cyclonedx::v_1_6::{Component, CycloneDx}; use std::str::FromStr; use tracing::instrument; use trustify_common::hashing::Digests; @@ -28,7 +28,7 @@ impl<'g> CyclonedxLoader<'g> { digests: &Digests, tx: &(impl ConnectionTrait + TransactionTrait), ) -> Result { - let cdx: Box = source + let cdx: Box = source .parse_json() .map_err(|err| Error::UnsupportedFormat(format!("Failed to parse: {err}")))?; @@ -39,7 +39,7 @@ impl<'g> CyclonedxLoader<'g> { pub(crate) async fn ingest( &self, labels: Labels, - cdx: Box, + cdx: Box, digests: &Digests, tx: &(impl ConnectionTrait + TransactionTrait), ) -> Result { diff --git a/modules/storage/src/service/s3.rs b/modules/storage/src/service/s3.rs index 283c8334c..e1cb09614 100644 --- a/modules/storage/src/service/s3.rs +++ b/modules/storage/src/service/s3.rs @@ -18,7 +18,7 @@ use aws_sdk_s3::{ types::{Delete, ObjectIdentifier}, }; use aws_smithy_http_client::tls::{Provider, TlsContext, TrustStore, rustls_provider::CryptoMode}; -use aws_smithy_types::endpoint::Endpoint; +use aws_smithy_types::{byte_stream::error::Error as ByteStreamError, endpoint::Endpoint}; use bytes::Bytes; use futures::{Stream, TryStreamExt}; use std::{fmt::Debug, io, str::FromStr}; @@ -274,7 +274,7 @@ pub enum Error { #[error(transparent)] S3(#[from] aws_sdk_s3::Error), #[error(transparent)] - Bytes(#[from] aws_smithy_types::byte_stream::error::Error), + Bytes(#[from] ByteStreamError), #[error(transparent)] Io(#[from] io::Error), #[error("{0}")] diff --git a/modules/ui/src/service.rs b/modules/ui/src/service.rs index e952fe521..f88bd5038 100644 --- a/modules/ui/src/service.rs +++ b/modules/ui/src/service.rs @@ -1,5 +1,5 @@ use crate::model::ExtractPackage; -use serde_cyclonedx::cyclonedx::v_1_6::{Component, ComponentEvidenceIdentity}; +use serde_cyclonedx::cyclonedx::v_1_6::{Component, ComponentEvidenceIdentity, CycloneDx}; use std::collections::BTreeMap; use trustify_common::purl::Purl; @@ -30,7 +30,7 @@ pub fn extract_spdx_purls( /// Extract PURLs from a CycloneDX file pub fn extract_cyclonedx_purls( - sbom: serde_cyclonedx::cyclonedx::v_1_6::CycloneDx, + sbom: CycloneDx, warnings: &mut Vec, ) -> BTreeMap { let mut result = BTreeMap::new(); diff --git a/query/src/lib.rs b/query/src/lib.rs index fbb43a578..f35bdc3df 100644 --- a/query/src/lib.rs +++ b/query/src/lib.rs @@ -3,7 +3,7 @@ use utoipa::{ IntoParams, openapi::{ ObjectBuilder, Type, - path::{Parameter, ParameterIn}, + path::{Parameter, ParameterBuilder, ParameterIn}, }, }; @@ -19,13 +19,13 @@ pub struct TrustifyQuery { impl IntoParams for TrustifyQuery { fn into_params(_parameter_in_provider: impl Fn() -> Option) -> Vec { vec![ - utoipa::openapi::path::ParameterBuilder::new() + ParameterBuilder::new() .name("q") .parameter_in(ParameterIn::Query) .description(Some(T::generate_query_description())) .schema(Some(ObjectBuilder::new().schema_type(Type::String))) .build(), - utoipa::openapi::path::ParameterBuilder::new() + ParameterBuilder::new() .name("sort") .parameter_in(ParameterIn::Query) .description(Some(T::generate_sort_description())) diff --git a/trustd/src/main.rs b/trustd/src/main.rs index 0f75563e2..269421376 100644 --- a/trustd/src/main.rs +++ b/trustd/src/main.rs @@ -9,6 +9,7 @@ use tokio::{ select, task::{LocalSet, spawn_local}, }; +use trustify_server::profile::{api::Run as ApiRun, importer::Run as ImporterRun}; mod db; mod openapi; @@ -17,9 +18,9 @@ mod openapi; #[derive(clap::Subcommand, Debug)] pub enum Command { /// Run the API server - Api(trustify_server::profile::api::Run), + Api(ApiRun), /// Run the importer server - Importer(trustify_server::profile::importer::Run), + Importer(ImporterRun), /// Manage the database Db(db::Run), /// Access OpenAPI related information of the API server diff --git a/xtask/src/precommit.rs b/xtask/src/precommit.rs index c4b71d059..60f355d85 100644 --- a/xtask/src/precommit.rs +++ b/xtask/src/precommit.rs @@ -28,6 +28,8 @@ impl Precommit { "clippy::unwrap_used", "-D", "clippy::expect_used", + "-W", + "clippy::absolute_paths", ]) .status() .map_err(|_| anyhow!("cargo clippy failed"))?