Skip to content

Commit

Permalink
Integrate review feedback
Browse files Browse the repository at this point in the history
* use `PackageIdSpec` instead of only `PackageId` in SBOM output
* change `version` of a dependency to `Option<Version>`
* output `Vec<CrateType>` instead of only the first found crate type
* output rustc workspace wrapper
* update 'warning' string in test using `[WARNING]`
* use `serde_json::to_writer` to serialize SBOM
* set sbom suffix in tests explicitely, instead of using `with_extension`
  • Loading branch information
justahero committed May 13, 2024
1 parent 6a05ed9 commit a29ec29
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 38 deletions.
32 changes: 17 additions & 15 deletions src/cargo/core/compiler/output_sbom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
//! See [`output_sbom`] for more.

use std::collections::BTreeSet;
use std::io::{BufWriter, Write};
use std::io::BufWriter;
use std::path::PathBuf;

use cargo_util::paths::{self};
use cargo_util_schemas::core::PackageIdSpec;
use itertools::Itertools;
use semver::Version;
use serde::Serialize;

use crate::{
core::{profiles::Profile, PackageId, Target, TargetKind},
core::{profiles::Profile, Target, TargetKind},
util::Rustc,
CargoResult,
};
Expand Down Expand Up @@ -43,16 +44,16 @@ impl<const V: u32> Serialize for SbomFormatVersion<V> {
#[derive(Serialize, Clone, Debug)]
struct SbomDependency {
name: String,
package_id: PackageId,
version: String,
package_id: PackageIdSpec,
version: Option<Version>,
features: Vec<String>,
}

impl From<&UnitDep> for SbomDependency {
fn from(dep: &UnitDep) -> Self {
let package_id = dep.unit.pkg.package_id();
let package_id = dep.unit.pkg.package_id().to_spec();
let name = package_id.name().to_string();
let version = package_id.version().to_string();
let version = package_id.version();
let features = dep
.unit
.features
Expand All @@ -71,9 +72,9 @@ impl From<&UnitDep> for SbomDependency {

#[derive(Serialize, Clone, Debug)]
struct SbomPackage {
package_id: PackageId,
package_id: PackageIdSpec,
package: String,
version: String,
version: Option<Version>,
features: Vec<String>,
build_type: SbomBuildType,
extern_crate_name: String,
Expand All @@ -86,9 +87,9 @@ impl SbomPackage {
dependencies: Vec<SbomDependency>,
build_type: SbomBuildType,
) -> Self {
let package_id = dep.unit.pkg.package_id();
let package_id = dep.unit.pkg.package_id().to_spec();
let package = package_id.name().to_string();
let version = package_id.version().to_string();
let version = package_id.version();
let features = dep
.unit
.features
Expand All @@ -111,7 +112,7 @@ impl SbomPackage {
#[derive(Serialize)]
struct SbomTarget {
kind: TargetKind,
crate_type: Option<CrateType>,
crate_types: Vec<CrateType>,
name: String,
edition: String,
}
Expand All @@ -120,7 +121,7 @@ impl From<&Target> for SbomTarget {
fn from(target: &Target) -> Self {
SbomTarget {
kind: target.kind().clone(),
crate_type: target.kind().rustc_crate_types().first().cloned(),
crate_types: target.kind().rustc_crate_types().clone(),
name: target.name().to_string(),
edition: target.edition().to_string(),
}
Expand All @@ -131,6 +132,7 @@ impl From<&Target> for SbomTarget {
struct SbomRustc {
version: String,
wrapper: Option<PathBuf>,
workspace_wrapper: Option<PathBuf>,
commit_hash: Option<String>,
host: String,
}
Expand All @@ -140,6 +142,7 @@ impl From<&Rustc> for SbomRustc {
Self {
version: rustc.version.to_string(),
wrapper: rustc.wrapper.clone(),
workspace_wrapper: rustc.workspace_wrapper.clone(),
commit_hash: rustc.commit_hash.clone(),
host: rustc.host.to_string(),
}
Expand Down Expand Up @@ -196,9 +199,8 @@ pub fn output_sbom(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> Cargo
for sbom_output_file in build_runner.sbom_output_files(unit)? {
let sbom = Sbom::new(unit, packages.clone(), rustc.clone());

let mut outfile = BufWriter::new(paths::create(sbom_output_file)?);
let output = serde_json::to_string(&sbom)?;
write!(outfile, "{}", output)?;
let outfile = BufWriter::new(paths::create(sbom_output_file)?);
serde_json::to_writer(outfile, &sbom)?;
}

Ok(())
Expand Down
3 changes: 3 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ build process that are difficult or impossible to obtain in another way.
To enable this feature either set the `sbom` field in the `.cargo/config.toml`

```toml
[unstable]
sbom = true

[build]
sbom = true
```
Expand Down
69 changes: 46 additions & 23 deletions tests/testsuite/sbom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ fn assert_json_output(actual_json_file: PathBuf, expected_json: &str) {
}
}

const SBOM_FILE_EXTENSION: &str = ".cargo-sbom.json";

fn with_sbom_suffix(link: &PathBuf) -> PathBuf {
let mut link_buf = link.clone().into_os_string();
link_buf.push(SBOM_FILE_EXTENSION);
PathBuf::from(link_buf)
}

fn configured_project() -> ProjectBuilder {
project().file(
".cargo/config.toml",
Expand All @@ -39,13 +47,13 @@ fn build_sbom_without_passing_unstable_flag() {
.masquerade_as_nightly_cargo(&["sbom"])
.with_stderr(
"\
warning: ignoring 'sbom' config, pass `-Zsbom` to enable it\n\
[WARNING] ignoring 'sbom' config, pass `-Zsbom` to enable it\n\
[COMPILING] foo v0.5.0 ([..])\n\
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [..]\n",
)
.run();

let file = p.bin("foo").with_extension("cargo-sbom.json");
let file = with_sbom_suffix(&p.bin("foo"));
assert!(!file.exists());
}

Expand All @@ -60,7 +68,7 @@ fn build_sbom_using_cargo_config() {
.masquerade_as_nightly_cargo(&["sbom"])
.run();

let file = p.bin("foo").with_extension("cargo-sbom.json");
let file = with_sbom_suffix(&p.bin("foo"));
assert_json_output(
file,
r#"
Expand All @@ -74,7 +82,9 @@ fn build_sbom_using_cargo_config() {
"kind": [
"bin"
],
"crate_type": "bin",
"crate_types": [
"bin"
],
"name": "foo",
"edition": "2015"
},
Expand All @@ -100,6 +110,7 @@ fn build_sbom_using_cargo_config() {
"rustc": {
"version": "[..]",
"wrapper": null,
"workspace_wrapper": null,
"commit_hash": "[..]",
"host": "[..]"
}
Expand All @@ -120,7 +131,7 @@ fn build_sbom_using_env_var() {
.masquerade_as_nightly_cargo(&["sbom"])
.run();

let file = p.bin("foo").with_extension("cargo-sbom.json");
let file = with_sbom_suffix(&p.bin("foo"));
assert!(file.is_file());
}

Expand All @@ -147,7 +158,7 @@ fn build_sbom_project_bin_and_lib() {
.masquerade_as_nightly_cargo(&["sbom"])
.run();

assert!(p.bin("foo").with_extension("cargo-sbom.json").is_file());
assert!(with_sbom_suffix(&p.bin("foo")).is_file());
assert_eq!(
2,
p.glob(p.target_debug_dir().join("*.cargo-sbom.json"))
Expand All @@ -171,31 +182,36 @@ fn build_sbom_with_simple_build_script() {
.file("src/main.rs", "#[cfg(foo)] fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
r#"fn main() {
println!("cargo::rustc-check-cfg=cfg(foo)");
println!("cargo::rustc-cfg=foo");
}"#,
)
.build();

p.cargo("build -Zsbom")
.masquerade_as_nightly_cargo(&["sbom"])
.run();

let path = p.bin("foo").with_extension("cargo-sbom.json");
let path = with_sbom_suffix(&p.bin("foo"));
assert!(path.is_file());

assert_json_output(
path,
r#"
{
"format_version": 1,
"package_id": "path+file:///[..]/foo#0.0.1",
"package_id": "path+file://[..]/foo#0.0.1",
"name": "foo",
"version": "0.0.1",
"source": "[ROOT]/foo",
"target": {
"kind": [
"bin"
],
"crate_type": "bin",
"crate_types": [
"bin"
],
"name": "foo",
"edition": "2015"
},
Expand Down Expand Up @@ -223,18 +239,18 @@ fn build_sbom_with_simple_build_script() {
{
"features": [],
"name": "foo",
"package_id": "foo 0.0.1 (path+file:///[..]/foo)",
"package_id": "path+file://[..]/foo#0.0.1",
"version": "0.0.1"
}
],
"extern_crate_name": "build_script_build",
"features": [],
"package": "foo",
"package_id": "foo 0.0.1 (path+file:///[..]/foo)",
"package_id": "path+file://[..]/foo#0.0.1",
"version": "0.0.1"
},
{
"package_id": "foo 0.0.1 (path+file:///[..]/foo)",
"package_id": "path+file://[..]/foo#0.0.1",
"package": "foo",
"version": "0.0.1",
"features": [],
Expand All @@ -247,6 +263,7 @@ fn build_sbom_with_simple_build_script() {
"rustc": {
"version": "[..]",
"wrapper": null,
"workspace_wrapper": null,
"commit_hash": "[..]",
"host": "[..]"
}
Expand Down Expand Up @@ -274,7 +291,10 @@ fn build_sbom_with_build_dependencies() {
.file("src/lib.rs", "pub fn bar() -> i32 { 2 }")
.file(
"build.rs",
r#"fn main() { println!("cargo::rustc-cfg=foo"); }"#,
r#"fn main() {
println!("cargo::rustc-check-cfg=cfg(foo)");
println!("cargo::rustc-cfg=foo");
}"#,
)
.publish();

Expand All @@ -298,7 +318,7 @@ fn build_sbom_with_build_dependencies() {
.masquerade_as_nightly_cargo(&["sbom"])
.run();

let path = p.bin("foo").with_extension("cargo-sbom.json");
let path = with_sbom_suffix(&p.bin("foo"));
assert_json_output(
path,
r#"
Expand All @@ -312,7 +332,9 @@ fn build_sbom_with_build_dependencies() {
"kind": [
"bin"
],
"crate_type": "bin",
"crate_types": [
"bin"
],
"name": "foo",
"edition": "2015"
},
Expand All @@ -335,7 +357,7 @@ fn build_sbom_with_build_dependencies() {
},
"packages": [
{
"package_id": "bar 0.1.0 (registry+[..])",
"package_id": "registry+[..]#bar@0.1.0",
"package": "bar",
"version": "0.1.0",
"features": [],
Expand All @@ -344,14 +366,14 @@ fn build_sbom_with_build_dependencies() {
"dependencies": [
{
"name": "bar",
"package_id": "bar 0.1.0 (registry+[..])",
"package_id": "registry+[..]#bar@0.1.0",
"version": "0.1.0",
"features": []
}
]
},
{
"package_id": "bar 0.1.0 (registry+[..])",
"package_id": "registry+[..]#bar@0.1.0",
"package": "bar",
"version": "0.1.0",
"features": [],
Expand All @@ -360,14 +382,14 @@ fn build_sbom_with_build_dependencies() {
"dependencies": [
{
"name": "bar",
"package_id": "bar 0.1.0 (registry+[..])",
"package_id": "registry+[..]#bar@0.1.0",
"version": "0.1.0",
"features": []
}
]
},
{
"package_id": "bar 0.1.0 (registry+[..])",
"package_id": "registry+[..]#bar@0.1.0",
"package": "bar",
"version": "0.1.0",
"features": [],
Expand All @@ -376,14 +398,14 @@ fn build_sbom_with_build_dependencies() {
"dependencies": [
{
"name": "baz",
"package_id": "baz 0.1.0 (registry+[..])",
"package_id": "registry+[..]#baz@0.1.0",
"version": "0.1.0",
"features": []
}
]
},
{
"package_id": "baz 0.1.0 (registry+[..])",
"package_id": "registry+[..]#baz@0.1.0",
"package": "baz",
"version": "0.1.0",
"features": [],
Expand All @@ -396,6 +418,7 @@ fn build_sbom_with_build_dependencies() {
"rustc": {
"version": "[..]",
"wrapper": null,
"workspace_wrapper": null,
"commit_hash": "[..]",
"host": "[..]"
}
Expand Down

0 comments on commit a29ec29

Please sign in to comment.