-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: implement RFC 3553 to add SBOM support #13709
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,17 @@ | ||
//! [`BuildRunner`] is the mutable state used during the build process. | ||
|
||
use std::collections::{BTreeSet, HashMap, HashSet}; | ||
use std::io::BufWriter; | ||
use std::path::{Path, PathBuf}; | ||
use std::sync::{Arc, Mutex}; | ||
|
||
use crate::core::compiler::compilation::{self, UnitOutput}; | ||
use crate::core::compiler::{self, artifact, Unit}; | ||
use crate::core::PackageId; | ||
use crate::core::compiler::{self, artifact, CrateType, Unit}; | ||
use crate::core::{PackageId, TargetKind}; | ||
use crate::util::cache_lock::CacheLockMode; | ||
use crate::util::errors::CargoResult; | ||
use anyhow::{bail, Context as _}; | ||
use cargo_util::paths; | ||
use filetime::FileTime; | ||
use itertools::Itertools; | ||
use jobserver::Client; | ||
|
@@ -291,6 +293,14 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { | |
} | ||
|
||
super::output_depinfo(&mut self, unit)?; | ||
|
||
if self.bcx.build_config.sbom { | ||
let sbom = super::build_sbom(&mut self, unit)?; | ||
for sbom_output_file in self.sbom_output_files(unit)? { | ||
let outfile = BufWriter::new(paths::create(sbom_output_file)?); | ||
serde_json::to_writer(outfile, &sbom)?; | ||
} | ||
} | ||
} | ||
|
||
for (script_meta, output) in self.build_script_outputs.lock().unwrap().iter() { | ||
|
@@ -446,6 +456,44 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { | |
self.files().metadata(unit).unit_id() | ||
} | ||
|
||
/// Returns the list of SBOM output file paths for a given [`Unit`]. | ||
/// | ||
/// Only call this function when `sbom` is active. | ||
pub fn sbom_output_files(&self, unit: &Unit) -> CargoResult<Vec<PathBuf>> { | ||
weihanglo marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do these need to be calculated in |
||
const SBOM_FILE_EXTENSION: &str = ".cargo-sbom.json"; | ||
|
||
fn append_sbom_suffix(link: &PathBuf, suffix: &str) -> PathBuf { | ||
let mut link_buf = link.clone().into_os_string(); | ||
link_buf.push(suffix); | ||
PathBuf::from(link_buf) | ||
} | ||
|
||
assert!(self.bcx.build_config.sbom); | ||
let sbom_enabled = match unit.target.kind() { | ||
TargetKind::Lib(crate_types) | TargetKind::ExampleLib(crate_types) => { | ||
crate_types.iter().any(|crate_type| { | ||
matches!( | ||
crate_type, | ||
CrateType::Cdylib | CrateType::Dylib | CrateType::Staticlib | ||
) | ||
}) | ||
} | ||
TargetKind::Bin | TargetKind::Test | TargetKind::Bench | TargetKind::ExampleBin => true, | ||
TargetKind::CustomBuild => false, | ||
}; | ||
if !sbom_enabled { | ||
return Ok(Vec::new()); | ||
} | ||
|
||
let files = self | ||
.outputs(unit)? | ||
.iter() | ||
.filter(|o| matches!(o.flavor, FileFlavor::Normal | FileFlavor::Linkable)) | ||
Comment on lines
+472
to
+491
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a place to track specific points we want to have called out in the RFC? For me, when we do this is one of them |
||
.map(|link| append_sbom_suffix(link.bin_dst(), SBOM_FILE_EXTENSION)) | ||
.collect::<Vec<_>>(); | ||
Ok(files) | ||
} | ||
|
||
pub fn is_primary_package(&self, unit: &Unit) -> bool { | ||
self.primary_packages.contains(&unit.pkg.package_id()) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ pub(crate) mod layout; | |
mod links; | ||
mod lto; | ||
mod output_depinfo; | ||
mod output_sbom; | ||
pub mod rustdoc; | ||
pub mod standard_lib; | ||
mod timings; | ||
|
@@ -85,6 +86,7 @@ use self::job_queue::{Job, JobQueue, JobState, Work}; | |
pub(crate) use self::layout::Layout; | ||
pub use self::lto::Lto; | ||
use self::output_depinfo::output_depinfo; | ||
use self::output_sbom::build_sbom; | ||
use self::unit_graph::UnitDep; | ||
use crate::core::compiler::future_incompat::FutureIncompatReport; | ||
pub use crate::core::compiler::unit::{Unit, UnitInterner}; | ||
|
@@ -685,6 +687,7 @@ where | |
/// completion of other units will be added later in runtime, such as flags | ||
/// from build scripts. | ||
fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> { | ||
let gctx = build_runner.bcx.gctx; | ||
let is_primary = build_runner.is_primary_package(unit); | ||
let is_workspace = build_runner.bcx.ws.is_member(&unit.pkg); | ||
|
||
|
@@ -700,7 +703,7 @@ fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult | |
base.args(args); | ||
} | ||
base.args(&unit.rustflags); | ||
if build_runner.bcx.gctx.cli_unstable().binary_dep_depinfo { | ||
if gctx.cli_unstable().binary_dep_depinfo { | ||
base.arg("-Z").arg("binary-dep-depinfo"); | ||
} | ||
if build_runner.bcx.gctx.cli_unstable().checksum_freshness { | ||
|
@@ -709,6 +712,11 @@ fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult | |
|
||
if is_primary { | ||
base.env("CARGO_PRIMARY_PACKAGE", "1"); | ||
|
||
if gctx.cli_unstable().sbom && build_runner.bcx.build_config.sbom { | ||
justahero marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let file_list = std::env::join_paths(build_runner.sbom_output_files(unit)?)?; | ||
base.env("CARGO_SBOM_PATH", file_list); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you document this in the unstable docs like it will be when moved to the stable docs? I want to make sure we call out that it can be multiple files |
||
} | ||
} | ||
|
||
if unit.target.is_test() || unit.target.is_bench() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are outputting the same sbom for each output.
If we're package focused, that makes sense. If we're create focused, then that doesn't quite work.
Is there anything specific about each root artifact that we'd want to call out?