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             assertTrue(size >= 1);
121 
122             Dependency dependency = engine.getDependencies().get(0);
123             assertTrue(dependency.getProductEvidence().toString().toLowerCase().contains("redcarpet"));
124             assertTrue(dependency.getVersionEvidence().toString().toLowerCase().contains("2.2.2"));
125             assertTrue(dependency.getFilePath().endsWith(resource));
126             assertTrue(dependency.getFileName().equals("Gemfile.lock"));
127         } catch (Exception e) {
128             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\".");
129             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", e);
130         }
131     }
132 
133     /**
134      * Test Ruby addCriticalityToVulnerability
135      */
136     @Test
137     public void testAddCriticalityToVulnerability() throws AnalysisException, DatabaseException {
138         try {
139             analyzer.initialize();
140 
141             final Dependency result = new Dependency(BaseTest.getResourceAsFile(this,
142                     "ruby/vulnerable/gems/sinatra/Gemfile.lock"));
143             final Engine engine = new Engine();
144             analyzer.analyze(result, engine);
145 
146             Dependency dependency = engine.getDependencies().get(0);
147             Vulnerability vulnerability = dependency.getVulnerabilities().first();
148             assertEquals(vulnerability.getCvssScore(), 5.0f, 0.0);
149 
150         } catch (Exception e) {
151             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\".");
152             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", e);
153         }
154     }
155 
156     /**
157      * Test when Ruby bundle-audit is not available on the system.
158      *
159      * @throws AnalysisException is thrown when an exception occurs.
160      */
161     @Test
162     public void testMissingBundleAudit() throws AnalysisException, DatabaseException {
163         //set a non-exist bundle-audit
164         Settings.setString(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, "phantom-bundle-audit");
165         try {
166             //initialize should fail.
167             analyzer.initialize();
168         } catch (Exception e) {
169             //expected, so ignore.
170         } finally {
171             assertThat(analyzer.isEnabled(), is(false));
172             LOGGER.info("phantom-bundle-audit is not available. Ruby Bundle Audit Analyzer is disabled as expected.");
173         }
174     }
175 
176     /**
177      * Test Ruby dependencies and their paths.
178      *
179      * @throws AnalysisException is thrown when an exception occurs.
180      * @throws DatabaseException thrown when an exception occurs
181      */
182     @Test
183     public void testDependenciesPath() throws AnalysisException, DatabaseException {
184         final Engine engine = new Engine();
185         engine.scan(BaseTest.getResourceAsFile(this,
186                 "ruby/vulnerable/gems/rails-4.1.15/"));
187         try {
188             engine.analyzeDependencies();
189         } catch (NullPointerException ex) {
190             LOGGER.error("NPE", ex);
191             throw ex;
192         } catch (ExceptionCollection ex) {
193             Assume.assumeNoException("Exception setting up RubyBundleAuditAnalyzer; bundle audit may not be installed, or property \"analyzer.bundle.audit.path\" may not be set.", ex);
194         }
195         List<Dependency> dependencies = engine.getDependencies();
196         LOGGER.info(dependencies.size() + " dependencies found.");
197         Iterator<Dependency> dIterator = dependencies.iterator();
198         while (dIterator.hasNext()) {
199             Dependency dept = dIterator.next();
200             LOGGER.info("dept path: " + dept.getActualFilePath());
201 
202             Set<Identifier> identifiers = dept.getIdentifiers();
203             Iterator<Identifier> idIterator = identifiers.iterator();
204             while (idIterator.hasNext()) {
205                 Identifier id = idIterator.next();
206                 LOGGER.info("  Identifier: " + id.getValue() + ", type=" + id.getType() + ", url=" + id.getUrl() + ", conf=" + id.getConfidence());
207             }
208 
209             Set<Evidence> prodEv = dept.getProductEvidence().getEvidence();
210             Iterator<Evidence> it = prodEv.iterator();
211             while (it.hasNext()) {
212                 Evidence e = it.next();
213                 LOGGER.info("  prod: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
214             }
215             Set<Evidence> versionEv = dept.getVersionEvidence().getEvidence();
216             Iterator<Evidence> vIt = versionEv.iterator();
217             while (vIt.hasNext()) {
218                 Evidence e = vIt.next();
219                 LOGGER.info("  version: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
220             }
221 
222             Set<Evidence> vendorEv = dept.getVendorEvidence().getEvidence();
223             Iterator<Evidence> vendorIt = vendorEv.iterator();
224             while (vendorIt.hasNext()) {
225                 Evidence e = vendorIt.next();
226                 LOGGER.info("  vendor: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence());
227             }
228         }
229     }
230 }