Skip to content

Commit

Permalink
Merge pull request #169 from cp-andrew-lindesay/extra-snyk-cli-commands
Browse files Browse the repository at this point in the history
feat: implement new commands `code-test` and `container-test` + new c…
  • Loading branch information
michelkaporin authored Nov 16, 2022
2 parents d8bcb3a + 97bdf7a commit 3737e7e
Show file tree
Hide file tree
Showing 22 changed files with 400 additions and 27 deletions.
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,19 @@ Ensure that your code adheres to the included `.eslintrc` config by running `npm
*Important:* when fixing a bug, please commit a **failing test** first so that Travis CI (or I can) can show the code failing. Once that commit is in place, then commit the bug fix, so that we can test *before* and *after*.

Remember that you're developing for multiple platforms and versions of node, so if the tests pass on your Mac or Linux or Windows machine, it *may* not pass elsewhere.

## Local Build

During the build of this plugin, a number of tests will run in the host platform's environment. To get these tests to run from a developer setting requires some environment variables to be set;

### `SNYK_DOWNLOAD_DESTINATION`

This value is a file path where the test is able to download the Snyk binary to for use in the test. An example might be `downloads/snyk`.

### `SNYK_TEST_TOKEN`

A Snyk token that can be used in the execution of the test. You can obtain a token for your Snyk user under the "Account Settings" page in the Snyk Web UI.

### `SNYK_CLI_EXECUTABLE`

The path where the Snyk tool would ordinarily be found on the system. An example would be `/usr/local/bin/snyk`.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ officially maintained by [Snyk](https://snyk.io).

## Goals

### `code-test` (experimental)

Default phase: `test`

Performs a static-analysis of your project's source code and provides a list of
vulnerabilities if any are found.

### `container-test` (experimental)

Default phase: `install`

Performs analysis of the layers of a container image. The tag of the image to
be scanned should be provided as an argument;

```xml
<!-- Example of specifying the tag of the image to scan -->
<configuration>
<args>
<arg>--print-deps</arg>
<arg>nginx:1.9.5</arg>
</args>
</configuration>
```

### `test`

Default Phase: `test`
Expand Down Expand Up @@ -94,6 +118,15 @@ Skip this execution entirely.

When running `mvn`, you can also use `-Dsnyk.skip` to enable this behavior.

### `failOnIssues` \[boolean\]

Default: `true`

When set to `true` then, should the Snyk CLI tool indicate that action is
required to remedy a security issue, the Maven build will be considered
failed. When set to `false` the build will continue even if action is
required.

### `args` \[array\<string\>\]

This plugin uses [Snyk CLI](https://github.com/snyk/snyk) so you can pass any
Expand Down
3 changes: 3 additions & 0 deletions src/it/test-code-test/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://maven.apache.org/plugins/maven-invoker-plugin/integration-test-mojo.html#invokerPropertiesFile
invoker.goals=test
invoker.buildResult=failure
48 changes: 48 additions & 0 deletions src/it/test-code-test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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>

<groupId>io.snyk.it</groupId>
<artifactId>test-code-test</artifactId>
<version>1.0-SNAPSHOT</version>

<build>
<plugins>

<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>code-test</goal>
</goals>
</execution>
</executions>
<configuration>
<cli>
<executable>${env.SNYK_CLI_EXECUTABLE}</executable>
</cli>
<args>
<arg>--print-deps</arg>
</args>
<apiToken>${env.SNYK_TEST_TOKEN}</apiToken>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

</plugins>
</build>
</project>
26 changes: 26 additions & 0 deletions src/it/test-code-test/src/main/java/com/example/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.example;

import java.sql.SQLException;

public class Application {

/**
* <p>This code will allow the caller to provide an argument to the application which
* finds its way into a SQL statement. For example <code>';DROP TABLE product;SELECT '</code>
* could be passed in and it would give an opportunity to attack the system at the database
* level.</p>
*/

public static void main(String[] args) {
VulnerableQueryHelper vulnerableQueryHelper = new VulnerableQueryHelper(
null // not relevant for the purpose of analysis
);

try {
System.out.println("" + vulnerableQueryHelper.countProductOrders(args[1]));
} catch (SQLException se) {
throw new Error(se);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.example;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class VulnerableQueryHelper {

private final DataSource dataSource;

public VulnerableQueryHelper(DataSource dataSource) {
this.dataSource = dataSource;
}

public int countProductOrders(String productCode) throws SQLException {
try (Connection connection = dataSource.getConnection()) {
return countProductOrders(connection, productCode);
}
}

/**
* <p>In this method, the argument provided is put directly into the SQL which would
* allow an attacker to be able to execute arbitrary logic in the database.</p>
*/

public int countProductOrders(Connection connection, String productCode) throws SQLException {
String sql = "SELECT COUNT(id)\n"
+ "FROM order o JOIN product p ON o.product_id = o.id\n"
+ "WHERE p.code = '" + productCode + "'";

try (PreparedStatement statement = connection.prepareStatement(sql)) {
try (ResultSet resultSet = statement.executeQuery()) {
if (!resultSet.next()) {
throw new IllegalStateException("expected a row to be returned from the sql query");
}
return resultSet.getInt(1);
}
}
}

}
9 changes: 9 additions & 0 deletions src/it/test-code-test/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import org.codehaus.plexus.util.FileUtils;

String log = FileUtils.fileRead(new File(basedir, "build.log"))

if (!log.contains("[High] SQL Injection")) {
throw new Exception("no sql injection issue found")
}

return true;
3 changes: 3 additions & 0 deletions src/it/test-container-test/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://maven.apache.org/plugins/maven-invoker-plugin/integration-test-mojo.html#invokerPropertiesFile
invoker.goals=install
invoker.buildResult=failure
40 changes: 40 additions & 0 deletions src/it/test-container-test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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>

<groupId>io.snyk.it</groupId>
<artifactId>test-code-test</artifactId>
<version>1.0-SNAPSHOT</version>

<build>
<plugins>

<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>container-test</goal>
</goals>
</execution>
</executions>
<configuration>
<cli>
<executable>${env.SNYK_CLI_EXECUTABLE}</executable>
</cli>
<args>
<arg>--print-deps</arg>
<arg>--platform=linux/amd64</arg>
<arg>nginx:1.21.1</arg>
</args>
<apiToken>${env.SNYK_TEST_TOKEN}</apiToken>
</configuration>
</plugin>

</plugins>
</build>
</project>
13 changes: 13 additions & 0 deletions src/it/test-container-test/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import org.codehaus.plexus.util.FileUtils;

String log = FileUtils.fileRead(new File(basedir, "build.log"))

if (!log.contains("Medium severity vulnerability found in tiff/libtiff5")) {
throw new Exception("Expected medium vulnerability not found")
}

if (!log.contains("Critical severity vulnerability found in zlib/zlib1g")) {
throw new Exception("Expected critical vulnerability not found")
}

return true
4 changes: 2 additions & 2 deletions src/it/test-multi-module-child/verify.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ if (!log.contains("child-module-2 ..................................... FAILURE"
throw new Exception("child-module-2 should have failed.");
}

if (!log.contains("introduced by io.snyk.it:[email protected] > axis:[email protected]")) {
throw new Exception("Could not find vulnerability in child-module-2.");
if (!log.contains("introduced by axis:[email protected]")) {
throw new Exception("Could not find expected vulnerability in child-module-2.");
}

return true;
3 changes: 3 additions & 0 deletions src/it/test-not-fail-on-issues/invoker.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://maven.apache.org/plugins/maven-invoker-plugin/integration-test-mojo.html#invokerPropertiesFile
invoker.goals = install
invoker.buildResult = success
48 changes: 48 additions & 0 deletions src/it/test-not-fail-on-issues/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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>

<groupId>io.snyk.it</groupId>
<artifactId>test-not-fail-on-issues</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<!-- this contains a known vulnerability -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.5</version>
</dependency>
</dependencies>

<build>
<plugins>

<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<cli>
<executable>${env.SNYK_CLI_EXECUTABLE}</executable>
</cli>
<args>
<arg>--print-deps</arg>
</args>
<apiToken>${env.SNYK_TEST_TOKEN}</apiToken>
<failOnIssues>false</failOnIssues>
</configuration>
</plugin>

</plugins>
</build>
</project>
9 changes: 9 additions & 0 deletions src/it/test-not-fail-on-issues/verify.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import org.codehaus.plexus.util.FileUtils;

String log = FileUtils.fileRead(new File(basedir, "build.log"))

if (!log.contains("introduced by org.postgresql:[email protected]")) {
throw new Exception("Vulnerability in dependency not found")
}

return true;
2 changes: 1 addition & 1 deletion src/it/test-with-specific-cli-version/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>

<groupId>io.snyk.it</groupId>
<artifactId>test-without-cli-executable</artifactId>
<artifactId>test-with-specific-cli-version</artifactId>
<version>1.0-SNAPSHOT</version>

<build>
Expand Down
15 changes: 10 additions & 5 deletions src/it/test-without-dependency/verify.groovy
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import org.codehaus.plexus.util.FileUtils;

String log = FileUtils.fileRead(new File(basedir, "build.log"));
String log = FileUtils.fileRead(new File(basedir, "build.log"))
String snykCliExecutable = System.getenv("SNYK_CLI_EXECUTABLE")

if (snykCliExecutable == null || snykCliExecutable.isEmpty()) {
throw new Exception("the environment variable `SNYK_CLI_EXECUTABLE` is not defined")
}

if (!log.contains("Snyk Executable Path: " + System.getenv("SNYK_CLI_EXECUTABLE"))) {
throw new Exception("snyk executable path log line not found.");
throw new Exception("snyk executable path log line not found.")
}

if (!(log =~ /Snyk CLI Version:\s+\d+\.\d+\.\d+/)) {
throw new Exception("snyk version log line not found");
throw new Exception("snyk version log line not found")
}

if (!log.contains("for known issues, no vulnerable paths found.")) {
throw new Exception("`snyk test` success output not found");
throw new Exception("`snyk test` success output not found")
}

return true;
return true
14 changes: 10 additions & 4 deletions src/main/java/io/snyk/snyk_maven_plugin/command/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

public enum Command {

CODE_TEST("code", "test"),
CONTAINER_TEST("container", "test"),
TEST("test"),
MONITOR("monitor"),
VERSION("version");

private final String commandName;
private final String[] commandParameters;

Command(String commandName) {
this.commandName = commandName;
Command(String... commandParameters) {
this.commandParameters = commandParameters;
}

public String[] commandParameters() {
return commandParameters;
}

public String commandName() {
return commandName;
return String.join(" ", commandParameters());
}

}
Loading

0 comments on commit 3737e7e

Please sign in to comment.