mirror of
https://github.com/ysoftdevs/DependencyCheck.git
synced 2026-01-15 00:03:43 +01:00
Ruby Analyzer: Added bundle-audit analyzer. So far just launches if available and logs the output.
This commit is contained in:
@@ -27,6 +27,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.owasp.dependencycheck.data.nvdcve.CveDB;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
|
||||
import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
|
||||
@@ -354,6 +355,10 @@ public class App {
|
||||
if (pathToMono != null && !pathToMono.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
|
||||
}
|
||||
String pathToBundleAudit = cli.getPathToBundleAudit();
|
||||
if (!StringUtils.isEmpty(pathToBundleAudit)){
|
||||
Settings.setString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, pathToBundleAudit);
|
||||
}
|
||||
if (cveBase12 != null && !cveBase12.isEmpty()) {
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_1_2, cveBase12);
|
||||
Settings.setString(Settings.KEYS.CVE_SCHEMA_2_0, cveBase20);
|
||||
|
||||
@@ -328,6 +328,10 @@ public final class CliParser {
|
||||
.withDescription("The path to Mono for .NET Assembly analysis on non-windows systems.")
|
||||
.create();
|
||||
|
||||
final Option pathToBundleAudit = OptionBuilder.withArgName("path").hasArg()
|
||||
.withLongOpt(ARGUMENT.PATH_TO_BUNDLE_AUDIT)
|
||||
.withDescription("The path to bundle-audit for Gem bundle analysis.").create();
|
||||
|
||||
final Option connectionTimeout = OptionBuilder.withArgName("timeout").hasArg().withLongOpt(ARGUMENT.CONNECTION_TIMEOUT)
|
||||
.withDescription("The connection timeout (in milliseconds) to use when downloading resources.")
|
||||
.create(ARGUMENT.CONNECTION_TIMEOUT_SHORT);
|
||||
@@ -426,7 +430,8 @@ public final class CliParser {
|
||||
.addOption(nexusUrl)
|
||||
.addOption(nexusUsesProxy)
|
||||
.addOption(additionalZipExtensions)
|
||||
.addOption(pathToMono);
|
||||
.addOption(pathToMono)
|
||||
.addOption(pathToBundleAudit);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -690,6 +695,15 @@ public final class CliParser {
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_MONO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to bundle-audit for Ruby bundle analysis.
|
||||
*
|
||||
* @return the path to Mono
|
||||
*/
|
||||
public String getPathToBundleAudit() {
|
||||
return line.getOptionValue(ARGUMENT.PATH_TO_BUNDLE_AUDIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the output format specified on the command line. Defaults to HTML if no format was specified.
|
||||
*
|
||||
@@ -1160,5 +1174,9 @@ public final class CliParser {
|
||||
* Exclude path argument.
|
||||
*/
|
||||
public static final String EXCLUDE = "exclude";
|
||||
/**
|
||||
* The CLI argument name for setting the path to bundle-audit for Ruby bundle analysis.
|
||||
*/
|
||||
public static final String PATH_TO_BUNDLE_AUDIT = "bundleAudit";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* This file is part of dependency-check-core.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
|
||||
*/
|
||||
package org.owasp.dependencycheck.analyzer;
|
||||
|
||||
import org.owasp.dependencycheck.Engine;
|
||||
import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
|
||||
import org.owasp.dependencycheck.dependency.Dependency;
|
||||
import org.owasp.dependencycheck.utils.FileFilterBuilder;
|
||||
import org.owasp.dependencycheck.utils.Settings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to analyze Ruby Bundler Gemspec.lock files utilizing the 3rd party bundle-audit tool.
|
||||
*
|
||||
* @author Dale Visser <dvisser@ida.org>
|
||||
*/
|
||||
public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RubyBundleAuditAnalyzer.class);
|
||||
|
||||
/**
|
||||
* The name of the analyzer.
|
||||
*/
|
||||
private static final String ANALYZER_NAME = "Ruby Bundle Audit Analyzer";
|
||||
|
||||
/**
|
||||
* The phase that this analyzer is intended to run in.
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
private static final FileFilter FILTER =
|
||||
FileFilterBuilder.newInstance().addFilenames("Gemfile.lock").build();
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files named Rakefile or matching the glob pattern, *.gemspec
|
||||
*/
|
||||
@Override
|
||||
protected FileFilter getFileFilter() {
|
||||
return FILTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch bundle-audit.
|
||||
*
|
||||
* @return a handle to the process
|
||||
*/
|
||||
private Process launchBundleAudit(File folder) throws AnalysisException {
|
||||
if (!folder.isDirectory()){
|
||||
throw new AnalysisException(String.format("%s should have been a directory.", folder.getAbsolutePath()));
|
||||
}
|
||||
final List<String> args = new ArrayList<String>();
|
||||
final String bundleAuditPath = Settings.getString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH);
|
||||
args.add(null == bundleAuditPath ? "bundle-audit" : bundleAuditPath);
|
||||
args.add("check");
|
||||
final ProcessBuilder builder = new ProcessBuilder(args);
|
||||
builder.directory(folder);
|
||||
try {
|
||||
return builder.start();
|
||||
} catch (IOException ioe) {
|
||||
throw new AnalysisException("bundle-audit failure", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the analyzer. In this case, extract GrokAssembly.exe to a temporary location.
|
||||
*
|
||||
* @throws Exception if anything goes wrong
|
||||
*/
|
||||
@Override
|
||||
public void initializeFileTypeAnalyzer() throws Exception {
|
||||
// Now, need to see if bundle-audit actually runs from this location.
|
||||
try {
|
||||
Process process = launchBundleAudit(Settings.getTempDirectory());
|
||||
int exitValue = process.waitFor();
|
||||
if (0 == exitValue) {
|
||||
LOGGER.warn("Unexpected exit code from bundle-audit process. Disabling %s: %d", ANALYZER_NAME, exitValue);
|
||||
setEnabled(false);
|
||||
} else {
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(process.getErrorStream(), "UTF-8"));
|
||||
if (!reader.ready()) {
|
||||
LOGGER.warn("Bundle-audit error stream unexpectedly not ready. Disabling " + ANALYZER_NAME);
|
||||
setEnabled(false);
|
||||
} else {
|
||||
final String line = reader.readLine();
|
||||
if (!line.contains("Errno::ENOENT")) {
|
||||
LOGGER.warn("Unexpected bundle-audit output. Disabling %s: %s", ANALYZER_NAME, line);
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (null != reader) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (AnalysisException ae) {
|
||||
LOGGER.warn("Exception while trying to launch bundle-audit. Disabling " + ANALYZER_NAME, ae.getCause());
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the analyzer.
|
||||
*
|
||||
* @return the name of the analyzer.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return ANALYZER_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phase that the analyzer is intended to run in.
|
||||
*
|
||||
* @return the phase that the analyzer is intended to run in.
|
||||
*/
|
||||
@Override
|
||||
public AnalysisPhase getAnalysisPhase() {
|
||||
return ANALYSIS_PHASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key used in the properties file to reference the analyzer's enabled property.
|
||||
*
|
||||
* @return the analyzer's enabled property setting key
|
||||
*/
|
||||
@Override
|
||||
protected String getAnalyzerEnabledSettingKey() {
|
||||
return Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void analyzeFileType(Dependency dependency, Engine engine)
|
||||
throws AnalysisException {
|
||||
final File parentFile = dependency.getActualFile().getParentFile();
|
||||
final Process process = launchBundleAudit(parentFile);
|
||||
try {
|
||||
process.waitFor();
|
||||
} catch (InterruptedException ie) {
|
||||
throw new AnalysisException("bundle-audit process interrupted", ie);
|
||||
}
|
||||
BufferedReader rdr = null;
|
||||
try {
|
||||
rdr = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
||||
while (rdr.ready()) {
|
||||
final String nextLine = rdr.readLine();
|
||||
if (null == nextLine) {
|
||||
break;
|
||||
}
|
||||
LOGGER.info(String.format("bundle-audit (%s): %s", parentFile.getName(), nextLine));
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit failure", ioe);
|
||||
} finally {
|
||||
if (null != rdr) {
|
||||
try {
|
||||
rdr.close();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.warn("bundle-audit close failure", ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -49,11 +49,12 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer {
|
||||
*/
|
||||
private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
|
||||
|
||||
private static final String GEMSPEC = "gemspec";
|
||||
|
||||
private static final FileFilter FILTER =
|
||||
FileFilterBuilder.newInstance().addExtensions("gemspec").addFilenames("Rakefile").build();
|
||||
FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build();
|
||||
|
||||
private static final String EMAIL = "email";
|
||||
private static final String GEMSPEC = "gemspec";
|
||||
|
||||
/**
|
||||
* @return a filter that accepts files named Rakefile or matching the glob pattern, *.gemspec
|
||||
|
||||
@@ -17,4 +17,5 @@ org.owasp.dependencycheck.analyzer.PythonPackageAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.AutoconfAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.CMakeAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer
|
||||
org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer
|
||||
@@ -246,6 +246,10 @@ public final class Settings {
|
||||
* The path to mono, if available.
|
||||
*/
|
||||
public static final String ANALYZER_ASSEMBLY_MONO_PATH = "analyzer.assembly.mono.path";
|
||||
/**
|
||||
* The path to bundle-audit, if available.
|
||||
*/
|
||||
public static final String ANALYZER_BUNDLE_AUDIT_PATH = "analyzer.bundle.audit.path";
|
||||
/**
|
||||
* The additional configured zip file extensions, if available.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user