Skip to content

Commit 5c63eb7

Browse files
authored
Merge pull request #630 from Shnatsel/refactor
More robust target kind recording
2 parents a9ff97d + 5dd79fd commit 5c63eb7

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed

cargo-cyclonedx/src/generator.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
7988
impl 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

680689
impl 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

Comments
 (0)