@@ -76,6 +76,15 @@ pub struct SbomGenerator {
7676 crate_hashes : HashMap < cargo_metadata:: PackageId , Checksum > ,
7777}
7878
79+ /// Contains a map from `bom_ref` of a subcomponent to the kinds of Cargo targets it has,
80+ /// sourced from `cargo metadata`
81+ #[ derive( Debug , Clone ) ]
82+ pub struct TargetKinds (
83+ // TODO: refactor it to store Vec<TargetKind> once `cargo_metadata` crate ships enums:
84+ // https://github.com/oli-obk/cargo_metadata/pull/258
85+ HashMap < String , Vec < String > > ,
86+ ) ;
87+
7988impl SbomGenerator {
8089 pub fn create_sboms (
8190 meta : CargoMetadata ,
@@ -97,14 +106,6 @@ impl SbomGenerator {
97106 top_level_dependencies ( member, & packages, & resolve)
98107 } ;
99108
100- // Figure out the types of the various produced artifacts.
101- // This is additional information on top of the SBOM structure
102- // that is used to implement emitting a separate SBOM for each binary or artifact.
103- let root_package = & packages[ member] ;
104- let target_kinds: Vec < Vec < String > > = filter_targets ( & root_package. targets )
105- . map ( |tgt| tgt. kind . clone ( ) )
106- . collect ( ) ;
107-
108109 let manifest_path = packages[ member] . manifest_path . clone ( ) . into_std_path_buf ( ) ;
109110
110111 let mut crate_hashes = HashMap :: new ( ) ;
@@ -127,7 +128,8 @@ impl SbomGenerator {
127128 workspace_root : meta. workspace_root . to_owned ( ) ,
128129 crate_hashes,
129130 } ;
130- let bom = generator. create_bom ( member, & dependencies, & pruned_resolve) ?;
131+ let ( bom, target_kinds) =
132+ generator. create_bom ( member, & dependencies, & pruned_resolve) ?;
131133
132134 let generated = GeneratedSbom {
133135 bom,
@@ -148,7 +150,7 @@ impl SbomGenerator {
148150 package : & PackageId ,
149151 packages : & PackageMap ,
150152 resolve : & ResolveMap ,
151- ) -> Result < Bom , GeneratorError > {
153+ ) -> Result < ( Bom , TargetKinds ) , GeneratorError > {
152154 let mut bom = Bom :: default ( ) ;
153155 let root_package = & packages[ package] ;
154156
@@ -160,13 +162,13 @@ impl SbomGenerator {
160162
161163 bom. components = Some ( Components ( components) ) ;
162164
163- let metadata = self . create_metadata ( & packages[ package] ) ?;
165+ let ( metadata, target_kinds ) = self . create_metadata ( & packages[ package] ) ?;
164166
165167 bom. metadata = Some ( metadata) ;
166168
167169 bom. dependencies = Some ( create_dependencies ( resolve) ) ;
168170
169- Ok ( bom)
171+ Ok ( ( bom, target_kinds ) )
170172 }
171173
172174 fn create_component ( & self , package : & Package , root_package : & Package ) -> Component {
@@ -204,9 +206,10 @@ impl SbomGenerator {
204206
205207 /// Same as [Self::create_component] but also includes information
206208 /// on binaries and libraries comprising it as subcomponents
207- fn create_toplevel_component ( & self , package : & Package ) -> Component {
209+ fn create_toplevel_component ( & self , package : & Package ) -> ( Component , TargetKinds ) {
208210 let mut top_component = self . create_component ( package, package) ;
209211 let mut subcomponents: Vec < Component > = Vec :: new ( ) ;
212+ let mut target_kinds = HashMap :: new ( ) ;
210213 for tgt in filter_targets ( & package. targets ) {
211214 // classification
212215 #[ allow( clippy:: if_same_then_else) ]
@@ -234,6 +237,9 @@ impl SbomGenerator {
234237 subcomponents. len( ) , // numbers the components
235238 ) ;
236239
240+ // record target kinds now that we have the bom_ref
241+ target_kinds. insert ( bom_ref. clone ( ) , tgt. kind . clone ( ) ) ;
242+
237243 // create the subcomponent
238244 let mut subcomponent = Component :: new (
239245 cdx_type,
@@ -268,7 +274,7 @@ impl SbomGenerator {
268274 subcomponents. push ( subcomponent) ;
269275 }
270276 top_component. components = Some ( Components ( subcomponents) ) ;
271- top_component
277+ ( top_component, TargetKinds ( target_kinds ) )
272278 }
273279
274280 fn get_classification ( pkg : & Package ) -> Classification {
@@ -445,15 +451,18 @@ impl SbomGenerator {
445451 }
446452 }
447453
448- fn create_metadata ( & self , package : & Package ) -> Result < Metadata , GeneratorError > {
454+ fn create_metadata (
455+ & self ,
456+ package : & Package ,
457+ ) -> Result < ( Metadata , TargetKinds ) , GeneratorError > {
449458 let authors = Self :: create_authors ( package) ;
450459
451460 let mut metadata = Metadata :: new ( ) ?;
452461 if !authors. is_empty ( ) {
453462 metadata. authors = Some ( authors) ;
454463 }
455464
456- let mut component = self . create_toplevel_component ( package) ;
465+ let ( mut component, target_kinds ) = self . create_toplevel_component ( package) ;
457466
458467 component. component_type = Self :: get_classification ( package) ;
459468
@@ -463,7 +472,7 @@ impl SbomGenerator {
463472
464473 metadata. tools = Some ( Tools ( vec ! [ tool] ) ) ;
465474
466- Ok ( metadata)
475+ Ok ( ( metadata, target_kinds ) )
467476 }
468477
469478 fn create_authors ( package : & Package ) -> Vec < OrganizationalContact > {
@@ -674,7 +683,7 @@ pub struct GeneratedSbom {
674683 pub manifest_path : PathBuf ,
675684 pub package_name : String ,
676685 pub sbom_config : SbomConfig ,
677- pub target_kinds : Vec < Vec < String > > ,
686+ pub target_kinds : TargetKinds ,
678687}
679688
680689impl GeneratedSbom {
@@ -733,7 +742,7 @@ impl GeneratedSbom {
733742 /// Returns an iterator over SBOMs and their associated target kinds
734743 fn per_artifact_sboms < ' a > (
735744 bom : & ' a Bom ,
736- target_kinds : & ' a [ Vec < String > ] ,
745+ target_kinds : & ' a TargetKinds ,
737746 pattern : Pattern ,
738747 ) -> impl Iterator < Item = ( Bom , Vec < String > ) > + ' a {
739748 let meta = bom. metadata . as_ref ( ) . unwrap ( ) ;
@@ -743,8 +752,8 @@ impl GeneratedSbom {
743752 components
744753 . 0
745754 . iter ( )
746- . zip ( target_kinds . iter ( ) )
747- . filter ( move | ( _component , target_kind) | {
755+ . filter ( move |component| {
756+ let target_kind = & target_kinds . 0 [ component . bom_ref . as_ref ( ) . unwrap ( ) ] ;
748757 match pattern {
749758 Pattern :: Binary => {
750759 // only record binary artifacts
@@ -757,7 +766,8 @@ impl GeneratedSbom {
757766 Pattern :: Bom | Pattern :: Package => unreachable ! ( ) ,
758767 }
759768 } )
760- . map ( |( component, target_kind) | {
769+ . map ( |component| {
770+ let target_kind = & target_kinds. 0 [ component. bom_ref . as_ref ( ) . unwrap ( ) ] ;
761771 // In the original SBOM the toplevel component describes a crate.
762772 // We need to change it to describe a specific binary.
763773 // Most properties apply to the entire package and should be kept;
0 commit comments