diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java index 2cf35171d..fd6911e6f 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyBundlingAnalyzer.java @@ -138,6 +138,14 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal mergeDependencies(nextDependency, dependency, dependenciesToRemove); break; //since we merged into the next dependency - skip forward to the next in mainIterator } + } else if ( isSameRubyGem(dependency, nextDependency) ) { + Dependency main = getMainGemspecDependency(dependency, nextDependency); + if (main == dependency) { + mergeDependencies(dependency, nextDependency, dependenciesToRemove); + } else { + mergeDependencies(nextDependency, dependency, dependenciesToRemove); + break; //since we merged into the next dependency - skip forward to the next in mainIterator + } } } } @@ -302,6 +310,44 @@ public class DependencyBundlingAnalyzer extends AbstractAnalyzer implements Anal } return false; } + + /** + * Bundling Ruby gems that are identified from different .gemspec files but denote the same package path. + * This happens when Ruby bundler installs an app's dependencies by running "bundle install". + */ + private boolean isSameRubyGem(Dependency dependency1, Dependency dependency2) { + if (dependency1 == null || dependency2 == null || + !dependency1.getFileName().endsWith(".gemspec") || + !dependency2.getFileName().endsWith(".gemspec") || + dependency1.getPackagePath() == null || + dependency2.getPackagePath() == null) { + return false; + } + if (dependency1.getPackagePath().equalsIgnoreCase(dependency2.getPackagePath())) + return true; + + return false; + } + + /** + * Ruby gems installed by "bundle install" can have zero or more *.gemspec files, all of which have the same packagePath and should be grouped. + * If one of these gemspec is from /specifications/*.gemspec, because it is a stub with fully resolved gem meta-data + * created by Ruby bundler, this dependency should be the main one. Otherwise, use dependency2 as main. + * + * This method returns null if any dependency is not from *.gemspec, or the two do not have the same packagePath. + * In this case, they should not be grouped. + */ + private Dependency getMainGemspecDependency(Dependency dependency1, Dependency dependency2) { + if (isSameRubyGem(dependency1, dependency2)) { + final File lFile = dependency1.getActualFile(); + File left = lFile.getParentFile(); + if (left != null && left.getName().equalsIgnoreCase("specifications")) { + return dependency1; + } + return dependency2; + } + return null; + } /** * This is likely a very broken attempt at determining if the 'left' dependency is the 'core' library in comparison to the diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java index b7d23a3e3..570e63ff0 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java @@ -98,7 +98,7 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer { dependency.getVersionEvidence().addEvidence("file", "name", version.toString(), Confidence.MEDIUM); } else { - dependency.getVersionEvidence().addEvidence("file", "name", + dependency.getVersionEvidence().addEvidence("file", "version", version.toString(), Confidence.HIGHEST); } dependency.getVersionEvidence().addEvidence("file", "name", @@ -106,12 +106,13 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer { } //add as vendor and product evidence - if (fileName.contains("-")) { - dependency.getProductEvidence().addEvidence("file", "name", - fileName, Confidence.HIGHEST); - dependency.getVendorEvidence().addEvidence("file", "name", - fileName, Confidence.HIGHEST); - } else if (!IGNORED_FILES.accept(f)) { +// if (fileName.contains("-")) { +// dependency.getProductEvidence().addEvidence("file", "name", +// fileName, Confidence.HIGHEST); +// dependency.getVendorEvidence().addEvidence("file", "name", +// fileName, Confidence.HIGHEST); +// } else + if (!IGNORED_FILES.accept(f)) { dependency.getProductEvidence().addEvidence("file", "name", fileName, Confidence.HIGH); dependency.getVendorEvidence().addEvidence("file", "name", diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java index c76e8199b..51bf51724 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java @@ -565,6 +565,11 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { addMatchingValues(classes, trimmedDescription, dependency.getVendorEvidence()); addMatchingValues(classes, trimmedDescription, dependency.getProductEvidence()); } + + String projectURL = pom.getProjectURL(); + if(projectURL != null && !projectURL.trim().isEmpty()) { + dependency.getVendorEvidence().addEvidence("pom", "url", projectURL, Confidence.HIGHEST); + } extractLicense(pom, dependency); return foundSomething; diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java index 8500eac22..527892bce 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java @@ -174,20 +174,22 @@ public class PythonPackageAnalyzer extends AbstractFileTypeAnalyzer { final File file = dependency.getActualFile(); final File parent = file.getParentFile(); final String parentName = parent.getName(); - boolean found = false; if (INIT_PY_FILTER.accept(file)) { + //by definition, the containing folder of __init__.py is considered the package, even the file is empty: + //"The __init__.py files are required to make Python treat the directories as containing packages" + //see section "6.4 Packages" from https://docs.python.org/2/tutorial/modules.html; + dependency.setDisplayFileName(parentName + "/__init__.py"); + dependency.getProductEvidence().addEvidence(file.getName(), + "PackageName", parentName, Confidence.HIGHEST); + final File[] fileList = parent.listFiles(PY_FILTER); if (fileList != null) { for (final File sourceFile : fileList) { - found |= analyzeFileContents(dependency, sourceFile); + analyzeFileContents(dependency, sourceFile); } } } - if (found) { - dependency.setDisplayFileName(parentName + "/__init__.py"); - dependency.getProductEvidence().addEvidence(file.getName(), - "PackageName", parentName, Confidence.HIGH); - } else { + else { // copy, alter and set in case some other thread is iterating over final List dependencies = new ArrayList( engine.getDependencies()); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java index 48b437fa8..8a315bd42 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java @@ -207,14 +207,18 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { boolean failed = true; final String className = RubyGemspecAnalyzer.class.getName(); for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) { - if (analyzer instanceof RubyGemspecAnalyzer) { + if (analyzer instanceof RubyBundlerAnalyzer) { + ((RubyBundlerAnalyzer) analyzer).setEnabled(false); + LOGGER.info("Disabled " + RubyBundlerAnalyzer.class.getName() + " to avoid noisy duplicate results."); + } + else if (analyzer instanceof RubyGemspecAnalyzer) { ((RubyGemspecAnalyzer) analyzer).setEnabled(false); LOGGER.info("Disabled " + className + " to avoid noisy duplicate results."); failed = false; } } if (failed) { - LOGGER.warn("Did not find" + className + '.'); + LOGGER.warn("Did not find " + className + '.'); } needToDisableGemspecAnalyzer = false; } @@ -251,6 +255,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException { final String parentName = original.getActualFile().getParentFile().getName(); final String fileName = original.getFileName(); + final String filePath = original.getFilePath(); Dependency dependency = null; Vulnerability vulnerability = null; String gem = null; @@ -264,7 +269,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { appendToDescription = false; gem = nextLine.substring(NAME.length()); if (!map.containsKey(gem)) { - map.put(gem, createDependencyForGem(engine, parentName, fileName, gem)); + map.put(gem, createDependencyForGem(engine, parentName, fileName, filePath, gem)); } dependency = map.get(gem); LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine)); @@ -359,13 +364,17 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { return vulnerability; } - private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String gem) throws IOException { - final File tempFile = File.createTempFile("Gemfile-" + gem, ".lock", Settings.getTempDirectory()); + private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException { + final File gemFile = new File(Settings.getTempDirectory(), gem + "_Gemfile.lock"); + gemFile.createNewFile(); final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem); - FileUtils.write(tempFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling - final Dependency dependency = new Dependency(tempFile); + + FileUtils.write(gemFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling + final Dependency dependency = new Dependency(gemFile); dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST); dependency.setDisplayFileName(displayFileName); + dependency.setFileName(fileName); + dependency.setFilePath(filePath); engine.getDependencies().add(dependency); return dependency; } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java new file mode 100644 index 000000000..05bfddb89 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzer.java @@ -0,0 +1,126 @@ +/* + * 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) 2016 Bianca Jiang. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import java.io.File; +import java.io.FilenameFilter; + +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Dependency; + +/** + * This analyzer accepts the fully resolved .gemspec created by the Ruby bundler (http://bundler.io) + * for better evidence results. It also tries to resolve the dependency packagePath + * to where the gem is actually installed. Then during {@link AnalysisPhase.PRE_FINDING_ANALYSIS} + * {@link DependencyBundlingAnalyzer} will merge two .gemspec dependencies together if + * Dependency.getPackagePath() are the same. + * + * Ruby bundler creates new .gemspec files under a folder called "specifications" at deploy time, + * in addition to the original .gemspec files from source. The bundler generated + * .gemspec files always contain fully resolved attributes thus provide more accurate + * evidences, whereas the original .gemspec from source often contain variables for attributes + * that can't be used for evidences. + * + * Note this analyzer share the same {@link Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED} as + * {@link RubyGemspecAnalyzer}, so it will enabled/disabled with {@link RubyGemspecAnalyzer}. + * + * @author Bianca Jiang (biancajiang@gmail.com) + */ +public class RubyBundlerAnalyzer extends RubyGemspecAnalyzer { + + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "Ruby Bundler Analyzer"; + + //Folder name that contains .gemspec files created by "bundle install" + private static final String SPECIFICATIONS = "specifications"; + + //Folder name that contains the gems by "bundle install" + private static final String GEMS = "gems"; + + /** + * Returns the name of the analyzer. + * + * @return the name of the analyzer. + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Only accept *.gemspec files generated by "bundle install --deployment" under "specifications" folder. + */ + @Override + public boolean accept(File pathname) { + + boolean accepted = super.accept(pathname); + if(accepted == true) { + File parentDir = pathname.getParentFile(); + accepted = parentDir != null && parentDir.getName().equals(SPECIFICATIONS); + } + + return accepted; + } + + @Override + protected void analyzeFileType(Dependency dependency, Engine engine) + throws AnalysisException { + super.analyzeFileType(dependency, engine); + + //find the corresponding gem folder for this .gemspec stub by "bundle install --deployment" + File gemspecFile = dependency.getActualFile(); + String gemFileName = gemspecFile.getName(); + final String gemName = gemFileName.substring(0, gemFileName.lastIndexOf(".gemspec")); + File specificationsDir = gemspecFile.getParentFile(); + if(specificationsDir != null && specificationsDir.getName().equals(SPECIFICATIONS) && specificationsDir.exists()) { + File parentDir = specificationsDir.getParentFile(); + if(parentDir != null && parentDir.exists()) { + File gemsDir = new File(parentDir, GEMS); + if(gemsDir != null && gemsDir.exists()) { + File[] matchingFiles = gemsDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.equals(gemName); + } + }); + + if(matchingFiles.length > 0) { + String gemPath = matchingFiles[0].getAbsolutePath(); + if(dependency.getActualFilePath().equals(dependency.getFilePath())) { + if(gemPath != null) + dependency.setPackagePath(gemPath); + } else { + //.gemspec's actualFilePath and filePath are different when it's from a compressed file + //in which case actualFilePath is the temp directory used by decompression. + //packagePath should use the filePath of the identified gem file in "gems" folder + File gemspecStub = new File(dependency.getFilePath()); + File specDir = gemspecStub.getParentFile(); + if(specDir != null && specDir.getName().equals(SPECIFICATIONS)) { + File gemsDir2 = new File(specDir.getParentFile(), GEMS); + File packageDir = new File(gemsDir2, gemName); + dependency.setPackagePath(packageDir.getAbsolutePath()); + } + } + } + } + } + } + } +} diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java index d6fb5e6a4..8bad7cab2 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java @@ -17,6 +17,15 @@ */ package org.owasp.dependencycheck.analyzer; +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; @@ -26,12 +35,6 @@ import org.owasp.dependencycheck.dependency.EvidenceCollection; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Used to analyze Ruby Gem specifications and collect information that can be used to determine the associated CPE. Regular * expressions are used to parse the well-defined Ruby syntax that forms the specification. @@ -53,12 +56,14 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { private static final String GEMSPEC = "gemspec"; private static final FileFilter FILTER - = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build(); + = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).build(); + //TODO: support Rakefile + //= FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build(); - private static final String EMAIL = "email"; + private static final String VERSION_FILE_NAME = "VERSION"; /** - * @return a filter that accepts files named Rakefile or matching the glob pattern, *.gemspec + * @return a filter that accepts files matching the glob pattern, *.gemspec */ @Override protected FileFilter getFileFilter() { @@ -120,43 +125,84 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { if (matcher.find()) { contents = contents.substring(matcher.end()); final String blockVariable = matcher.group(1); + final EvidenceCollection vendor = dependency.getVendorEvidence(); - addStringEvidence(vendor, contents, blockVariable, "author", Confidence.HIGHEST); - addListEvidence(vendor, contents, blockVariable, "authors", Confidence.HIGHEST); - final String email = addStringEvidence(vendor, contents, blockVariable, EMAIL, Confidence.MEDIUM); - if (email.isEmpty()) { - addListEvidence(vendor, contents, blockVariable, EMAIL, Confidence.MEDIUM); - } - addStringEvidence(vendor, contents, blockVariable, "homepage", Confidence.MEDIUM); final EvidenceCollection product = dependency.getProductEvidence(); - final String name = addStringEvidence(product, contents, blockVariable, "name", Confidence.HIGHEST); + final String name = addStringEvidence(product, contents, blockVariable, "name", "name", Confidence.HIGHEST); if (!name.isEmpty()) { vendor.addEvidence(GEMSPEC, "name_project", name + "_project", Confidence.LOW); } - addStringEvidence(product, contents, blockVariable, "summary", Confidence.LOW); - addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", Confidence.HIGHEST); - } - } + addStringEvidence(product, contents, blockVariable, "summary", "summary", Confidence.LOW); - private void addListEvidence(EvidenceCollection evidences, String contents, - String blockVariable, String field, Confidence confidence) { - final Matcher matcher = Pattern.compile( - String.format("\\s+?%s\\.%s\\s*?=\\s*?\\[(.*?)\\]", blockVariable, field)).matcher(contents); - if (matcher.find()) { - final String value = matcher.group(1).replaceAll("['\"]", " ").trim(); - evidences.addEvidence(GEMSPEC, field, value, confidence); + addStringEvidence(vendor, contents, blockVariable, "author", "authors?", Confidence.HIGHEST); + addStringEvidence(vendor, contents, blockVariable, "email", "emails?", Confidence.MEDIUM); + addStringEvidence(vendor, contents, blockVariable, "homepage", "homepage", Confidence.HIGHEST); + addStringEvidence(vendor, contents, blockVariable, "license", "licen[cs]es?", Confidence.HIGHEST); + + String value = addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", "version", Confidence.HIGHEST); + if(value.length() < 1) + addEvidenceFromVersionFile(dependency.getActualFile(), dependency.getVersionEvidence()); } + + setPackagePath(dependency); } private String addStringEvidence(EvidenceCollection evidences, String contents, - String blockVariable, String field, Confidence confidence) { - final Matcher matcher = Pattern.compile( - String.format("\\s+?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, field)).matcher(contents); + String blockVariable, String field, String fieldPattern, Confidence confidence) { String value = ""; - if (matcher.find()) { - value = matcher.group(2); - evidences.addEvidence(GEMSPEC, field, value, confidence); - } + + //capture array value between [ ] + final Matcher arrayMatcher = Pattern.compile( + String.format("\\s*?%s\\.%s\\s*?=\\s*?\\[(.*?)\\]", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents); + if(arrayMatcher.find()) { + String arrayValue = arrayMatcher.group(1); + value = arrayValue.replaceAll("['\"]", "").trim(); //strip quotes + } + //capture single value between quotes + else { + final Matcher matcher = Pattern.compile( + String.format("\\s*?%s\\.%s\\s*?=\\s*?(['\"])(.*?)\\1", blockVariable, fieldPattern), Pattern.CASE_INSENSITIVE).matcher(contents); + if (matcher.find()) { + value = matcher.group(2); + } + } + if(value.length() > 0) + evidences.addEvidence(GEMSPEC, field, value, confidence); + return value; } + + private String addEvidenceFromVersionFile(File dependencyFile, EvidenceCollection versionEvidences) { + String value = null; + File parentDir = dependencyFile.getParentFile(); + if(parentDir != null) { + File[] matchingFiles = parentDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.contains(VERSION_FILE_NAME); + } + }); + + for(int i = 0; i < matchingFiles.length; i++) { + try { + List lines = FileUtils.readLines(matchingFiles[i]); + if(lines.size() == 1) { //TODO other checking? + value = lines.get(0).trim(); + versionEvidences.addEvidence(GEMSPEC, "version", value, Confidence.HIGH); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return value; + } + + private void setPackagePath(Dependency dep) { + File file = new File(dep.getFilePath()); + String parent = file.getParent(); + if(parent != null) + dep.setPackagePath(parent); + } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java index 1f0b06fdd..37e6c5bb1 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java @@ -72,7 +72,17 @@ public class Dependency implements Serializable, Comparable { * The file name of the dependency. */ private String fileName; - /** + + private String packagePath; + public String getPackagePath() { + return packagePath; + } + + public void setPackagePath(String packagePath) { + this.packagePath = packagePath; + } + + /** * The md5 hash of the dependency. */ private String md5sum; @@ -120,6 +130,7 @@ public class Dependency implements Serializable, Comparable { this.actualFilePath = file.getAbsolutePath(); this.filePath = this.actualFilePath; this.fileName = file.getName(); + this.packagePath = filePath; determineHashes(file); } @@ -188,6 +199,9 @@ public class Dependency implements Serializable, Comparable { * @param filePath the file path of the dependency */ public void setFilePath(String filePath) { + if(this.packagePath == null || this.packagePath.equals(this.filePath)) + this.packagePath = filePath; + this.filePath = filePath; } @@ -719,6 +733,7 @@ public class Dependency implements Serializable, Comparable { .append(this.actualFilePath, other.actualFilePath) .append(this.filePath, other.filePath) .append(this.fileName, other.fileName) + .append(this.packagePath, other.packagePath) .append(this.md5sum, other.md5sum) .append(this.sha1sum, other.sha1sum) .append(this.identifiers, other.identifiers) @@ -767,6 +782,6 @@ public class Dependency implements Serializable, Comparable { */ @Override public String toString() { - return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "'}"; + return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "', packagePath='" + packagePath + "'}"; } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java index 190116acc..2cecff585 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java @@ -260,6 +260,29 @@ public class Model { public void addLicense(License license) { licenses.add(license); } + + /** + * The project URL. + */ + private String projectURL; + + /** + * Get the value of projectURL. + * + * @return the value of projectURL + */ + public String getProjectURL() { + return projectURL; + } + + /** + * Set the value of projectURL. + * + * @param parentVersion new value of projectURL + */ + public void setProjectURL(String projectURL) { + this.projectURL = projectURL; + } /** * Process the Maven properties file and interpolate all properties. @@ -276,11 +299,11 @@ public class Model { l.setUrl(interpolateString(l.getUrl(), properties)); } this.name = interpolateString(this.name, properties); + this.projectURL = interpolateString(this.projectURL, properties); this.organization = interpolateString(this.organization, properties); this.parentGroupId = interpolateString(this.parentGroupId, properties); this.parentArtifactId = interpolateString(this.parentArtifactId, properties); this.parentVersion = interpolateString(this.parentVersion, properties); - } /** @@ -317,7 +340,7 @@ public class Model { return substitutor.replace(text); } - /** + /** * Utility class that can provide values from a Properties object to a StrSubstitutor. */ private static class PropertyLookup extends StrLookup { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java index d3f0bc701..669ab9d0d 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java @@ -145,6 +145,8 @@ public class PomHandler extends DefaultHandler { model.setOrganization(currentText.toString()); } else if (DESCRIPTION.equals(qName)) { model.setDescription(currentText.toString()); + } else if (URL.equals(qName)) { + model.setProjectURL(currentText.toString()); } } else if (PARENT.equals(parentNode)) { if (GROUPID.equals(qName)) { diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer index 43d67c5fe..7f67a3d84 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer @@ -19,5 +19,6 @@ org.owasp.dependencycheck.analyzer.OpenSSLAnalyzer org.owasp.dependencycheck.analyzer.CMakeAnalyzer org.owasp.dependencycheck.analyzer.NodePackageAnalyzer org.owasp.dependencycheck.analyzer.RubyGemspecAnalyzer +org.owasp.dependencycheck.analyzer.RubyBundlerAnalyzer org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java index de85050be..9c8b44cf6 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/JarAnalyzerTest.java @@ -17,23 +17,25 @@ */ package org.owasp.dependencycheck.analyzer; -import org.junit.Test; -import org.owasp.dependencycheck.BaseTest; -import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.dependency.Evidence; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.io.File; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.Evidence; /** * @author Jeremy Long */ public class JarAnalyzerTest extends BaseTest { +// private static final Logger LOGGER = LoggerFactory.getLogger(JarAnalyzerTest.class); + /** * Test of inspect method, of class JarAnalyzer. * @@ -48,12 +50,25 @@ public class JarAnalyzerTest extends BaseTest { instance.analyze(result, null); assertTrue(result.getVendorEvidence().toString().toLowerCase().contains("apache")); assertTrue(result.getVendorEvidence().getWeighting().contains("apache")); + + file = BaseTest.getResourceAsFile(this, "dwr.jar"); + result = new Dependency(file); + instance.analyze(result, null); + boolean found = false; + for (Evidence e : result.getVendorEvidence()) { + if (e.getName().equals("url")) { + assertEquals("Project url was not as expected in dwr.jar", e.getValue(), "http://getahead.ltd.uk/dwr"); + found = true; + break; + } + } + assertTrue("Project url was not found in dwr.jar", found); //file = new File(this.getClass().getClassLoader().getResource("org.mortbay.jetty.jar").getPath()); file = BaseTest.getResourceAsFile(this, "org.mortbay.jetty.jar"); result = new Dependency(file); instance.analyze(result, null); - boolean found = false; + found = false; for (Evidence e : result.getProductEvidence()) { if (e.getName().equalsIgnoreCase("package-title") && e.getValue().equalsIgnoreCase("org.mortbay.http")) { diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java index 68436e92e..64afd6c52 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java @@ -23,16 +23,22 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import org.junit.After; import org.junit.Assume; import org.junit.Before; import org.junit.Test; +import org.owasp.dependencycheck.BaseDBTestCase; import org.owasp.dependencycheck.BaseTest; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; @@ -43,7 +49,7 @@ import org.slf4j.LoggerFactory; * * @author Dale Visser */ -public class RubyBundleAuditAnalyzerTest extends BaseTest { +public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase { private static final Logger LOGGER = LoggerFactory.getLogger(RubyBundleAuditAnalyzerTest.class); @@ -101,19 +107,19 @@ public class RubyBundleAuditAnalyzerTest extends BaseTest { public void testAnalysis() throws AnalysisException, DatabaseException { try { analyzer.initialize(); - - final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, - "ruby/vulnerable/gems/rails-4.1.15/Gemfile.lock")); + final String resource = "ruby/vulnerable/gems/rails-4.1.15/Gemfile.lock"; + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, resource)); final Engine engine = new Engine(); analyzer.analyze(result, engine); int size = engine.getDependencies().size(); - assertThat(size, is(1)); + assertTrue(size >= 1); + Dependency dependency = engine.getDependencies().get(0); assertTrue(dependency.getProductEvidence().toString().toLowerCase().contains("redcarpet")); assertTrue(dependency.getVersionEvidence().toString().toLowerCase().contains("2.2.2")); - - + assertTrue(dependency.getFilePath().endsWith(resource)); + assertTrue(dependency.getFileName().equals("Gemfile.lock")); } catch (Exception e) { LOGGER.warn("Exception setting up RubyBundleAuditAnalyzer. Make sure Ruby gem bundle-audit is installed. You may also need to set property \"analyzer.bundle.audit.path\".", e); Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", e); @@ -166,5 +172,52 @@ public class RubyBundleAuditAnalyzerTest extends BaseTest { } } + /** + * Test Ruby dependencies and their paths. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + @Test + public void testDependenciesPath() throws AnalysisException, DatabaseException { + + final Engine engine = new Engine(); + engine.scan(BaseTest.getResourceAsFile(this, + "ruby/vulnerable/gems/rails-4.1.15/")); + engine.analyzeDependencies(); + + List dependencies = engine.getDependencies(); + LOGGER.info(dependencies.size() + " dependencies found."); + Iterator dIterator = dependencies.iterator(); + while(dIterator.hasNext()) { + Dependency dept = dIterator.next(); + LOGGER.info("dept path: " + dept.getActualFilePath()); + Set identifiers = dept.getIdentifiers(); + Iterator idIterator = identifiers.iterator(); + while(idIterator.hasNext()) { + Identifier id = idIterator.next(); + LOGGER.info(" Identifier: " + id.getValue() + ", type=" + id.getType() + ", url=" + id.getUrl() + ", conf="+ id.getConfidence()); + } + + Set prodEv = dept.getProductEvidence().getEvidence(); + Iterator it = prodEv.iterator(); + while(it.hasNext()) { + Evidence e = it.next(); + LOGGER.info(" prod: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + Set versionEv = dept.getVersionEvidence().getEvidence(); + Iterator vIt = versionEv.iterator(); + while(vIt.hasNext()) { + Evidence e = vIt.next(); + LOGGER.info(" version: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + + Set vendorEv = dept.getVendorEvidence().getEvidence(); + Iterator vendorIt = vendorEv.iterator(); + while(vendorIt.hasNext()) { + Evidence e = vendorIt.next(); + LOGGER.info(" vendor: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + } + } } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzerTest.java new file mode 100644 index 000000000..d304a4200 --- /dev/null +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundlerAnalyzerTest.java @@ -0,0 +1,106 @@ +/* + * 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) 2016 Bianca Jiang. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.owasp.dependencycheck.BaseTest; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.dependency.Dependency; + +import java.io.File; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +/** + * Unit tests for {@link RubyBundlerAnalyzer}. + * + * @author Bianca Jiang + */ +public class RubyBundlerAnalyzerTest extends BaseTest { + + /** + * The analyzer to test. + */ + RubyBundlerAnalyzer analyzer; + + /** + * Correctly setup the analyzer for testing. + * + * @throws Exception thrown if there is a problem + */ + @Before + public void setUp() throws Exception { + analyzer = new RubyBundlerAnalyzer(); + analyzer.setFilesMatched(true); + analyzer.initialize(); + } + + /** + * Cleanup the analyzer's temp files, etc. + * + * @throws Exception thrown if there is a problem + */ + @After + public void tearDown() throws Exception { + analyzer.close(); + analyzer = null; + } + + /** + * Test Analyzer name. + */ + @Test + public void testGetName() { + assertThat(analyzer.getName(), is("Ruby Bundler Analyzer")); + } + + /** + * Test Ruby Gemspec file support. + */ + @Test + public void testSupportsFiles() { + assertThat(analyzer.accept(new File("test.gemspec")), is(false)); + assertThat(analyzer.accept(new File("specifications" + File.separator + "test.gemspec")), is(true)); + } + + /** + * Test Ruby Bundler created gemspec analysis. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + @Test + public void testAnalyzeGemspec() throws AnalysisException { + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, + "ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/specifications/dalli-2.7.5.gemspec")); + analyzer.analyze(result, null); + + final String vendorString = result.getVendorEvidence().toString(); + assertThat(vendorString, containsString("Peter M. Goldstein")); + assertThat(vendorString, containsString("Mike Perham")); + assertThat(vendorString, containsString("peter.m.goldstein@gmail.com")); + assertThat(vendorString, containsString("https://github.com/petergoldstein/dalli")); + assertThat(vendorString, containsString("MIT")); + assertThat(result.getProductEvidence().toString(), containsString("dalli")); + assertThat(result.getProductEvidence().toString(), containsString("High performance memcached client for Ruby")); + assertThat(result.getVersionEvidence().toString(), containsString("2.7.5")); + } +} diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java index 23aabb135..882a70ef7 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java @@ -79,7 +79,7 @@ public class RubyGemspecAnalyzerTest extends BaseTest { @Test public void testSupportsFiles() { assertThat(analyzer.accept(new File("test.gemspec")), is(true)); - assertThat(analyzer.accept(new File("Rakefile")), is(true)); +// assertThat(analyzer.accept(new File("Rakefile")), is(true)); } /** @@ -100,4 +100,17 @@ public class RubyGemspecAnalyzerTest extends BaseTest { assertThat(result.getProductEvidence().toString(), containsString("rest-client")); assertThat(result.getVersionEvidence().toString(), containsString("1.7.2")); } + + /** + * Test Rakefile analysis. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + //@Test TODO: place holder to test Rakefile support + public void testAnalyzeRakefile() throws AnalysisException { + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, + "ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/gems/pg-0.18.4/Rakefile")); + analyzer.analyze(result, null); + //TODO add verification + } } diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index e3862e8e7..8d4e7a035 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -101,4 +101,4 @@ analyzer.nexus.enabled=false analyzer.nexus.proxy=true #Use your own bundle-audit install directory. -#analyzer.bundle.audit.path=/usr/local/bin/bundle-audit +analyzer.bundle.audit.path=/usr/local/bin/bundle-audit diff --git a/dependency-check-core/src/test/resources/dwr.jar b/dependency-check-core/src/test/resources/dwr.jar new file mode 100644 index 000000000..cbe768ad6 Binary files /dev/null and b/dependency-check-core/src/test/resources/dwr.jar differ diff --git a/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/gems/pg-0.18.4/Rakefile b/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/gems/pg-0.18.4/Rakefile new file mode 100644 index 000000000..4c6baeada --- /dev/null +++ b/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/gems/pg-0.18.4/Rakefile @@ -0,0 +1,218 @@ +#!/usr/bin/env rake + +require 'rbconfig' +require 'pathname' +require 'tmpdir' + +begin + require 'rake/extensiontask' +rescue LoadError + abort "This Rakefile requires rake-compiler (gem install rake-compiler)" +end + +begin + require 'hoe' +rescue LoadError + abort "This Rakefile requires hoe (gem install hoe)" +end + +require 'rake/clean' + +# Build directory constants +BASEDIR = Pathname( __FILE__ ).dirname +SPECDIR = BASEDIR + 'spec' +LIBDIR = BASEDIR + 'lib' +EXTDIR = BASEDIR + 'ext' +PKGDIR = BASEDIR + 'pkg' +TMPDIR = BASEDIR + 'tmp' + +DLEXT = RbConfig::CONFIG['DLEXT'] +EXT = LIBDIR + "pg_ext.#{DLEXT}" + +GEMSPEC = 'pg.gemspec' + +TEST_DIRECTORY = BASEDIR + "tmp_test_specs" + +CLOBBER.include( TEST_DIRECTORY.to_s ) +CLEAN.include( PKGDIR.to_s, TMPDIR.to_s ) + +# Set up Hoe plugins +Hoe.plugin :mercurial +Hoe.plugin :signing +Hoe.plugin :deveiate +Hoe.plugin :bundler + +Hoe.plugins.delete :rubyforge +Hoe.plugins.delete :compiler + +load 'Rakefile.cross' + + +# Hoe specification +$hoespec = Hoe.spec 'pg' do + self.readme_file = 'README.rdoc' + self.history_file = 'History.rdoc' + self.extra_rdoc_files = Rake::FileList[ '*.rdoc' ] + self.extra_rdoc_files.include( 'POSTGRES', 'LICENSE' ) + self.extra_rdoc_files.include( 'ext/*.c' ) + self.license :BSD + + self.developer 'Michael Granger', 'ged@FaerieMUD.org' + self.developer 'Lars Kanis', 'lars@greiz-reinsdorf.de' + + self.dependency 'rake-compiler', '~> 0.9', :developer + self.dependency 'rake-compiler-dock', '~> 0.3', :developer + self.dependency 'hoe', '~> 3.12', :developer + self.dependency 'hoe-deveiate', '~> 0.6', :developer + self.dependency 'hoe-bundler', '~> 1.0', :developer + self.dependency 'rspec', '~> 3.0', :developer + + self.spec_extras[:licenses] = ['BSD', 'Ruby', 'GPL'] + self.spec_extras[:extensions] = [ 'ext/extconf.rb' ] + + self.require_ruby_version( '>= 1.9.3' ) + + self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= ) + self.check_history_on_release = true if self.respond_to?( :check_history_on_release= ) + + self.rdoc_locations << "deveiate:/usr/local/www/public/code/#{remote_rdoc_dir}" +end + +ENV['VERSION'] ||= $hoespec.spec.version.to_s + +# Tests should pass before checking in +task 'hg:precheckin' => [ :check_history, :check_manifest, :spec ] + +# Support for 'rvm specs' +task :specs => :spec + +# Compile before testing +task :spec => :compile + +# gem-testers support +task :test do + # rake-compiler always wants to copy the compiled extension into lib/, but + # we don't want testers to have to re-compile, especially since that + # often fails because they can't (and shouldn't have to) write to tmp/ in + # the installed gem dir. So we clear the task rake-compiler set up + # to break the dependency between :spec and :compile when running under + # rubygems-test, and then run :spec. + Rake::Task[ EXT.to_s ].clear + Rake::Task[ :spec ].execute +end + +desc "Turn on warnings and debugging in the build." +task :maint do + ENV['MAINTAINER_MODE'] = 'yes' +end + +ENV['RUBY_CC_VERSION'] ||= '1.8.7:1.9.2:2.0.0' + +# Rake-compiler task +Rake::ExtensionTask.new do |ext| + ext.name = 'pg_ext' + ext.gem_spec = $hoespec.spec + ext.ext_dir = 'ext' + ext.lib_dir = 'lib' + ext.source_pattern = "*.{c,h}" + ext.cross_compile = true + ext.cross_platform = CrossLibraries.map &:for_platform + + ext.cross_config_options += CrossLibraries.map do |lib| + { + lib.for_platform => [ + "--enable-windows-cross", + "--with-pg-include=#{lib.static_postgresql_incdir}", + "--with-pg-lib=#{lib.static_postgresql_libdir}", + # libpq-fe.h resides in src/interfaces/libpq/ before make install + "--with-opt-include=#{lib.static_postgresql_libdir}", + ] + } + end + + # Add libpq.dll to windows binary gemspec + ext.cross_compiling do |spec| + # mingw32-platform strings differ (RUBY_PLATFORM=i386-mingw32 vs. x86-mingw32 for rubygems) + spec.files << "lib/#{spec.platform.to_s.gsub(/^x86-/, "i386-")}/libpq.dll" + end +end + + +# Use the fivefish formatter for docs generated from development checkout +if File.directory?( '.hg' ) + require 'rdoc/task' + + Rake::Task[ 'docs' ].clear + RDoc::Task.new( 'docs' ) do |rdoc| + rdoc.main = "README.rdoc" + rdoc.rdoc_files.include( "*.rdoc", "ChangeLog", "lib/**/*.rb", 'ext/**/*.{c,h}' ) + rdoc.generator = :fivefish + rdoc.title = "PG: The Ruby PostgreSQL Driver" + rdoc.rdoc_dir = 'doc' + end +end + + +# Make the ChangeLog update if the repo has changed since it was last built +file '.hg/branch' do + warn "WARNING: You need the Mercurial repo to update the ChangeLog" +end +file 'ChangeLog' do |task| + if File.exist?('.hg/branch') + $stderr.puts "Updating the changelog..." + begin + include Hoe::MercurialHelpers + content = make_changelog() + rescue NameError + abort "Packaging tasks require the hoe-mercurial plugin (gem install hoe-mercurial)" + end + File.open( task.name, 'w', 0644 ) do |fh| + fh.print( content ) + end + else + touch 'ChangeLog' + end +end + +# Rebuild the ChangeLog immediately before release +task :prerelease => 'ChangeLog' + + +desc "Stop any Postmaster instances that remain after testing." +task :cleanup_testing_dbs do + require 'spec/lib/helpers' + PgTestingHelpers.stop_existing_postmasters() + Rake::Task[:clean].invoke +end + +desc "Update list of server error codes" +task :update_error_codes do + URL_ERRORCODES_TXT = "http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob_plain;f=src/backend/utils/errcodes.txt;hb=HEAD" + + ERRORCODES_TXT = "ext/errorcodes.txt" + sh "wget #{URL_ERRORCODES_TXT.inspect} -O #{ERRORCODES_TXT.inspect} || curl #{URL_ERRORCODES_TXT.inspect} -o #{ERRORCODES_TXT.inspect}" +end + +file 'ext/errorcodes.def' => ['ext/errorcodes.rb', 'ext/errorcodes.txt'] do + ruby 'ext/errorcodes.rb', 'ext/errorcodes.txt', 'ext/errorcodes.def' +end + +file 'ext/pg_errors.c' => ['ext/errorcodes.def'] do + # trigger compilation of changed errorcodes.def + touch 'ext/pg_errors.c' +end + +task :gemspec => GEMSPEC +file GEMSPEC => __FILE__ +task GEMSPEC do |task| + spec = $hoespec.spec + spec.files.delete( '.gemtest' ) + spec.version = "#{spec.version}.pre#{Time.now.strftime("%Y%m%d%H%M%S")}" + File.open( task.name, 'w' ) do |fh| + fh.write( spec.to_ruby ) + end +end + +CLOBBER.include( GEMSPEC.to_s ) +task :default => :gemspec + diff --git a/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/specifications/dalli-2.7.5.gemspec b/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/specifications/dalli-2.7.5.gemspec new file mode 100644 index 000000000..8db8be505 --- /dev/null +++ b/dependency-check-core/src/test/resources/ruby/vulnerable/gems/rails-4.1.15/vendor/bundle/ruby/2.2.0/specifications/dalli-2.7.5.gemspec @@ -0,0 +1,54 @@ +# -*- encoding: utf-8 -*- +# stub: dalli 2.7.5 ruby lib + +Gem::Specification.new do |s| + s.name = "dalli" + s.version = "2.7.5" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.require_paths = ["lib"] + s.authors = ["Peter M. Goldstein", "Mike Perham"] + s.date = "2015-12-16" + s.description = "High performance memcached client for Ruby" + s.email = ["peter.m.goldstein@gmail.com", "mperham@gmail.com"] + s.homepage = "https://github.com/petergoldstein/dalli" + s.licenses = ["MIT"] + s.rdoc_options = ["--charset=UTF-8"] + s.rubygems_version = "2.5.0" + s.summary = "High performance memcached client for Ruby" + + s.installed_by_version = "2.5.0" if s.respond_to? :installed_by_version + + if s.respond_to? :specification_version then + s.specification_version = 4 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + s.add_development_dependency(%q, [">= 4.2.0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, ["~> 4"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + s.add_development_dependency(%q, [">= 0"]) + else + s.add_dependency(%q, [">= 4.2.0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, ["~> 4"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + end + else + s.add_dependency(%q, [">= 4.2.0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, ["~> 4"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) + end +end