Skip to content

Commit

Permalink
Add command timeout to dependency checker
Browse files Browse the repository at this point in the history
  • Loading branch information
sergioasantiago committed Nov 24, 2021
1 parent 15e92bc commit 4a38941
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 14 deletions.
Expand Up @@ -6,6 +6,7 @@
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.Builder;

@Builder
Expand All @@ -16,6 +17,7 @@ public class Command
private final File outputFile;
private final String commandline;
private final Path repositoryPath;
private final Integer commandTimeout;


public void run() throws IOException, InterruptedException, NonZeroExitCodeException
Expand All @@ -30,7 +32,7 @@ public void run() throws IOException, InterruptedException, NonZeroExitCodeExcep
}
Process process = builder.start();

if (process.waitFor() != 0)
if (!process.waitFor(commandTimeout, TimeUnit.MINUTES))
{
throw new NonZeroExitCodeException(commandline, new String(process.getErrorStream().readAllBytes()));
}
Expand Down
@@ -1,8 +1,22 @@
package com.freenow.sauron.plugins.generator;

import com.freenow.sauron.properties.PluginsConfigurationProperties;
import java.nio.file.Path;

public interface DependencyGenerator
public abstract class DependencyGenerator
{
Path generateCycloneDxBom(Path repositoryPath);
private static final Integer DEFAULT_COMMAND_TIMEOUT_MINUTES = 10;

protected final Integer commandTimeoutMinutes;


protected DependencyGenerator(PluginsConfigurationProperties properties)
{
commandTimeoutMinutes = properties.getPluginConfigurationProperty("dependency-checker", "commandTimeoutMinutes")
.map(Integer.class::cast)
.orElse(DEFAULT_COMMAND_TIMEOUT_MINUTES);
}


public abstract Path generateCycloneDxBom(Path repositoryPath);
}
Expand Up @@ -20,11 +20,11 @@ public static Optional<DependencyGenerator> newInstance(ProjectType type, Plugin
switch (type)
{
case MAVEN:
return Optional.of(new MavenDependencyGenerator());
return Optional.of(new MavenDependencyGenerator(properties));
case GRADLE_GROOVY:
return Optional.of(new GradleGroovyDependencyGenerator());
return Optional.of(new GradleGroovyDependencyGenerator(properties));
case GRADLE_KOTLIN_DSL:
return Optional.of(new GradleKotlinDslDependencyGenerator());
return Optional.of(new GradleKotlinDslDependencyGenerator(properties));
case NODEJS:
return Optional.of(new NodeJsDependencyGenerator(properties));
case PYTHON_REQUIREMENTS:
Expand Down
@@ -1,24 +1,33 @@
package com.freenow.sauron.plugins.generator.gradle;

import com.freenow.sauron.plugins.generator.DependencyGenerator;
import com.freenow.sauron.properties.PluginsConfigurationProperties;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.gradle.tooling.BuildLauncher;
import org.gradle.tooling.GradleConnector;
import org.gradle.tooling.ProjectConnection;

import org.gradle.tooling.internal.consumer.ConnectorServices;
import org.gradle.tooling.internal.consumer.DefaultGradleConnector;

@Slf4j
public abstract class GradleDependencyGenerator implements DependencyGenerator
public abstract class GradleDependencyGenerator extends DependencyGenerator
{

protected GradleDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);
}


protected abstract String gradleFile();

protected abstract String cycloneDxPlugin();


@Override
public Path generateCycloneDxBom(Path repositoryPath)
{
Expand All @@ -39,8 +48,9 @@ public Path generateCycloneDxBom(Path repositoryPath)

private void runGradleTask(Path repositoryPath, String... tasks)
{
GradleConnector connector = GradleConnector.newConnector();
DefaultGradleConnector connector = ConnectorServices.createConnector();
connector.forProjectDirectory(repositoryPath.toFile());
connector.daemonMaxIdleTime(commandTimeoutMinutes, TimeUnit.MINUTES);
try (ProjectConnection connection = connector.connect())
{
BuildLauncher build = connection.newBuild();
Expand All @@ -55,7 +65,7 @@ private void injectCycloneDxPlugin(Path repositoryPath) throws IOException
Path buildGradlePath = repositoryPath.resolve(gradleFile());
String content = new String(Files.readAllBytes(buildGradlePath));

if(Pattern.compile("plugins\\s*\\{[^}]*}").matcher(content).find())
if (Pattern.compile("plugins\\s*\\{[^}]*}").matcher(content).find())
{
content = content.replaceAll("plugins\\s*\\{([^}]*)}", String.format("plugins {$1\n%s\n}", cycloneDxPlugin()));
}
Expand Down
@@ -1,7 +1,15 @@
package com.freenow.sauron.plugins.generator.gradle;

import com.freenow.sauron.properties.PluginsConfigurationProperties;

public class GradleGroovyDependencyGenerator extends GradleDependencyGenerator
{
public GradleGroovyDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);
}


@Override
protected String gradleFile()
{
Expand Down
@@ -1,7 +1,15 @@
package com.freenow.sauron.plugins.generator.gradle;

import com.freenow.sauron.properties.PluginsConfigurationProperties;

public class GradleKotlinDslDependencyGenerator extends GradleDependencyGenerator
{
public GradleKotlinDslDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);
}


@Override
protected String gradleFile()
{
Expand Down
@@ -1,11 +1,13 @@
package com.freenow.sauron.plugins.generator.maven;

import com.freenow.sauron.plugins.generator.DependencyGenerator;
import com.freenow.sauron.properties.PluginsConfigurationProperties;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Collections;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.model.Build;
Expand All @@ -22,8 +24,14 @@
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

@Slf4j
public class MavenDependencyGenerator implements DependencyGenerator
public class MavenDependencyGenerator extends DependencyGenerator
{
public MavenDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);
}


@Override
public Path generateCycloneDxBom(Path repositoryPath)
{
Expand All @@ -32,6 +40,7 @@ public Path generateCycloneDxBom(Path repositoryPath)
File pom = repositoryPath.resolve("pom.xml").toFile();
injectCycloneDxPlugin(pom);
InvocationRequest request = new DefaultInvocationRequest();
request.setTimeoutInSeconds(Math.toIntExact(Duration.ofMinutes(commandTimeoutMinutes).toSeconds()));
request.setPomFile(pom);
request.setQuiet(!log.isDebugEnabled());
request.setGoals(Collections.singletonList("cyclonedx:makeBom"));
Expand Down
Expand Up @@ -11,7 +11,7 @@
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class NodeJsDependencyGenerator implements DependencyGenerator
public class NodeJsDependencyGenerator extends DependencyGenerator
{
public static class PackageLockJsonMissingException extends IllegalStateException
{
Expand All @@ -35,6 +35,8 @@ private YarnNotSupportedException(String message)

public NodeJsDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);

properties.getPluginConfigurationProperty("dependency-checker", "nodejs")
.ifPresent(nodeJsConfig ->
{
Expand Down Expand Up @@ -78,6 +80,7 @@ private void npmInstall(Path repositoryPath) throws IOException, InterruptedExce
requireNotYarn(repositoryPath);
requirePackageLockJson(repositoryPath);
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(String.join(" ", npmBin, "ci"))
.build()
Expand All @@ -88,6 +91,7 @@ private void npmInstall(Path repositoryPath) throws IOException, InterruptedExce
private Path buildCycloneDxBom(Path repositoryPath) throws IOException, InterruptedException, NonZeroExitCodeException
{
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(String.join(" ", npxBin, "@cyclonedx/bom"))
.build()
Expand Down
Expand Up @@ -11,7 +11,7 @@
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class PythonDependencyGenerator implements DependencyGenerator
public abstract class PythonDependencyGenerator extends DependencyGenerator
{
protected static final String ENV_PATH = "env";
protected static final String REQUIREMENTS_FREEZE_FILE = "requirements.freeze";
Expand All @@ -32,6 +32,7 @@ private RequirementsFreezeMissingException()

protected PythonDependencyGenerator(PluginsConfigurationProperties properties)
{
super(properties);
properties.getPluginConfigurationProperty("dependency-checker", "python")
.ifPresent(pythonConfig ->
{
Expand Down Expand Up @@ -72,12 +73,14 @@ public Path generateCycloneDxBom(Path repositoryPath)
private Path buildCycloneDxBom(Path repositoryPath) throws IOException, InterruptedException, NonZeroExitCodeException
{
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(PIP_INSTALL_CYCLONE_DX_COMMAND))
.build()
.run();

Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(CYCLONE_DX_PY_COMMAND))
.environment(Map.of("PYTHONPATH", repositoryPath.resolve(ENV_PATH).toString()))
Expand Down
Expand Up @@ -25,12 +25,14 @@ public PythonPoetryDependencyGenerator(PluginsConfigurationProperties properties
protected void generateRequirementsFreeze(Path repositoryPath) throws IOException, InterruptedException, NonZeroExitCodeException
{
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(PIP_INSTALL_POETRY))
.build()
.run();

Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(POETRY_EXPORT))
.environment(Map.of("PYTHONPATH", repositoryPath.resolve(ENV_PATH).toString()))
Expand Down
Expand Up @@ -37,6 +37,7 @@ protected void generateRequirementsFreeze(Path repositoryPath)
private void pipInstall(Path repositoryPath) throws IOException, InterruptedException
{
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(PIP_INSTALL_COMMAND))
.build()
Expand All @@ -47,6 +48,7 @@ private void pipInstall(Path repositoryPath) throws IOException, InterruptedExce
private void pipFreeze(Path repositoryPath) throws IOException, InterruptedException
{
Command.builder()
.commandTimeout(commandTimeoutMinutes)
.repositoryPath(repositoryPath)
.commandline(pythonCommand(FREEZE_COMMAND))
.outputFile(repositoryPath.resolve(REQUIREMENTS_FREEZE_FILE).toFile())
Expand Down

0 comments on commit 4a38941

Please sign in to comment.