Skip to content

Commit

Permalink
feat: sbom maven & gradle extra args support (#4819)
Browse files Browse the repository at this point in the history
Add support for the following args for the snyk sbom command:

maven:
--maven-aggregate-project
--scan-unmanaged --file=<JAR_FILE_NAME>
--scan-all-unmanaged

gradle:
--sub-project=<NAME>, --gradle-sub-project=<NAME>
--all-sub-projects
--configuration-matching=<CONFIGURATION_REGEX>
--configuration-attributes=<ATTRIBUTE>[,<ATTRIBUTE>]...
--init-script=<FILE>

Co-authored-by: Krzysztof <krzysztof.lesniewski@snyk.io>
  • Loading branch information
danlucian and klesniewski authored Sep 4, 2023
1 parent ff6575e commit 3ebe046
Show file tree
Hide file tree
Showing 17 changed files with 390 additions and 6 deletions.
4 changes: 2 additions & 2 deletions cliv2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ require (
github.com/google/uuid v1.3.1
github.com/pkg/errors v0.9.1
github.com/rs/zerolog v1.30.0
github.com/snyk/cli-extension-dep-graph v0.0.0-20230821114325-956f460c443c
github.com/snyk/cli-extension-dep-graph v0.0.0-20230831101913-402a467e32e7
github.com/snyk/cli-extension-iac-rules v0.0.0-20230601153200-c572cfce46ce
github.com/snyk/cli-extension-sbom v0.0.0-20230608154310-6573cedca977
github.com/snyk/cli-extension-sbom v0.0.0-20230831113416-7ffac8738181
github.com/snyk/go-application-framework v0.0.0-20230825084328-b839e0e50201
github.com/snyk/go-httpauth v0.0.0-20230726132335-d454674305a7
github.com/snyk/snyk-iac-capture v0.6.0
Expand Down
8 changes: 4 additions & 4 deletions cliv2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,12 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/snyk/cli-extension-dep-graph v0.0.0-20230821114325-956f460c443c h1:T9A/nUHxfxVrLWnlDg//FXa1Moj7gFJJexbPhHP5Wzc=
github.com/snyk/cli-extension-dep-graph v0.0.0-20230821114325-956f460c443c/go.mod h1:QF3v8HBpOpyudYNCuR8LqfULutO76c91sBdLzD+pBJU=
github.com/snyk/cli-extension-dep-graph v0.0.0-20230831101913-402a467e32e7 h1:V5b1Yz4Qjufs14bFoYBH6BRtfzTTCHeW32rV/9TiUY8=
github.com/snyk/cli-extension-dep-graph v0.0.0-20230831101913-402a467e32e7/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-20230608154310-6573cedca977 h1:kW8XGQ3hseTP6WbGrO4Q6ssqGejT02hleNzxfWga72E=
github.com/snyk/cli-extension-sbom v0.0.0-20230608154310-6573cedca977/go.mod h1:O/cjwCbKhJQWyXHPmNbZ7ToQKnhyw0VUp1Qhim3WEcw=
github.com/snyk/cli-extension-sbom v0.0.0-20230831113416-7ffac8738181 h1:BMiPwr4/sD71Jfrvorgy+L2E7PCkbT36c4wo2N+BKPg=
github.com/snyk/cli-extension-sbom v0.0.0-20230831113416-7ffac8738181/go.mod h1:O/cjwCbKhJQWyXHPmNbZ7ToQKnhyw0VUp1Qhim3WEcw=
github.com/snyk/go-application-framework v0.0.0-20230825084328-b839e0e50201 h1:5oHKA6Zs/c2oJ6MEznPn4grAJyedzltm9ms3o9ojU0Y=
github.com/snyk/go-application-framework v0.0.0-20230825084328-b839e0e50201/go.mod h1:Aun65T/AmzxjZe9jZZBqia6RHwoS7oq8QB2UfQIcPjU=
github.com/snyk/go-httpauth v0.0.0-20230726132335-d454674305a7 h1:m8C34vcouY2vEvow2gV/uAZ0LKiV7vhwC5HI15nUDX4=
Expand Down
30 changes: 30 additions & 0 deletions test/fixtures/gradle-configurations/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
plugins {
id 'java-library'
}

group = 'com.example'
version = '1.0'

repositories {
mavenCentral()
}

def testAttribute = Attribute.of('test.snykattr', String)

dependencies.attributesSchema {
attribute(testAttribute)
}

configurations {
api {
attributes {
attribute(testAttribute, 'api')
}
}
}

dependencies {
api 'org.jooq:jooq:3.18.6'
implementation 'com.google.guava:guava:23.0'
testImplementation 'junit:junit:4.+'
}
7 changes: 7 additions & 0 deletions test/fixtures/gradle-configurations/test-init.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
allprojects {
plugins.withType(JavaPlugin) {
dependencies {
implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
}
}
}
15 changes: 15 additions & 0 deletions test/fixtures/gradle-multi-project/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id 'java'
}

group = 'com.example'
version = '1.0'

repositories {
mavenCentral()
}

dependencies {
implementation project(':lib')
implementation 'com.fasterxml.jackson.core:jackson-core:2.15.2'
}
Empty file.
16 changes: 16 additions & 0 deletions test/fixtures/gradle-multi-project/lib/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id 'java-library'
}

