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
37
38
39
40 protected static final String EXCEPTION_MSG = "There are %d unused suppression rule(s): check logs.";
41
42
43
44
45 private static final Logger LOGGER = LoggerFactory.getLogger(UnusedSuppressionRuleAnalyzer.class);
46
47
48
49
50 private boolean reported = false;
51
52
53
54 private boolean shouldFailForUnusedSuppressionRule = false;
55
56
57
58 private int unusedSuppressionRuleCount = 0;
59
60 @Override
61 public synchronized void initialize(Settings settings) {
62 super.initialize(settings);
63 if (settings.getBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, false)) {
64 this.shouldFailForUnusedSuppressionRule = true;
65 }
66 }
67
68 @Override
69 protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException {
70 if (!reported) {
71 checkUnusedRules(engine);
72 reported = true;
73 if (unusedSuppressionRuleCount > 0 && failsForUnusedSuppressionRule()) {
74 final String message = String.format(EXCEPTION_MSG, unusedSuppressionRuleCount);
75 LOGGER.error(message);
76 throw new AnalysisException(message);
77 }
78 }
79 }
80
81
82
83
84
85
86 protected void checkUnusedRules(Engine engine) {
87 if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) {
88 @SuppressWarnings("unchecked")
89 final List<SuppressionRule> rules = (List<SuppressionRule>) engine.getObject(SUPPRESSION_OBJECT_KEY);
90 rules.forEach((rule) -> {
91 if (!rule.isMatched() && !rule.isBase()) {
92 final String message = String.format("Suppression Rule had zero matches: %s", rule);
93 if (failsForUnusedSuppressionRule()) {
94 LOGGER.error(message);
95 } else {
96 LOGGER.info(message);
97 }
98 increaseUnusedSuppressionRuleCount();
99 }
100 });
101 }
102 }
103
104 @Override
105 protected String getAnalyzerEnabledSettingKey() {
106
107 return Settings.KEYS.ANALYZER_VULNERABILITY_SUPPRESSION_ENABLED;
108 }
109
110 @Override
111 public String getName() {
112 return "Unused Suppression Rule Analyzer";
113 }
114
115 @Override
116 public AnalysisPhase getAnalysisPhase() {
117 return AnalysisPhase.FINAL;
118 }
119
120 @Override
121 public boolean supportsParallelProcessing() {
122 return false;
123 }
124
125
126
127
128 public void increaseUnusedSuppressionRuleCount() {
129 unusedSuppressionRuleCount++;
130 }
131
132
133
134
135 public int getUnusedSuppressionRuleCount() {
136 return unusedSuppressionRuleCount;
137 }
138
139
140
141
142 public boolean failsForUnusedSuppressionRule() {
143 return shouldFailForUnusedSuppressionRule;
144 }
145 }