From 1330fc2442e48865ea2e1b27a94cf665ff4b0416 Mon Sep 17 00:00:00 2001 From: Paul Rosca Date: Wed, 21 Aug 2024 13:14:05 +0300 Subject: [PATCH] feat: add CycloneDX 1.6 SBOM support --- cliv2/go.mod | 4 +-- cliv2/go.sum | 8 ++--- test/acceptance/fake-server.ts | 14 ++++++++ .../snyk-container/container.spec.ts | 32 +++++++++++++++++++ test/jest/acceptance/snyk-sbom/sbom.spec.ts | 25 +++++++++++++++ 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/cliv2/go.mod b/cliv2/go.mod index 321c22961d..3c49f8dd44 100644 --- a/cliv2/go.mod +++ b/cliv2/go.mod @@ -14,8 +14,8 @@ require ( github.com/rs/zerolog v1.33.0 github.com/snyk/cli-extension-dep-graph v0.0.0-20240426125928-8d56ac52821e github.com/snyk/cli-extension-iac-rules v0.0.0-20240422133948-ae17a4306672 - github.com/snyk/cli-extension-sbom v0.0.0-20240812130014-3f4e892f15ec - github.com/snyk/container-cli v0.0.0-20240322120441-6d9b9482f9b1 + github.com/snyk/cli-extension-sbom v0.0.0-20240820111700-68258cba52c7 + github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7 github.com/snyk/error-catalog-golang-public v0.0.0-20240809094525-c48d19c27edb github.com/snyk/go-application-framework v0.0.0-20240827093100-f92edcc104ec github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65 diff --git a/cliv2/go.sum b/cliv2/go.sum index 97f0d37cd3..7453dd9e29 100644 --- a/cliv2/go.sum +++ b/cliv2/go.sum @@ -739,12 +739,12 @@ github.com/snyk/cli-extension-dep-graph v0.0.0-20240426125928-8d56ac52821e h1:j1 github.com/snyk/cli-extension-dep-graph v0.0.0-20240426125928-8d56ac52821e/go.mod h1:QF3v8HBpOpyudYNCuR8LqfULutO76c91sBdLzD+pBJU= github.com/snyk/cli-extension-iac-rules v0.0.0-20240422133948-ae17a4306672 h1:AkLej8Lk//vFex1fiygSYFrQTUd0xP+GyRbsI+m2kwQ= github.com/snyk/cli-extension-iac-rules v0.0.0-20240422133948-ae17a4306672/go.mod h1:2vKTUsW73sVbDcyD19iNLfN0so2GSu9BE3k/fqG0mjA= -github.com/snyk/cli-extension-sbom v0.0.0-20240812130014-3f4e892f15ec h1:xkRPBjcqXwRnWCYCoybM9PO2J/hYn8txm/wzwnDImZg= -github.com/snyk/cli-extension-sbom v0.0.0-20240812130014-3f4e892f15ec/go.mod h1:5CaY1bgvJY/uoG/1plLOf8T8o9AkwoBIGvw34RfRLZw= +github.com/snyk/cli-extension-sbom v0.0.0-20240820111700-68258cba52c7 h1:+xhigV8lkriZ8riIg79Yx/sDpKZV9ihz2iAM0Xa8/V4= +github.com/snyk/cli-extension-sbom v0.0.0-20240820111700-68258cba52c7/go.mod h1:5CaY1bgvJY/uoG/1plLOf8T8o9AkwoBIGvw34RfRLZw= github.com/snyk/code-client-go v1.10.0 h1:t/hBINxj4lKvoo681uGhxHBpMued/j68p2sHbB9qbfo= github.com/snyk/code-client-go v1.10.0/go.mod h1:orU911flV1kJQOlxxx0InUQkAfpBrcERsb2olfnlI8s= -github.com/snyk/container-cli v0.0.0-20240322120441-6d9b9482f9b1 h1:9RKY9NdX5DrJAoVXDP0JiqrXT+4Nb9NH8pjEcA0NsLA= -github.com/snyk/container-cli v0.0.0-20240322120441-6d9b9482f9b1/go.mod h1:38w+dcAQp9eG3P5t2eNS9eG0reut10AeJjLv5lJ5lpM= +github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7 h1:Zn5BcV76oFAbJm5tDygU945lvoZ3yY8FoRFDC3YpwF8= +github.com/snyk/container-cli v0.0.0-20240821111304-7ca1c415a5d7/go.mod h1:38w+dcAQp9eG3P5t2eNS9eG0reut10AeJjLv5lJ5lpM= github.com/snyk/error-catalog-golang-public v0.0.0-20240809094525-c48d19c27edb h1:w9tJhpTFxWqAhLeraGsMExDjGK9x5Dwj1NRFwb+t+QE= github.com/snyk/error-catalog-golang-public v0.0.0-20240809094525-c48d19c27edb/go.mod h1:Ytttq7Pw4vOCu9NtRQaOeDU2dhBYUyNBe6kX4+nIIQ4= github.com/snyk/go-application-framework v0.0.0-20240827093100-f92edcc104ec h1:hqrcfg/+5vz/svcws6B42J/5AurXpYCpeRimMVkgJtY= diff --git a/test/acceptance/fake-server.ts b/test/acceptance/fake-server.ts index 5e61592f66..d2f87996f1 100644 --- a/test/acceptance/fake-server.ts +++ b/test/acceptance/fake-server.ts @@ -872,6 +872,20 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => { }, }; break; + case 'cyclonedx1.6+json': + bom = { + specVersion: '1.6', + $schema: 'http://cyclonedx.org/schema/bom-1.6.schema.json', + components, + metadata: { + component: { name }, + tools: { + components: [...tools, { name: 'fake-server' }], + services: [{ name: 'fake-server', version: '42' }], + }, + }, + }; + break; } res.status(200).send(bom); diff --git a/test/jest/acceptance/snyk-container/container.spec.ts b/test/jest/acceptance/snyk-container/container.spec.ts index 0ae1f4210d..6721021181 100644 --- a/test/jest/acceptance/snyk-container/container.spec.ts +++ b/test/jest/acceptance/snyk-container/container.spec.ts @@ -347,6 +347,38 @@ DepGraph end`, TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH.pkgs.length, ); }); + + it('should print sbom for image - cyclonedx 1.6', async () => { + // return a dep-graph fixture from `/test-dependencies` endpoint + server.setCustomResponse({ + result: { + issues: [], + issuesData: {}, + depGraphData: TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH, + }, + meta: { org: 'test-org', isPublic: false }, + }); + const { code, stdout, stderr } = await runSnykCLIWithDebug( + `container sbom --org=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format=cyclonedx1.6+json ${TEST_DISTROLESS_STATIC_IMAGE}`, + { env }, + ); + + let sbom: any; + assertCliExitCode(code, 0, stderr); + + expect(() => { + sbom = JSON.parse(stdout); + }).not.toThrow(); + + expect(sbom.specVersion).toEqual('1.6'); + expect(sbom['$schema']).toEqual( + 'http://cyclonedx.org/schema/bom-1.6.schema.json', + ); + + expect(sbom.components).toHaveLength( + TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH.pkgs.length, + ); + }); }); describe('snyk container monitor --json output', () => { diff --git a/test/jest/acceptance/snyk-sbom/sbom.spec.ts b/test/jest/acceptance/snyk-sbom/sbom.spec.ts index 23277dc87c..13814ef1d1 100644 --- a/test/jest/acceptance/snyk-sbom/sbom.spec.ts +++ b/test/jest/acceptance/snyk-sbom/sbom.spec.ts @@ -174,6 +174,31 @@ describe('snyk sbom (mocked server only)', () => { ); }); + test('`sbom` generates an SBOM for a single project - CycloneDX 1.6', async () => { + const project = await createProjectFromWorkspace('npm-package'); + + const { code, stdout } = await runSnykCLI( + `sbom --org aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format cyclonedx1.6+json --debug`, + { + cwd: project.path(), + env, + }, + ); + let bom: any; + + expect(code).toEqual(0); + expect(() => { + bom = JSON.parse(stdout); + }).not.toThrow(); + + expect(bom.specVersion).toEqual('1.6'); + expect(bom['$schema']).toEqual( + 'http://cyclonedx.org/schema/bom-1.6.schema.json', + ); + expect(bom.metadata.component.name).toEqual('npm-package'); + expect(bom.components).toHaveLength(3); + }); + test('`sbom` retains the exit error code of the underlying SCA process', async () => { const project = await createProject('empty');