CycloneDX / cyclonedx-node-yarn

Create CycloneDX Software Bill of Materials (SBOM) from Node.js Yarn projects.
Apache License 2.0
21 stars 5 forks source link

feat: account yarn's applied "compat" patches in SBOM results #192

Open gernot-h opened 4 weeks ago

gernot-h commented 4 weeks ago

Describe the bug feature

Yarn's builtin @yarnpkg/plugin-compat will automatically patch specific packages upon install. As far as I can see, this is not reflected in the created SBOM.

To Reproduce

# yarn add resolve
➤ YN0000: · Yarn 4.5.1
➤ YN0000: ┌ Resolution step
➤ YN0085: │ + resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d, function-bind@npm:1.1.2, hasown@npm:2.0.2, is-core-module@npm:2.15.1, path-parse@npm:1.0.7, resolve@npm:1.22.8, supports-preserve-symlinks-flag@npm:1.0.0
➤ YN0000: └ Completed
[...]
~# yarn info --name-only
├─ resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d
[...]
# yarn dlx -q @cyclonedx/yarn-plugin-cyclonedx        
[...]
  "components": [
    {
      "type": "library",
      "name": "resolve",
      "version": "1.22.8",
      "bom-ref": "resolve@patch:resolve@npm%3A1.22.8#optional!builtin<compat/resolve>::version=1.22.8&hash=c3c19d",
      "author": "James Halliday",
      "description": "resolve like require.resolve() on behalf of files asynchronously and synchronously",
      "purl": "pkg:npm/resolve@1.22.8?vcs_url=git%3A//github.com/browserify/resolve.git",
[...]

So the only trace of the patch you see in the SBOM is the bom-ref which should be opaque to BOM consumers, I guess.

Looking at the version and purl, you would assume that an unchanged resolve as available from NPM is in your system while in fact, this patch (readable version) was applied to it.

Expected behavior

To be honest, I'm unsure whether the information should be better provided using pedigree/patches, using something like 1.22.8&hash=c2c19d as version ... or if this would even justify to extend the purl specification...

Environment

Tested on:

gernot-h commented 4 weeks ago

By the way, you can also easily inspect the changes using Yarn's cacheFolder, you will find both unchanged and patched version of resolve there.

So if you would consider the cache content as "patched package", this would remind me to the situation we have with Linux distributions which also carry their own patches. For those, you just refer to "Debian package linux 6.1.112-1" in your BOM, and the consumers know how to resolve the corresponding patches. So perhaps just specifying some special version string and a purl qualifier would also be enough here?

jkowalleck commented 4 weeks ago

Thank you for the ticket, @gernot-h .

In general, this is not a bug but a lack of feature. Are you interested in working on a solution?


Here are some remarks:

So the only trace of the patch you see in the SBOM is the bom-ref which should be opaque to BOM consumers, I guess.

The bom-ref has no meaning, it is just an arbitrary string, unique in universe of the SBOM it ocurred in.

To be honest, I'm unsure whether the information should be better provided using pedigree/patches,

yes. such modifications are intended to be documented as "pedigree".

gernot-h commented 4 weeks ago

Thank you for the ticket, @gernot-h .

Thanks for the super-fast reply!!

In general, this is not a bug but a lack of feature. Are you interested in working on a solution?

Unfortunately, my JS/TS/Yarn skills are ... very limited, I wouldn't only need to dive into TypeScript, but I also have only a very rough understanding of the involved Yarn (patching) details so I wouldn't feel too comfortable shaping a best practice here.

To be honest, I'm unsure whether the information should be better provided using pedigree/patches,

yes. such modifications are intended to be documented as "pedigree".

As it seems that the hash string Yarn adds to the version number is nothing one could lookup somewhere, I agree that explicitely listing the patches in the BOM might be the best solution. While it sounds like adding a lot of complexity to the backend consuming the SBOM which needs to retrieve the involved patches...