|
8 | 8 |
|
9 | 9 |
|
10 | 10 | from django.apps import apps |
| 11 | +from django.db.models import Exists |
| 12 | +from django.db.models import OuterRef |
11 | 13 |
|
12 | 14 | # VulnerabilityAnalysis states that indicate a vulnerability has been triaged and addressed. |
13 | 15 | TERMINAL_VULNERABILITY_STATES = ["resolved", "resolved_with_pedigree", "not_affected"] |
@@ -132,11 +134,47 @@ def count_violations(self, product, threshold, parameters): |
132 | 134 | return count if count > threshold else 0 |
133 | 135 |
|
134 | 136 |
|
| 137 | +class UnresolvedVulnerabilityCountRule(BaseRule): |
| 138 | + rule_type = "unresolved_vulnerability_count" |
| 139 | + label = "Unresolved Vulnerability Count" |
| 140 | + severity = "warning" |
| 141 | + description = ( |
| 142 | + "Counts individual package-vulnerability links in the product that have not been " |
| 143 | + "addressed via a VulnerabilityAnalysis with a terminal state " |
| 144 | + "(resolved, resolved_with_pedigree, or not_affected)." |
| 145 | + ) |
| 146 | + |
| 147 | + def count_violations(self, product, threshold, parameters): |
| 148 | + PackageAffectedByVulnerability = apps.get_model( |
| 149 | + "component_catalog", "packageaffectedbyvulnerability" |
| 150 | + ) |
| 151 | + VulnerabilityAnalysis = apps.get_model("vulnerabilities", "vulnerabilityanalysis") |
| 152 | + |
| 153 | + terminal_analysis = VulnerabilityAnalysis.objects.filter( |
| 154 | + product=product, |
| 155 | + state__in=TERMINAL_VULNERABILITY_STATES, |
| 156 | + package=OuterRef("package"), |
| 157 | + vulnerability=OuterRef("vulnerability"), |
| 158 | + ) |
| 159 | + |
| 160 | + count = ( |
| 161 | + PackageAffectedByVulnerability.objects.filter( |
| 162 | + package__productpackages__product=product, |
| 163 | + ) |
| 164 | + .annotate(has_terminal_analysis=Exists(terminal_analysis)) |
| 165 | + .filter(has_terminal_analysis=False) |
| 166 | + .distinct() |
| 167 | + .count() |
| 168 | + ) |
| 169 | + return count if count > threshold else 0 |
| 170 | + |
| 171 | + |
135 | 172 | RULE_REGISTRY = { |
136 | 173 | UsagePolicyErrorRule.rule_type: UsagePolicyErrorRule(), |
137 | 174 | UsagePolicyWarningRule.rule_type: UsagePolicyWarningRule(), |
138 | 175 | LicensePolicyErrorRule.rule_type: LicensePolicyErrorRule(), |
139 | 176 | LicensePolicyWarningRule.rule_type: LicensePolicyWarningRule(), |
140 | 177 | LicenseCoverageGapRule.rule_type: LicenseCoverageGapRule(), |
141 | 178 | VulnerabilityDetectedRule.rule_type: VulnerabilityDetectedRule(), |
| 179 | + UnresolvedVulnerabilityCountRule.rule_type: UnresolvedVulnerabilityCountRule(), |
142 | 180 | } |
0 commit comments