Skip to content

Conversation

@thomasschafer
Copy link

@thomasschafer thomasschafer commented Oct 30, 2025

Summary

This PR adds a new SBOM format (CycloneDX v1.5 JSON) to the uv export command.

One notable point about the implementation is the use of a synthetic root when using the --all-projects flag. This has been discussed separately in more detail, but on a high level, it is possible for workspace packages to be disconnected from the workspace root, so if we had the workspace root as the root component in the SBOM then in such cases there would be unreachable components, which causes issues with some SBOM tooling. By having a synthetic root we ensure that all components can be reached by traversing from the root of the SBOM.

Screenshot 2025-10-30 at 17 38 49

Resolves #6012

Test Plan

We've tested manually using a variety of uv projects locally, and have added a variety of tests to crates/uv/tests/it/export.rs.

@thomasschafer thomasschafer force-pushed the sbom-export-support branch 3 times, most recently from 31c2e14 to 4d897e8 Compare October 30, 2025 20:28
@konstin konstin requested a review from woodruffw October 31, 2025 09:37
@thomasschafer thomasschafer marked this pull request as ready for review October 31, 2025 09:49
@thomasschafer thomasschafer force-pushed the sbom-export-support branch 5 times, most recently from 9901b84 to e110bcd Compare October 31, 2025 13:19
Copy link
Member

@woodruffw woodruffw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Some questions and nitpicks 🙂

Comment on lines +323 to +328
Source::Registry(_) | Source::Git(_, _) | Source::Direct(_, _) => {
// Workspace packages are always local dependencies
unreachable!(
"Workspace member {:?} has non-local source {:?}",
node.package.id.name, node.package.id.source,
)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flagging: I don't know uv workspaces well enough to know if this is right 🙂 -- @zanieb or @konstin should confirm this!

Comment on lines 367 to 372
let mut output = Vec::<u8>::new();

export.output_as_json_v1_5(&mut output)?;

let output_str = String::from_utf8(output)?;
write!(writer, "{output_str}")?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: instead of building an intermediate buffer + string, why not send export.output_as_json_v1_5 directly to writer? If I'm following right, that should avoid rebuffering and allocations here.

Ref: https://docs.rs/cyclonedx-bom/0.8.0/cyclonedx_bom/models/bom/struct.Bom.html#method.output_as_json_v1_5

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a go at this but seeing the error below - I think it's because output_as_json_v1_5 has a bound of std::io::Write which OutputWriter doesn't implement, it just has write_fmt defined

$ cargo check
    Checking uv v0.9.7 (/Users/thomasschafer/Development/uv/crates/uv)
error[E0277]: the trait bound `OutputWriter<'_>: std::io::Write` is not satisfied
   --> crates/uv/src/commands/project/export.rs:367:40
    |
367 |             export.output_as_json_v1_5(&mut writer)?;
    |                    ------------------- ^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `OutputWriter<'_>`
    |                    |
    |                    required by a bound introduced by this call
    |
note: required by a bound in `cyclonedx_bom::models::bom::Bom::output_as_json_v1_5`
   --> /Users/thomasschafer/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/cyclonedx-bom-0.8.0/src/models/bom.rs:315:35
    |
315 |     pub fn output_as_json_v1_5<W: std::io::Write>(
    |                                   ^^^^^^^^^^^^^^ required by this bound in `Bom::output_as_json_v1_5`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `uv` (lib) due to 1 previous error

I could implement Write for OutputWriter if you think it's worth it? (Or I could be missing something else, let me know!)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was fairly straightforward to implement Write for OutputWriter and I could then remove the write_fmt method so pushed that up, let me know what you think

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, I missed that this was our own OutputWriter type. I have no objection to doing this all through a Write impl., but @konstin or @zanieb might have context on why this was done with a explicit write_fmt implementation before 🙂

@thomasschafer thomasschafer force-pushed the sbom-export-support branch 3 times, most recently from 332140c to 8e701cc Compare October 31, 2025 23:40
@woodruffw woodruffw added enhancement New feature or improvement to existing functionality cli Related to the command line interface labels Nov 3, 2025
@@ -4660,3 +4660,3926 @@ fn export_lock_workspace_mismatch_with_frozen() -> Result<()> {

Ok(())
}

#[test]
fn cyclonedx_export_basic() -> Result<()> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud: these snapshots are pretty large, in part because anyio==3.7.0 has a nontrivial number of dependencies.

We definitely want to exercise the dependency paths here, but maybe we could pick a slimmer package to use for testcases here? Some candidates:

  • urllib3 has fewer dependencies (particularly when no extras are used)
  • cryptography has very few dependencies by default, but has extras we could use to exercise dependency cases. It has relatively large wheels, however.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli Related to the command line interface enhancement New feature or improvement to existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Software Bill of Materials (SBOM) output

3 participants