Skip to content

Commit 4332b0b

Browse files
authored
fix(trivy_operator): fix compliance severity logic and checkID comparison (#14359)
Fix two bugs in the Trivy Operator parser: 1. compliance_handler.py: The severity selection logic was inverted - it attempted to use check_severity when it was empty (causing KeyError) and fell back to result_severity when check_severity was present. Fixed to correctly prefer check-level severity, falling back to result-level severity when the check has no severity. 2. checks_handler.py: The checkID comparison used integer 0 instead of string "0", so `check_id != 0` was always True (string vs int). This caused bogus reference URLs and vulnerability IDs to be generated for checks without a checkID. Also changed from `check.get("checkID", "0")` to `check.get("checkID") or "0"` to handle explicit null values in JSON. Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
1 parent ba4dcfc commit 4332b0b

5 files changed

Lines changed: 152 additions & 8 deletions

File tree

dojo/tools/trivy_operator/checks_handler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def handle_checks(self, labels, checks, test):
2323
for check in checks:
2424
check_title = check.get("title")
2525
check_severity = TRIVY_SEVERITIES[check.get("severity")]
26-
check_id = check.get("checkID", "0")
26+
check_id = check.get("checkID") or "0"
2727
check_references = ""
28-
if check_id != 0:
28+
if check_id != "0":
2929
check_references = (
3030
"https://avd.aquasec.com/misconfig/kubernetes/"
3131
+ check_id.lower()
@@ -49,7 +49,7 @@ def handle_checks(self, labels, checks, test):
4949
)
5050
if resource_namespace:
5151
finding.unsaved_tags = [resource_namespace]
52-
if check_id:
52+
if check_id != "0":
5353
finding.unsaved_vulnerability_ids = [UniformTrivyVulnID().return_uniformed_vulnid(check_id)]
5454
findings.append(finding)
5555
return findings

dojo/tools/trivy_operator/compliance_handler.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ def handle_compliance(self, benchmarkreport, test):
3131
check_severity = check.get("severity", "")
3232
check_target = check.get("target", "")
3333
check_title = check.get("title", "")
34-
if not check_severity:
35-
severity = TRIVY_SEVERITIES[check_severity]
36-
else:
37-
severity = TRIVY_SEVERITIES[result_severity]
34+
severity = TRIVY_SEVERITIES[check_severity] if check_severity else TRIVY_SEVERITIES[result_severity]
3835
description += "**result description:** " + result_description + "\n"
3936
description += "**result id:** " + result_id + "\n"
4037
description += "**result name:** " + result_name + "\n"
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"apiVersion": "aquasecurity.github.io/v1alpha1",
3+
"kind": "ClusterComplianceReport",
4+
"metadata": {
5+
"creationTimestamp": "2024-03-05T10:38:15Z",
6+
"generation": 1,
7+
"labels": {
8+
"app.kubernetes.io/instance": "trivy-operator",
9+
"app.kubernetes.io/managed-by": "kubectl",
10+
"app.kubernetes.io/name": "trivy-operator",
11+
"app.kubernetes.io/version": "0.18.5"
12+
},
13+
"name": "cis",
14+
"resourceVersion": "1649372",
15+
"uid": "test-compliance-severity"
16+
},
17+
"spec": {
18+
"compliance": {
19+
"controls": [],
20+
"description": "Test Compliance Severity",
21+
"id": "test",
22+
"title": "Test Compliance Severity Report",
23+
"version": "1.0"
24+
},
25+
"cron": "0 */6 * * *",
26+
"reportType": "all"
27+
},
28+
"status": {
29+
"detailReport": {
30+
"description": "Test report for compliance severity logic",
31+
"id": "test",
32+
"relatedResources": [],
33+
"results": [
34+
{
35+
"checks": [
36+
{
37+
"category": "Kubernetes Security Check",
38+
"checkID": "AVD-KSV-0001",
39+
"description": "Check with its own severity",
40+
"messages": [
41+
"Test message 1"
42+
],
43+
"remediation": "Fix it",
44+
"severity": "MEDIUM",
45+
"success": false,
46+
"target": "/test-target-1",
47+
"title": "Check with severity"
48+
},
49+
{
50+
"category": "Kubernetes Security Check",
51+
"checkID": "AVD-KSV-0002",
52+
"description": "Check without severity",
53+
"messages": [
54+
"Test message 2"
55+
],
56+
"remediation": "Fix it too",
57+
"severity": "",
58+
"success": false,
59+
"target": "/test-target-2",
60+
"title": "Check without severity"
61+
}
62+
],
63+
"description": "Test result",
64+
"id": "1.1.1",
65+
"name": "Test result name",
66+
"severity": "HIGH"
67+
}
68+
],
69+
"title": "Test Compliance Severity Report",
70+
"version": "1.0"
71+
},
72+
"summary": {
73+
"failCount": 2,
74+
"passCount": 0
75+
},
76+
"updateTimestamp": "2024-03-05T10:38:15Z"
77+
}
78+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"apiVersion": "aquasecurity.github.io/v1alpha1",
3+
"kind": "ConfigAuditReport",
4+
"metadata": {
5+
"annotations": {
6+
"trivy-operator.aquasecurity.github.io/report-ttl": "24h0m0s"
7+
},
8+
"creationTimestamp": "2023-03-23T16:22:54Z",
9+
"generation": 1,
10+
"labels": {
11+
"plugin-config-hash": "659b7b9c46",
12+
"resource-spec-hash": "fc85b485f",
13+
"trivy-operator.resource.kind": "ReplicaSet",
14+
"trivy-operator.resource.name": "test-deployment-12345",
15+
"trivy-operator.resource.namespace": "default"
16+
},
17+
"name": "replicaset-test-deployment-12345",
18+
"namespace": "default",
19+
"resourceVersion": "1268",
20+
"uid": "test-missing-checkid"
21+
},
22+
"report": {
23+
"checks": [
24+
{
25+
"category": "Kubernetes Security Check",
26+
"description": "A check without a checkID field",
27+
"messages": [
28+
"Container 'test' of ReplicaSet 'test-deployment-12345' has an issue"
29+
],
30+
"severity": "MEDIUM",
31+
"success": false,
32+
"title": "Missing checkID test"
33+
}
34+
],
35+
"scanner": {
36+
"name": "Trivy",
37+
"vendor": "Aqua Security",
38+
"version": "dev"
39+
},
40+
"summary": {
41+
"criticalCount": 0,
42+
"highCount": 0,
43+
"lowCount": 0,
44+
"mediumCount": 1
45+
},
46+
"updateTimestamp": "2023-03-23T16:22:54Z"
47+
}
48+
}