group = 'com.example'
version = '1.0'

repositories {
mavenCentral()
}

dependencies {
api 'org.jooq:jooq:3.18.6'
implementation 'com.google.guava:guava:23.0'
testImplementation 'junit:junit:4.+'
}
3 changes: 3 additions & 0 deletions test/fixtures/gradle-multi-project/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rootProject.name = 'example-multi-project'
include 'app'
include 'lib'
29 changes: 29 additions & 0 deletions test/fixtures/maven-aggregate-project/core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent-project</artifactId>
<groupId>io.snyk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

<groupId>io.snyk</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>

<name>core</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
</dependencies>
</project>
21 changes: 21 additions & 0 deletions test/fixtures/maven-aggregate-project/extra/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent-project</artifactId>
<groupId>io.snyk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

<groupId>io.snyk</groupId>
<artifactId>extra</artifactId>
<version>1.0-SNAPSHOT</version>

<name>extra</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
23 changes: 23 additions & 0 deletions test/fixtures/maven-aggregate-project/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>io.snyk</groupId>
<artifactId>parent-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>parent-project</name>

<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<modules>
<module>service</module>
<module>core</module>
<module>extra</module>
</modules>
</project>
21 changes: 21 additions & 0 deletions test/fixtures/maven-aggregate-project/service/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>parent-project</artifactId>
<groupId>io.snyk</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

<groupId>io.snyk</groupId>
<artifactId>service</artifactId>
<version>1.0-SNAPSHOT</version>

<name>service</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Binary file added test/fixtures/maven-jars/keycloak-core-5.0.0.jar
Binary file not shown.
Binary file added test/fixtures/maven-jars/tomcat-http11-4.1.34.jar
Binary file not shown.
31 changes: 31 additions & 0 deletions test/jest/acceptance/snyk-sbom/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createProjectFromFixture } from '../../util/createProject';
import { runSnykCLI } from '../../util/runSnykCLI';

export async function runSnykSbomCliCycloneDxJsonForFixture(
fixtureName: string,
options: string,
env: Record<string, string>,
): Promise<any> {
const project = await createProjectFromFixture(fixtureName);

const { code, stdout, stderr } = await runSnykCLI(
`sbom --org=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee --format=cyclonedx1.4+json --debug ${options}`,
{
cwd: project.path(),
env,
},
);

if (code) {
console.log(stderr);
}

expect(code).toEqual(0);

let sbom;
expect(() => {
sbom = JSON.parse(stdout);
}).not.toThrow();

return sbom;
}
119 changes: 119 additions & 0 deletions test/jest/acceptance/snyk-sbom/gradle-options.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { fakeServer } from '../../../acceptance/fake-server';
import { runSnykSbomCliCycloneDxJsonForFixture } from './common';

