Skip to content

feat: [CMPA-603] Add npm support for SBOM component metadata being FF#6950

Open
calhar-snyk wants to merge 1 commit into
mainfrom
feat/CMPA-603-add-npm-support-for-sbom-component-metadata
Open

feat: [CMPA-603] Add npm support for SBOM component metadata being FF#6950
calhar-snyk wants to merge 1 commit into
mainfrom
feat/CMPA-603-add-npm-support-for-sbom-component-metadata

Conversation

@calhar-snyk

@calhar-snyk calhar-snyk commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Pull Request Submission Checklist

  • Follows CONTRIBUTING guidelines
  • Commit messages are release-note ready, emphasizing what was changed, not how.
  • Includes detailed description of changes
  • Contains risk assessment (Low | Medium | High)
  • Highlights breaking API changes (if applicable) — none
  • Links to automated tests covering new functionality
  • Includes manual testing instructions (if necessary)
  • Updates relevant GitBook documentation (PR link: ___) — n/a, internal/undocumented flag
  • Includes product update to be announced in the next stable release notes — n/a, no user-facing change

What does this PR do?

Extends --include-component-metadata support to npm projects, following on from the Maven support added in #6948.

When the flag is set, the npm plugin now forwards it to snyk-nodejs-lockfile-parser, which reads the install-time integrity and resolved fields already recorded in the lockfile and surfaces them as hash:<algorithm> and distribution:url labels on the dep-graph nodes. The SBOM extension then uses these labels to populate component hashes and external distribution URLs in the CycloneDX output.

Concretely:

  • Forwards includeComponentMetadata through the legacy npm-lock-parser in both code paths — the v2/v3 dep-graph path (parseNpmLockV2Project) and the v1 depTree path (buildDepTreeFromFiles). For v1, the labels survive the downstream depTree→dep-graph conversion.
  • Adds includeComponentMetadata to the plugin Options type.
  • Bumps snyk-nodejs-lockfile-parser to 2.9.0, the version that emits the component-metadata labels.

The flag remains internal/undocumented and is gated by the feature-flag gateway — the same surface as the Maven precursor. Unlike Maven, no artifact resolution step is needed: the metadata already lives in the lockfile, so nothing has to be installed/resolved first.

Where should the reviewer start?

  • src/lib/plugins/nodejs-plugin/npm-lock-parser.ts — the two-line forwarding change (v1 and v2/v3 paths).
  • src/lib/plugins/types.ts — the new optional Options field.
  • test/jest/acceptance/snyk-test/npm-include-component-metadata.spec.ts — coverage across lockfile v1/v2/v3.

Note: npm intentionally stays on the in-tree legacy plugin here (the change just threads the flag through it).

How should this be manually tested?

Against an npm project with a package-lock.json (v1, v2, or v3):

snyk test --print-graph --include-component-metadata --file=package-lock.json

Dep-graph nodes should carry hash:<algorithm> and distribution:url labels. Re-running without --include-component-metadata should produce no such labels.

Automated coverage: test/jest/acceptance/snyk-test/npm-include-component-metadata.spec.ts exercises lockfile v1/v2/v3, each asserting the labels are present with the flag and absent without it.

The full snyk sbom flow can also be tested against the pre-prod API:

❯ ~/code/cli/binary-releases/snyk-macos-arm64 sbom --format=cyclonedx1.6+json | jq '.'
{
  "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "serialNumber": "urn:uuid:acd67741-5c1d-4c3e-8591-713b95281254",
  "version": 1,
  "metadata": {
    "timestamp": "2026-06-25T19:28:08Z",
    "tools": {
      "components": [
        {
          "type": "application",
          "author": "Snyk",
          "name": "snyk-cli",
          "version": "1.1306.0-dev.59984f8c87451bff7664b9b1598c599fc51f881f"
        }
      ],
      "services": [
        {
          "provider": {
            "name": "Snyk"
          },
          "name": "SBOM Export API",
          "version": "v1.131.0"
        }
      ]
    },
    "component": {
      "bom-ref": "1-npm-component-metadata-v1@1.0.0",
      "type": "application",
      "name": "npm-component-metadata-v1",
      "version": "1.0.0",
      "purl": "pkg:npm/npm-component-metadata-v1@1.0.0"
    }
  },
  "components": [
    {
      "bom-ref": "2-lodash@4.17.15",
      "type": "library",
      "name": "lodash",
      "version": "4.17.15",
      "hashes": [
        {
          "alg": "SHA-512",
          "content": "f3139c447bc28e7a1c752e5ca705d05d5ce69a1e5ee7eb1a136406a1e4266ca9914ba277550a693ce22dd0c9e613ee31959a2e9b2d063c6d03d0c54841b340d4"
        }
      ],
      "licenses": [
        {
          "expression": "MIT"
        }
      ],
      "purl": "pkg:npm/lodash@4.17.15",
      "externalReferences": [
        {
          "url": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
          "type": "distribution"
        }
      ],
      "properties": [
        {
          "name": "snyk:npm:scope",
          "value": "prod"
        }
      ]
    }
  ],
  "dependencies": [
    {
      "ref": "1-npm-component-metadata-v1@1.0.0",
      "dependsOn": [
        "2-lodash@4.17.15"
      ]
    },
    {
      "ref": "2-lodash@4.17.15"
    }
  ]
}