unittests/tools/test_trivy_operator_parser.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def test_cis_benchmark(self):
138138
self.assertEqual(len(findings), 795)
139139
finding = findings[0]
140140
self.assertEqual("5.1.2 AVD-KSV-0041 /clusterrole-admin", finding.title)
141-
self.assertEqual("High", finding.severity)
141+
self.assertEqual("Critical", finding.severity)
142142
self.assertEqual(1, len(finding.unsaved_vulnerability_ids))
143143
self.assertEqual("AVD-KSV-0041", finding.unsaved_vulnerability_ids[0])
144144
finding = findings[40]
@@ -169,3 +169,24 @@ def test_findings_clustercompliancereport(self):
169169
parser = TrivyOperatorParser()
170170
findings = parser.get_findings(test_file, Test())
171171
self.assertEqual(len(findings), 2)
172+
173+
def test_compliance_severity_logic(self):
174+
with sample_path("compliance_severity.json").open(encoding="utf-8") as test_file:
175+
parser = TrivyOperatorParser()
176+
findings = parser.get_findings(test_file, Test())
177+
self.assertEqual(len(findings), 2)
178+
# First check has severity MEDIUM, result has severity HIGH -> uses check's MEDIUM
179+
self.assertEqual("Medium", findings[0].severity)
180+
# Second check has empty severity, result has severity HIGH -> falls back to HIGH
181+
self.assertEqual("High", findings[1].severity)
182+
183+
def test_configauditreport_missing_checkid(self):
184+
with sample_path("configauditreport_missing_checkid.json").open(encoding="utf-8") as test_file:
185+
parser = TrivyOperatorParser()
186+
findings = parser.get_findings(test_file, Test())
187+
self.assertEqual(len(findings), 1)
188+
finding = findings[0]
189+
self.assertEqual("Medium", finding.severity)
190+
self.assertEqual("0 - Missing checkID test", finding.title)
191+
# When checkID is "0", references should be empty (not a bogus URL)
192+
self.assertEqual("", finding.references)

0 commit comments

Comments
 (0)