Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support cyclonedx 1.5 #5123

Merged
merged 1 commit into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cliv2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ require (
github.com/rs/zerolog v1.32.0
github.com/snyk/cli-extension-dep-graph v0.0.0-20230926124856-b0fdf1ee6f73
github.com/snyk/cli-extension-iac-rules v0.0.0-20230601153200-c572cfce46ce
github.com/snyk/cli-extension-sbom v0.0.0-20231123083311-52b1cecc1a7a
github.com/snyk/container-cli v0.0.0-20230920093251-fe865879a91f
github.com/snyk/cli-extension-sbom v0.0.0-20240314090036-46535b380426
github.com/snyk/container-cli v0.0.0-20240322120441-6d9b9482f9b1
github.com/snyk/go-application-framework v0.0.0-20240320144631-1935b2cb624e
github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65
github.com/snyk/snyk-iac-capture v0.6.5
Expand Down
8 changes: 4 additions & 4 deletions cliv2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -654,12 +654,12 @@ github.com/snyk/cli-extension-dep-graph v0.0.0-20230926124856-b0fdf1ee6f73 h1:rw
github.com/snyk/cli-extension-dep-graph v0.0.0-20230926124856-b0fdf1ee6f73/go.mod h1:QF3v8HBpOpyudYNCuR8LqfULutO76c91sBdLzD+pBJU=
github.com/snyk/cli-extension-iac-rules v0.0.0-20230601153200-c572cfce46ce h1:WchwuyPX4mEr7tFCGD6EsjwTDipFWfLxs4Wps6KB3b4=
github.com/snyk/cli-extension-iac-rules v0.0.0-20230601153200-c572cfce46ce/go.mod h1:5/IYYTgf32pST7St4GhS3KNz32WE17Ys+Hdb5Pqxex0=
github.com/snyk/cli-extension-sbom v0.0.0-20231123083311-52b1cecc1a7a h1:oRrk9bvMXdAVhRt84Y8G06+Op7fYQYrRuslngG9BPZk=
github.com/snyk/cli-extension-sbom v0.0.0-20231123083311-52b1cecc1a7a/go.mod h1:IwRGWjRuNkY08O7NJb7u3JuQkroEB8Qi1MlASpZVu1Q=
github.com/snyk/cli-extension-sbom v0.0.0-20240314090036-46535b380426 h1:MXbip3nmiOym3/9bNWlPISVOAEAAz4FDcPvqOMPcCc4=
github.com/snyk/cli-extension-sbom v0.0.0-20240314090036-46535b380426/go.mod h1:g2VgZU79btvZrAP3oHZGv3tHD9POVOx5a3DY894rS4w=
github.com/snyk/code-client-go v0.3.1 h1:jCYBRJJ/qVlPRqJONwmwpMCMe7s/lulbJQE6KUe2DW0=
github.com/snyk/code-client-go v0.3.1/go.mod h1:D+cfqDbuZE1S106bY3Tr+ZXLb9BR16kKBtvlf0xdyNA=
github.com/snyk/container-cli v0.0.0-20230920093251-fe865879a91f h1:ghajT5PEiLP8XNFIdc7Yn4Th74RH/9Q++dDOp6Cb9eo=
github.com/snyk/container-cli v0.0.0-20230920093251-fe865879a91f/go.mod h1:38w+dcAQp9eG3P5t2eNS9eG0reut10AeJjLv5lJ5lpM=
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/go-application-framework v0.0.0-20240320144631-1935b2cb624e h1:Cu5BIVoy+s6/oiOd0OAJS02AuJ+jM8FF2RBZ+YoZs80=
github.com/snyk/go-application-framework v0.0.0-20240320144631-1935b2cb624e/go.mod h1:Yz/qxFyfhf0xbA+z8Vzr5IM9IDG+BS+2PiGaP1yAsEw=
github.com/snyk/go-httpauth v0.0.0-20240307114523-1f5ea3f55c65 h1:CEQuYv0Go6MEyRCD3YjLYM2u3Oxkx8GpCpFBd4rUTUk=
Expand Down
68 changes: 46 additions & 22 deletions test/acceptance/fake-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -553,33 +553,57 @@ export const fakeServer = (basePath: string, snykToken: string): FakeServer => {
(req, res) => {
const depGraph: void | Record<string, any> = req.body.depGraph;
const depGraphs: void | Record<string, any>[] = req.body.depGraphs;
const tools: void | Record<string, any>[] = req.body.tools;
let bom: Record<string, unknown> = { bomFormat: 'CycloneDX' };
const tools = req.body.tools || [];
let name = '';
let components;

let bom: Record<string, any> = { bomFormat: 'CycloneDX' };

if (Array.isArray(depGraphs) && req.body.subject) {
// Return a fixture of an all-projects SBOM.
bom = {
...bom,
metadata: { component: { name: req.body.subject.name } },
components: depGraphs
.flatMap(({ pkgs }) => pkgs)
.map(({ info: { name } }) => ({ name })),
};
}

if (depGraph) {
bom = {
...bom,
metadata: { component: { name: depGraph.pkgs[0]?.info.name } },
components: depGraph.pkgs.map(({ info: { name } }) => ({ name })),
};
name = req.body.subject.name;
components = depGraphs
.flatMap(({ pkgs }) => pkgs)
.map(({ info: { name } }) => ({ name }));
} else if (depGraph) {
name = depGraph.pkgs[0]?.info.name;
components = depGraph.pkgs.map(({ info: { name } }) => ({ name }));
}

if (Array.isArray(tools)) {
bom.metadata = {
...(bom.metadata as any),
tools: [...tools, { name: 'fake-server' }],
};
switch (req.query.format) {
case 'spdx2.3+json':
bom = {
spdxVersion: 'SPDX-2.3',
name,
packages: components,
creators: [...tools, 'fake-server'],
};
break;
case 'cyclonedx1.4+json':
bom = {
specVersion: '1.4',
$schema: 'http://cyclonedx.org/schema/bom-1.4.schema.json',
components,
metadata: {
component: { name },
tools: [...tools, { name: 'fake-server', version: '42' }],
},
};
break;
case 'cyclonedx1.5+json':
bom = {
specVersion: '1.5',
$schema: 'http://cyclonedx.org/schema/bom-1.5.schema.json',
components,
metadata: {
component: { name },
tools: {
components: [...tools, { name: 'fake-server' }],
services: [{ name: 'fake-server', version: '42' }],
},
},
};
break;
}

res.status(200).send(bom);
Expand Down
59 changes: 57 additions & 2 deletions test/jest/acceptance/snyk-container/container.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ DepGraph end`,
});
});

it('should print sbom for image', async () => {
it('should print sbom for image - spdx', async () => {
const {
code,
stdout,
Expand All @@ -201,7 +201,62 @@ DepGraph end`,
expect(() => {
sbom = JSON.parse(stdout);
}).not.toThrow();
expect(sbom.metadata.component.name).toEqual('gcr.io/distroless/static');
expect(sbom.name).toEqual('gcr.io/distroless/static');
expect(sbom.spdxVersion).toEqual('SPDX-2.3');
expect(sbom.packages).toHaveLength(
TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH.pkgs.length,
);
});

it('should print sbom for image - cyclonedx 1.4', async () => {
const {
code,
stdout,
stderr,
} = await runSnykCLIWithDebug(
`container sbom --org=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format=cyclonedx1.4+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.4');
expect(sbom['$schema']).toEqual(
'http://cyclonedx.org/schema/bom-1.4.schema.json',
);

expect(sbom.components).toHaveLength(
TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH.pkgs.length,
);
});

it('should print sbom for image - cyclonedx 1.5', async () => {
const {
code,
stdout,
stderr,
} = await runSnykCLIWithDebug(
`container sbom --org=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format=cyclonedx1.5+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.5');
expect(sbom['$schema']).toEqual(
'http://cyclonedx.org/schema/bom-1.5.schema.json',
);

expect(sbom.components).toHaveLength(
TEST_DISTROLESS_STATIC_IMAGE_DEPGRAPH.pkgs.length,
);
Expand Down
68 changes: 65 additions & 3 deletions test/jest/acceptance/snyk-sbom/sbom.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('snyk sbom (mocked server only)', () => {
});
});

test('`sbom` generates an SBOM for a single project', async () => {
test('`sbom` generates an SBOM for a single project - CycloneDX 1.4', async () => {
const project = await createProjectFromWorkspace('npm-package');

const { code, stdout } = await runSnykCLI(
Expand All @@ -45,17 +45,22 @@ describe('snyk sbom (mocked server only)', () => {
env,
},
);
let bom;
let bom: any;

expect(code).toEqual(0);
expect(() => {
bom = JSON.parse(stdout);
}).not.toThrow();

expect(bom.specVersion).toEqual('1.4');
expect(bom['$schema']).toEqual(
'http://cyclonedx.org/schema/bom-1.4.schema.json',
);
expect(bom.metadata.component.name).toEqual('npm-package');
expect(bom.components).toHaveLength(3);
});

test('`sbom` includes a tool name in the document', async () => {
test('`sbom` includes a tool name in the document - CycloneDX 1.4', async () => {
const project = await createProjectFromWorkspace('npm-package');

const { stdout } = await runSnykCLI(
Expand All @@ -77,4 +82,61 @@ describe('snyk sbom (mocked server only)', () => {
]),
);
});

test('`sbom` generates an SBOM for a single project - CycloneDX 1.5', async () => {
const project = await createProjectFromWorkspace('npm-package');

const { code, stdout } = await runSnykCLI(
`sbom --org aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format cyclonedx1.5+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.5');
expect(bom['$schema']).toEqual(
'http://cyclonedx.org/schema/bom-1.5.schema.json',
);
expect(bom.metadata.component.name).toEqual('npm-package');
expect(bom.components).toHaveLength(3);
});

test('`sbom` includes a tool name in the document - CycloneDX 1.5', async () => {
PeterSchafer marked this conversation as resolved.
Show resolved Hide resolved
const project = await createProjectFromWorkspace('npm-package');

const { stdout } = await runSnykCLI(
`sbom --org aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format cyclonedx1.5+json --debug`,
{
cwd: project.path(),
env,
},
);
const bom = JSON.parse(stdout);

expect(bom.metadata.tools.components).toEqual(
expect.arrayContaining([
{
vendor: 'Snyk',
name: 'snyk-cli',
version: expect.any(String),
},
]),
);

expect(bom.metadata.tools.services).toEqual(
expect.arrayContaining([
{
name: 'fake-server',
version: expect.any(String),
},
]),
);
});
});
Loading