What's the product update that needs to be communicated to CLI users?

None. The feature is inert by default and gated behind an internal feature flag; there is no user-facing change unless explicitly enabled.

Risk assessment (Low | Medium | High)?

Low. The behaviour is gated behind an internal feature flag from the feature-flag gateway and is inert by default — clients see no change unless it is explicitly enabled for them. The only always-on change is the snyk-nodejs-lockfile-parser 2.9.0 bump, which adds the label-emitting code path without altering default output. npm scans continue to run through the existing legacy plugin.

Any background context you want to provide?

Precursor: #6948 (Maven component metadata + registering include-component-metadata as a recognised CLI argument forwarded to the plugins). This PR is the npm counterpart.

What are the relevant tickets?

@calhar-snyk calhar-snyk requested a review from a team as a code owner June 25, 2026 19:29
@snyk-io

snyk-io Bot commented Jun 25, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 59984f8 to 2fe53c6 Compare June 25, 2026 20:07
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 2fe53c6 to 5f7299b Compare June 25, 2026 22:14
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 5f7299b to 83d9058 Compare June 25, 2026 23:02
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 83d9058 to aff526d Compare June 26, 2026 08:10
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from aff526d to 35c9cf1 Compare June 26, 2026 08:19
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 35c9cf1 to 714ee6c Compare June 26, 2026 08:57
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 714ee6c to 98c902f Compare June 26, 2026 09:08
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk changed the base branch from main to feat/CMPA-604-add-support-for-sbom-component-metadata June 26, 2026 10:04
@calhar-snyk calhar-snyk changed the base branch from feat/CMPA-604-add-support-for-sbom-component-metadata to main June 26, 2026 10:05
@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 98c902f to fb0c5cb Compare June 26, 2026 13:56
@snyk-pr-review-bot

This comment has been minimized.

Comment thread src/lib/plugins/nodejs-plugin/npm-lock-parser.ts Outdated
Comment thread src/lib/plugins/types.ts
scanAllUnmanaged?: boolean;
showNpmScope?: boolean;
allProjects?: boolean;
includeComponentMetadata?: boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can this hold values such as null and undefined? Just a sanity question

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Effectively yes, in the vast majority of cases it won't be getting set.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

https://github.com/snyk/cli/pull/6948/changes#diff-eb8513f7e557af1081e96db6b6603ca292cc0c2bf383fb00c5f914431372cee3 is where we build the Options object that gets passed in to the plugin inspect method. So can be undefined

Comment on lines +48 to +54
it('does not attach the labels without the flag', async () => {
const project = await createProjectFromFixture(fixture);

const { code, stdout } = await runSnykCLI(
'test --print-graph --file=package-lock.json',
{ cwd: project.path() },
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

since this test is in a loop, I'm wondering if we should add some timeout here or if default is enough

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think the default timeout should be sufficient. The underlying behaviour is purely dependent on package-lock.json contents which are simple and small. This should be fast.

Comment on lines +56 to +59
expect(code).toEqual(0);
expect(stdout).toContain('DepGraph data:');
expect(labelKeys(stdout, 'hash:')).toHaveLength(0);
expect(labelKeys(stdout, 'distribution:url')).toHaveLength(0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

is there any chance that changes in the responses from runSnykCLI would cause these values to fail the test?
Maybe a better question is: are we testing what we want here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(maybe my comment is hard to understand the way I wrote - just wondering if this could be flaky)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think this should ever be flakey. The results here should not be dependent on external services as the underlying flows rely entirely on the package-lock.json contents

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from fb0c5cb to 94820da Compare June 26, 2026 15:26
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 94820da to 953a6dd Compare June 26, 2026 15:42
@snyk-pr-review-bot

This comment has been minimized.

@calhar-snyk calhar-snyk force-pushed the feat/CMPA-603-add-npm-support-for-sbom-component-metadata branch from 953a6dd to cc7531c Compare June 26, 2026 15:55
@snyk-pr-review-bot

Copy link
Copy Markdown

PR Reviewer Guide 🔍

🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Propagated Parameter Conflict 🟡 [minor]

The processWorkspacesProjects function now injects includeComponentMetadata into the settings object for all workspace managers (npm, pnpm, yarn). While the npm parser in this PR is updated to handle it, processPnpmWorkspaces is imported from snyk-nodejs-plugin. If that library version (2.1.0) does not explicitly handle or ignore this unknown key in its workspace processing logic, it may lead to runtime warnings or unexpected behavior in pnpm projects.

includeComponentMetadata: options['include-component-metadata'],
📚 Repository Context Analyzed

This review considered 15 relevant code sections from 7 files (average relevance: 0.85)

🤖 Repository instructions applied (from AGENTS.md)

@PeterSchafer PeterSchafer enabled auto-merge June 26, 2026 16:47

expect(code).toEqual(0);
const graphs = parseDepGraphs(stdout);
expect(graphs.map((g) => g.target).sort()).toEqual([root, ...members]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue: Seems like the windows path's didn't play nice for this assertion...
Image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is actually an interesting problem as we should internally use /, so there might be some more central problem than just the assertion.


expect(code).toEqual(0);
const graphs = parseDepGraphs(stdout);
expect(graphs.map((g) => g.target).sort()).toEqual([root, ...members]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants