Extracting dependency info for SBOM + licensing

We are building both compiled libraries (FFI) and executables for distribution. As part of this process, we need a simple and reliable way to to output target dependency information in a machine readable format:

  1. So that we can build a custom SBOM
    a) What are the version(s) of our dependencies
    b) What features were enabled during build, etc.

  2. So that we can cross-check this list against a dependency/license allow-list. We're not looking for anything fancy in terms of license compatibility. We have the allow-list for that.

I've played with various things in the ecosystem and I can't seem to find anything that works well or is guaranteed to keep working in the future. Here are a few options I've explored:

== cargo metadata ==

This seems to be what everyone else uses under the hood, but it has the limitation that it resolves everything in the workspace collectively, whereas I only want a dependency list for 1) a single target and 2) for the features enabled on that target

https://github.com/rust-lang/cargo/issues/7754

== cargo license ==

This was working well for a time, until we introduced features. Some of our customers want a build that excludes certain features because of licensing/footprint issues.

== cargo tree ==

Cargo tree actually does exactly what we need:

cargo tree -e normal -p target --no-default-features

The problem is the output isn't in a machine readable format! JSON would be ideal.

== parsing cargo build ==

You can tell cargo to output build events in JSON with:

cargo build -p target --message-format json > build.log

And then use structs defined in cargo-metadata to read them. So we could do our builds outputting this log, and then look back at the log. This might work for a time if we're willing to parse the PackageId string, but the representation isn't guaranteed to be stable:

Question

Is there some easier way of producing what I need? Am I missing something or is this a gap in the ecosystem ATM?

Do you mean target triple? For this you can use --filter-platform. Or do you mean executable? For that I'm not sure how to do this with cargo metadata.

There is also

which embeds an SBOM in your executable. It does use cargo metadata too, so it will hit the same issues as you. cc @Shnatsel

1 Like

Hi @bjorn3. I meant to say a single library or executable crate within a workspace.

Thanks for the pointer to cargo-auditable. Awesome concept.

ATM, I need to produce a separate document of what's in the build that I can then ingest and run against our library/license allow-list.

I have hit limitation too when writing cargo auditable. It turned out that you can in fact get it for a single executable in a workspace by setting your executable as the callback via the RUSTC_WORKSPACE_WRAPPER environment variable, which is what cargo auditable does now: all the Cargo subcommand does is set that variable, and all the real work is happening in the rustc wrapper. Both are in the same executable, and we decide which one to use based on the argument passed by Cargo.

Hope this helps.

Also, cargo-metadata always resolves features at the workspace level · Issue #7754 · rust-lang/cargo · GitHub you linked is concerning and may impact cargo auditable. Thanks for bringing that up.