Skip to content

Commit 7e9a0fe

Browse files
authored
improve trivy operator slack template (#597)
1 parent 4682136 commit 7e9a0fe

File tree

1 file changed

+142
-18
lines changed

1 file changed

+142
-18
lines changed
Lines changed: 142 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,144 @@
11
package postee.trivyoperator.slack
22

3-
title:=sprintf("Trivy Operator %s Report for - %s", [input.kind, input.metadata.name])
4-
5-
result:= res {
6-
res:= [
7-
{ "type":"section",
8-
"text": {"type":"mrkdwn","text": sprintf("*CRITICAL:* %d", [input.report.summary.criticalCount])}},
9-
{ "type":"section",
10-
"text": {"type":"mrkdwn","text": sprintf("*HIGH:* %d", [input.report.summary.highCount])}},
11-
{ "type":"section",
12-
"text": {"type":"mrkdwn","text": sprintf("*MEDIUM:* %d", [input.report.summary.mediumCount])}},
13-
{ "type":"section",
14-
"text": {"type":"mrkdwn","text": sprintf("*LOW:* %d", [input.report.summary.lowCount])}},
15-
{ "type":"section",
16-
"text": {"type":"mrkdwn","text": sprintf("*UNKNOWN:* %d", [input.report.summary.unknownCount])}},
17-
{ "type":"section",
18-
"text": {"type":"mrkdwn","text": sprintf("*NONE:* %d", [input.report.summary.noneCount])}},
19-
]
20-
}
3+
import data.postee.flat_array #converts [[{...},{...}], [{...},{...}]] to [{...},{...},{...},{...}]
4+
import data.postee.with_default
5+
6+
############################################# Common functions ############################################
7+
8+
# render_sections split collection of cells provided to chunks of 5 rows each and wraps every chunk with section element
9+
render_sections(rows, caption, headers) = result {
10+
count(rows) > 0 # only if some vulnerabilities are found
11+
rows_and_header := array.concat(headers, rows)
12+
a := flat_array([s |
13+
# code below converts 2 dimension array like [[row1, row2, ... row5], ....]
14+
group_size := 10 #it's 5 but every row is represented by 2 items
15+
num_chunks := ceil(count(rows_and_header) / group_size) - 1
16+
indices := {b | b := numbers.range(0, num_chunks)[_] * group_size}
17+
some k
18+
fields := [array.slice(rows_and_header, i, i + group_size) | i := indices[_]][k]
19+
# builds markdown section based on slice
20+
21+
s := with_caption(fields, caption, k)
22+
])
23+
result := array.concat(a, [{"type": "divider"}])
24+
}
25+
26+
render_sections(rows, caption, headers) = [] { #do not render section if provided collection is empty
27+
count(rows) == 0
28+
}
29+
30+
with_caption(fields, caption, position) = s {
31+
position == 0
32+
s := [
33+
{
34+
"type": "section",
35+
"text": {
36+
"type": "mrkdwn",
37+
"text": caption,
38+
},
39+
},
40+
{
41+
"type": "section",
42+
"fields": fields,
43+
},
44+
]
45+
}
46+
with_caption(fields, caption, position) = s {
47+
position > 0
48+
s := [
49+
{
50+
"type": "section",
51+
"fields": fields,
52+
},
53+
]
54+
}
55+
56+
57+
###########################################################################################################
58+
59+
vln_list(severity) = l {
60+
# builds list of rows for section for the given severity
61+
some i
62+
vlnrb := [r |
63+
item := input.report.vulnerabilities[i]
64+
vlnname := item.vulnerabilityID
65+
66+
fxvrsn := with_default(item, "fixedVersion", "none")
67+
resource_name = with_default(item, "resource", "none")
68+
resource_version = with_default(item, "installedVersion", "none")
69+
url = with_default(item, "primaryLink","")
70+
item.severity == severity # only items with severity matched
71+
72+
r := [
73+
{"type": "mrkdwn", "text": sprintf("<%s|%s>",[url,vlnname])},
74+
{"type": "mrkdwn", "text": concat(" / ", [resource_name, resource_version, fxvrsn])},
75+
]
76+
]
77+
78+
caption := sprintf("*%s severity vulnerabilities*", [severity]) #TODO make first char uppercase
79+
80+
headers := [
81+
{"type": "mrkdwn", "text": "*Vulnerability ID*"},
82+
{"type": "mrkdwn", "text": "*Resource / Version / Fixed version*"},
83+
]
84+
85+
# split rows and wrap slices with markdown section
86+
l := render_sections(flat_array(vlnrb), caption, headers)
87+
}
88+
89+
image_name := sprintf("%s:%s", [
90+
with_default(input.report.artifact,"repository","unknown"),
91+
with_default(input.report.artifact,"tag","unknown")
92+
])
93+
###########################################################################################################
94+
postee := with_default(input, "postee", {})
95+
96+
title = sprintf("Vulnerability scan report %s", [image_name]) # title is
97+
98+
result = res {
99+
100+
header := [
101+
{
102+
"type": "header",
103+
"text": {
104+
"type": "plain_text",
105+
"text": sprintf("Vulnerability issue with image:%s in namespace %s",[image_name, with_default(input.metadata,"namespace","unknown")]),
106+
},
107+
}
108+
]
109+
110+
summary := [
111+
{
112+
"type": "divider"
113+
},
114+
{
115+
"type": "context",
116+
"elements": [
117+
{"type": "mrkdwn", "text": "*Summary totals:*"},
118+
],
119+
},
120+
{
121+
"type": "context",
122+
"elements": [
123+
{"type": "mrkdwn", "text": sprintf("Critical: *%d*", [input.report.summary.criticalCount])},
124+
{"type": "mrkdwn", "text": sprintf("High: *%d*", [input.report.summary.highCount])},
125+
{"type": "mrkdwn", "text": sprintf("Medium: *%d*", [input.report.summary.mediumCount])},
126+
{"type": "mrkdwn", "text": sprintf("Low: *%d*", [input.report.summary.lowCount])},
127+
{"type": "mrkdwn", "text": sprintf("Unknown: *%d*", [input.report.summary.unknownCount])},
128+
],
129+
},
130+
{
131+
"type": "divider"
132+
}
133+
]
134+
135+
res := flat_array([
136+
header,
137+
summary,
138+
vln_list("CRITICAL"),
139+
vln_list("HIGH"),
140+
vln_list("MEDIUM"),
141+
vln_list("LOW"),
142+
vln_list("UNKNOWN")
143+
])
144+
}

0 commit comments

Comments
 (0)