1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
32
33
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
40
41 private static final Logger LOGGER = LoggerFactory.getLogger(UnusedSuppressionRuleAnalyzer.class);
42
43
44
45
46 private boolean reported = false;
47
48
49
50 private boolean shouldFailForUnusedSuppressionRule = false;
51
52
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
79
80
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
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
123
124 public void increaseUnusedSuppressionRuleCount() {
125 unusedSuppressionRuleCount++;
126 }
127
128
129
130
131 public int getUnusedSuppressionRuleCount() {
132 return unusedSuppressionRuleCount;
133 }
134
135
136
137
138 public boolean failsForUnusedSuppressionRule() {
139 return shouldFailForUnusedSuppressionRule;
140 }
141 }