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) 2022 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.analyzer;
19  
20  import java.util.List;
21  import org.owasp.dependencycheck.Engine;
22  import static org.owasp.dependencycheck.analyzer.AbstractSuppressionAnalyzer.SUPPRESSION_OBJECT_KEY;
23  import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
24  import org.owasp.dependencycheck.dependency.Dependency;
25  import org.owasp.dependencycheck.utils.Settings;
26  import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
27  import org.slf4j.Logger;
28  import org.slf4j.LoggerFactory;
29  
30  /**
31   * Log the unused suppression rules.
32   *
33   * @author Jeremy Long
34   */
35  public class UnusedSuppressionRuleAnalyzer extends AbstractAnalyzer {
36  	protected static final String EXCEPTION_MSG = "There are %d unused suppression rule(s): check logs.";
37  	
38      /**
39       * The Logger for use throughout the class.
40       */
41      private static final Logger LOGGER = LoggerFactory.getLogger(UnusedSuppressionRuleAnalyzer.class);
42      /**
43       * A flag indicating whether or not the unused vulnerabilities have already
44       * been reported.
45       */
46      private boolean reported = false;
47      /**
48       * A flag indicating whether build should fail on unused suppression rule
49       */
50      private boolean shouldFailForUnusedSuppressionRule = false;
51      /**
52       * unused suppression rule count
53       */
54      private int unusedSuppressionRuleCount = 0;
55  
56      @Override
57      public synchronized void initialize(Settings settings) {
58          super.initialize(settings);
59  		if (settings.getBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, false)) {
60  			this.shouldFailForUnusedSuppressionRule = true;
61  		}
62  	}
63  
64      @Override
65      protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
66          if (!reported) {
67  			checkUnusedRules(engine);
68  			reported = true;
69  			if(unusedSuppressionRuleCount > 0 && failsForUnusedSuppressionRule()) {
70  				final String message = String.format(EXCEPTION_MSG, unusedSuppressionRuleCount);
71  				LOGGER.error(message);
72  				throw new AnalysisException(message);
73  			}
74          }
75      }
76  
77      /**
78       * check unused suppression RULES.
79       *
80       * @param engine a reference to the ODC engine
81       */
82      protected void checkUnusedRules(Engine engine) {
83          if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
84              @SuppressWarnings("unchecked")
85              final List<SuppressionRule> rules = (List<SuppressionRule>) engine.getObject(SUPPRESSION_OBJECT_KEY);
86              rules.forEach((rule) -> {
87                  if (!rule.isMatched() && !rule.isBase()) {
88  					final String message = String.format("Suppression Rule had zero matches: %s", rule);
89                      if(failsForUnusedSuppressionRule()) {
90  						LOGGER.error(message);
91  					} else {
92  						LOGGER.info(message);
93  					}
94  					increaseUnusedSuppressionRuleCount();
95                  }
96              });
97          }
98      }
99  
100     @Override
101     protected String getAnalyzerEnabledSettingKey() {
102         //technically incorrect - but we will reuse the enabled key for this analyzer
103         return Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED;
104     }
105 
106     @Override
107     public String getName() {
108         return "Unused Suppression Rule Analyzer";
109     }
110 
111     @Override
112     public AnalysisPhase getAnalysisPhase() {
113         return AnalysisPhase.FINAL;
114     }
115 
116     @Override
117     public boolean supportsParallelProcessing() {
118         return false;
119     }
120 	
121 	/**
122 	* increases the count of unused suppression rules
123 	*/
124 	public void increaseUnusedSuppressionRuleCount() {
125 		unusedSuppressionRuleCount++;
126 	}
127 	
128 	/**
129 	* @return the count of unused suppression rules
130 	*/
131 	public int getUnusedSuppressionRuleCount() {
132 		return unusedSuppressionRuleCount;
133 	}
134 	
135 	/**
136 	* @return whether the analyzer will fail for a unused suppression rule
137 	*/
138 	public boolean failsForUnusedSuppressionRule() {
139 		return shouldFailForUnusedSuppressionRule;
140 	}
141 }