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