View Javadoc
1   /*
2    * This file is part of dependency-check-core.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2015 Institute for Defense Analyses. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.analyzer;
19  
20  import static org.hamcrest.CoreMatchers.is;
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertThat;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.File;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Set;
29  import java.util.logging.Level;
30  
31  import org.junit.After;
32  import org.junit.Assume;
33  import org.junit.Before;
34  import org.junit.Test;
35  import org.owasp.dependencycheck.BaseDBTestCase;
36  import org.owasp.dependencycheck.BaseTest;
37  import org.owasp.dependencycheck.Engine;
38  import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
39  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
40  import org.owasp.dependencycheck.dependency.Dependency;
41  import org.owasp.dependencycheck.dependency.Evidence;
42  import org.owasp.dependencycheck.dependency.Identifier;
43  import org.owasp.dependencycheck.dependency.Vulnerability;
44  import org.owasp.dependencycheck.exception.ExceptionCollection;
45  import org.owasp.dependencycheck.utils.Settings;
46  import org.slf4j.Logger;
47  import org.slf4j.LoggerFactory;
48  
49  /**
50   * Unit tests for {@link RubyBundleAuditAnalyzer}.
51   *
52   * @author Dale Visser
53   */
54  public class RubyBundleAuditAnalyzerTest extends BaseDBTestCase {
55  
56      private static final Logger LOGGER = LoggerFactory.getLogger(RubyBundleAuditAnalyzerTest.class);
57  
58      /**
59       * The analyzer to test.
60       */
61      RubyBundleAuditAnalyzer analyzer;
62  
63      /**
64       * Correctly setup the analyzer for testing.
65       *
66       * @throws Exception thrown if there is a problem
67       */
68      @Override
69      @Before
70      public void setUp() throws Exception {
71          super.setUp();
72          Settings.setBoolean(Settings.KEYS.AUTO_UPDATE, false);
73          Settings.setBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED, false);
74          Settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, false);
75          analyzer = new RubyBundleAuditAnalyzer();
76          analyzer.setFilesMatched(true);
77      }
78  
79      /**
80       * Cleanup the analyzer's temp files, etc.
81       *
82       * @throws Exception thrown if there is a problem
83       */
84      @After
85      public void tearDown() throws Exception {
86          analyzer.close();
87          analyzer = null;
88      }
89  
90      /**
91       * Test Ruby Gemspec name.
92       */
93      @Test
94      public void testGetName() {
95          assertThat(analyzer.getName(), is("Ruby Bundle Audit Analyzer"));
96      }
97  
98      /**
99       * Test Ruby Bundler Audit file support.
100      */
101     @Test
102     public void testSupportsFiles() {
103         assertThat(analyzer.accept(new File("Gemfile.lock")), is(true));
104     }
105 
106     /**
107      * Test Ruby BundlerAudit analysis.
108      *
109      * @throws AnalysisException is thrown when an exception occurs.
110      */
111     @Test
112     public void testAnalysis() throws AnalysisException, DatabaseException {
113         try {
114             analyzer.initialize();
115             final String resource = "ruby/vulnerable/gems/rails-4.1.15/Gemfile.lock";
116             final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, resource));
117             final Engine engine = new Engine();
118             analyzer.analyze(result, engine);
119             int size = engine.getDependencies().size();
120 
121             assertTrue(size >= 1);
122 
123             Dependency dependency = engine.getDependencies().get(0);
124             assertTrue(dependency.getProductEvidence().toString().toLowerCase().contains("redcarpet"));
125             assertTrue(dependency.getVersionEvidence().toString().toLowerCase().contains("2.2.2"));
126             assertTrue(dependency.getFilePath().endsWith(resource));
127             assertTrue(dependency.getFileName().equals("Gemfile.lock"));
128         } catch (Exception e) {
129             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\".");
130             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", e);
131         }
132     }
133 
134     /**
135      * Test Ruby addCriticalityToVulnerability
136      */
137     @Test
138     public void testAddCriticalityToVulnerability() throws AnalysisException, DatabaseException {
139         try {
140             analyzer.initialize();
141 
142             final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
143                     "ruby/vulnerable/gems/sinatra/Gemfile.lock"));
144             final Engine engine = new Engine();
145             analyzer.analyze(result, engine);
146 
147             Dependency dependency = engine.getDependencies().get(0);
148             Vulnerability vulnerability = dependency.getVulnerabilities().first();
149             assertEquals(vulnerability.getCvssScore(), 5.0f, 0.0);
150 
151         } catch (Exception e) {
152             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\".");
153             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", e);
154         }
155     }
156 
157     /**
158      * Test when Ruby bundle-audit is not available on the system.
159      *
160      * @throws AnalysisException is thrown when an exception occurs.
161      */
162     @Test
163     public void testMissingBundleAudit() throws AnalysisException, DatabaseException {
164         //set a non-exist bundle-audit
165         Settings.setString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, "phantom-bundle-audit");
166         try {
167             //initialize should fail.
168             analyzer.initialize();
169         } catch (Exception e) {
170             //expected, so ignore.
171         } finally {
172             assertThat(analyzer.isEnabled(), is(false));
173             LOGGER.info("phantom-bundle-audit is not available. Ruby Bundle Audit Analyzer is disabled as expected.");
174         }
175     }
176 
177     /**
178      * Test Ruby dependencies and their paths.
179      *
180      * @throws AnalysisException is thrown when an exception occurs.
181      * @throws DatabaseException thrown when an exception occurs
182      */
183     @Test
184     public void testDependenciesPath() throws AnalysisException, DatabaseException {
185         final Engine engine = new Engine();
186         engine.scan(BaseTest.getResourceAsFile(this,
187                 "ruby/vulnerable/gems/rails-4.1.15/"));
188         try {
189             engine.analyzeDependencies();
190         } catch (NullPointerException ex) {
191             LOGGER.error("NPE", ex);
192             throw ex;
193         } catch (ExceptionCollection ex) {
194             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", ex);
195         }
196         List<Dependency> dependencies = engine.getDependencies();
197         LOGGER.info(dependencies.size() + " dependencies found.");
198         Iterator<Dependency> dIterator = dependencies.iterator();
199         while (dIterator.hasNext()) {
200             Dependency dept = dIterator.next();
201             LOGGER.info("dept path: " + dept.getActualFilePath());
202 
203             Set<Identifier> identifiers = dept.getIdentifiers();
204             Iterator<Identifier> idIterator = identifiers.iterator();
205             while (idIterator.hasNext()) {
206                 Identifier id = idIterator.next();
207                 LOGGER.info("  Identifier: " + id.getValue() + ", type=" + id.getType() + ", url=" + id.getUrl() + ", conf=" + id.getConfidence());
208             }
209 
210             Set<Evidence> prodEv = dept.getProductEvidence().getEvidence();
211             Iterator<Evidence> it = prodEv.iterator();
212             while (it.hasNext()) {
213                 Evidence e = it.next();
214                 LOGGER.info("  prod: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
215             }
216             Set<Evidence> versionEv = dept.getVersionEvidence().getEvidence();
217             Iterator<Evidence> vIt = versionEv.iterator();
218             while (vIt.hasNext()) {
219                 Evidence e = vIt.next();
220                 LOGGER.info("  version: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
221             }
222 
223             Set<Evidence> vendorEv = dept.getVendorEvidence().getEvidence();
224             Iterator<Evidence> vendorIt = vendorEv.iterator();
225             while (vendorIt.hasNext()) {
226                 Evidence e = vendorIt.next();
227                 LOGGER.info("  vendor: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
228             }
229         }
230     }
231 }