@@ -16,12 +16,14 @@ use crate::{
1616 sbom:: {
1717 model:: {
1818 LicenseRefMapping , SbomExternalPackageReference , SbomNodeReference , SbomPackage ,
19- SbomPackageRelation , SbomSummary , Which , details:: SbomAdvisory ,
19+ SbomPackageRelation , SbomSummary , Which ,
20+ details:: SbomAdvisory ,
21+ exploitiq:: { ExploitIqRequest , ReportRequest , ReportResult } ,
2022 } ,
2123 service:: SbomService ,
2224 } ,
2325} ;
24- use actix_web:: { HttpResponse , Responder , delete, get, http:: header, post, web} ;
26+ use actix_web:: { HttpResponse , Responder , delete, get, http:: header, post, web, web :: BytesMut } ;
2527use config:: Config ;
2628use futures_util:: TryStreamExt ;
2729use sea_orm:: { TransactionTrait , prelude:: Uuid } ;
@@ -424,6 +426,48 @@ pub async fn related(
424426 Ok ( HttpResponse :: Ok ( ) . json ( result) )
425427}
426428
429+ /// Create ExploitIQ report
430+ #[ utoipa:: path(
431+ tag = "sbom" ,
432+ operation_id = "createExploitIQReport" ,
433+ params(
434+ ( "id" = Id , Path ) ,
435+ ) ,
436+ responses(
437+ ( status = 201 , description = "Create a report" , body = ReportResult ) ,
438+ ( status = 400 , description = "Unable to read advisory list" ) ,
439+ ( status = 404 , description = "The SBOM could not be found" ) ,
440+ )
441+ ) ]
442+ #[ post( "/v2/sbom/{id}/exploitiq" ) ]
443+ pub async fn create_exploitiq_report (
444+ ingestor : web:: Data < IngestorService > ,
445+ db : web:: Data < Database > ,
446+ sbom : web:: Data < SbomService > ,
447+ id : web:: Path < String > ,
448+ web:: Json ( ReportRequest { vulnerabilities } ) : web:: Json < ReportRequest > ,
449+ _: Require < ReadSbom > ,
450+ ) -> Result < impl Responder , Error > {
451+ let id = Id :: from_str ( & id) . map_err ( Error :: IdKey ) ?;
452+ match sbom
453+ . fetch_sbom_summary ( id, db. as_ref ( ) )
454+ . await ?
455+ . and_then ( |sbom| sbom. source_document )
456+ {
457+ Some ( doc) => Ok ( match ingestor. storage ( ) . retrieve ( doc. try_into ( ) ?) . await ? {
458+ Some ( s) => {
459+ let buf = s. try_collect :: < BytesMut > ( ) . await ?;
460+ let sbom: serde_json:: Value = serde_json:: from_slice ( buf. as_ref ( ) ) ?;
461+ let _req = ExploitIqRequest :: new ( sbom, vulnerabilities) ;
462+ // TODO: Invoke external service here
463+ HttpResponse :: Ok ( ) . json ( ReportResult :: default ( ) )
464+ }
465+ None => HttpResponse :: NotFound ( ) . finish ( ) ,
466+ } ) ,
467+ None => Ok ( HttpResponse :: NotFound ( ) . finish ( ) ) ,
468+ }
469+ }
470+
427471#[ derive( Clone , Debug , serde:: Deserialize , utoipa:: IntoParams ) ]
428472struct UploadQuery {
429473 /// Optional labels.
@@ -500,26 +544,18 @@ pub async fn download(
500544 _: Require < ReadSbom > ,
501545) -> Result < impl Responder , Error > {
502546 let id = Id :: from_str ( & key) . map_err ( Error :: IdKey ) ?;
503-
504- let Some ( sbom) = sbom. fetch_sbom_summary ( id, db. as_ref ( ) ) . await ? else {
505- return Ok ( HttpResponse :: NotFound ( ) . finish ( ) ) ;
506- } ;
507-
508- if let Some ( doc) = & sbom. source_document {
509- let storage_key = doc. try_into ( ) ?;
510-
511- let stream = ingestor
512- . storage ( )
513- . retrieve ( storage_key)
514- . await
515- . map_err ( Error :: Storage ) ?
516- . map ( |stream| stream. map_err ( Error :: Storage ) ) ;
517-
518- Ok ( match stream {
519- Some ( s) => HttpResponse :: Ok ( ) . streaming ( s) ,
520- None => HttpResponse :: NotFound ( ) . finish ( ) ,
521- } )
522- } else {
523- Ok ( HttpResponse :: NotFound ( ) . finish ( ) )
547+ match sbom
548+ . fetch_sbom_summary ( id, db. as_ref ( ) )
549+ . await ?
550+ . and_then ( |sbom| sbom. source_document )
551+ {
552+ Some ( doc) => {
553+ let storage_key = doc. try_into ( ) ?;
554+ Ok ( match ingestor. storage ( ) . retrieve ( storage_key) . await ? {
555+ Some ( s) => HttpResponse :: Ok ( ) . streaming ( s) ,
556+ None => HttpResponse :: NotFound ( ) . finish ( ) ,
557+ } )
558+ }
559+ None => Ok ( HttpResponse :: NotFound ( ) . finish ( ) ) ,
524560 }
525561}
0 commit comments