jest.setTimeout(1000 * 60 * 5);

describe('snyk sbom: gradle options (mocked server only)', () => {
let server;
let env: Record<string, string>;

beforeAll((done) => {
const port = process.env.PORT || process.env.SNYK_PORT || '58584';
const baseApi = '/api/v1';
env = {
...process.env,
SNYK_API: 'http://localhost:' + port + baseApi,
SNYK_HOST: 'http://localhost:' + port,
SNYK_TOKEN: '123456789',
SNYK_DISABLE_ANALYTICS: '1',
};
server = fakeServer(baseApi, env.SNYK_TOKEN);
server.listen(port, () => {
done();
});
});

afterEach(() => {
jest.resetAllMocks();
server.restore();
});

afterAll((done) => {
server.close(() => {
done();
});
});

test('`sbom --sub-project=<NAME>` generates an SBOM for selected sub-project', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-multi-project',
'--sub-project=lib',
env,
);

expect(sbom.metadata.component.name).toEqual('gradle-multi-project/lib');
expect(sbom.components.length).toBeGreaterThan(1);
});

test('`sbom --gradle-sub-project=<NAME>` generates an SBOM for selected sub-project', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-multi-project',
'--gradle-sub-project=lib',
env,
);

expect(sbom.metadata.component.name).toEqual('gradle-multi-project/lib');
expect(sbom.components.length).toBeGreaterThan(1);
});

test('`sbom --all-sub-projects` generates an SBOM for all sub-projects', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-multi-project',
'--all-sub-projects',
env,
);

expect(sbom.metadata.component.name).toEqual('gradle-multi-project');
const listedComponentNames = sbom.components.map((it) => it.name);
expect(listedComponentNames).toContain('gradle-multi-project');
expect(listedComponentNames).toContain('gradle-multi-project/lib');
expect(listedComponentNames).toContain('gradle-multi-project/app');
});

test('`sbom --configuration-matching=<CONFIGURATION_REGEX>` generates an SBOM only for matching configuration', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-configurations',
'--configuration-matching=^runtimeClasspath$',
env,
);

const listedComponentNames = sbom.components.map((it) => it.name);
expect(listedComponentNames).toContain('org.jooq:jooq');
expect(listedComponentNames).toContain('com.google.guava:guava');
expect(listedComponentNames).not.toContain('junit:junit');
});

test('`sbom --configuration-attributes=<ATTRIBUTE>[,<ATTRIBUTE>]...` generates an SBOM only for matching variant', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-configurations',
'--configuration-attributes=snykattr:api',
env,
);

// I failed to prepare an example where this works,
// so I will just test here that CLI executes successfully,
// meaning the command does not fail due to unrecognized config.
// To prepare the example I tried to set attribute on a configuration and filter by that,
// but I was always getting a full list of dependencies instead of a subset.
// The same I was getting when trying `snyk test` command.
// I was adding attributes as documented here: https://docs.gradle.org/current/userguide/variant_attributes.html
// I also tried using existing attribute `usage:java-api`, but also no luck.
expect(sbom.metadata.component.name).toEqual('gradle-configurations');
// const listedComponentNames = sbom.components.map((it) => it.name);
// expect(listedComponentNames).toContain('org.jooq:jooq');
// expect(listedComponentNames).not.toContain('com.google.guava:guava');
});

test('`sbom --init-script=<FILE>` applies given init script', async () => {
const sbom = await runSnykSbomCliCycloneDxJsonForFixture(
'gradle-configurations',
'--init-script=test-init.gradle',
env,
);

const listedComponentNames = sbom.components.map((it) => it.name);
expect(listedComponentNames).toContain(
'org.apache.logging.log4j:log4j-api',
); // Dep added by init script
});
});
Loading

0 comments on commit 3ebe046

Please sign in to comment.