Skip to content

Commit 1b59140

Browse files
committed
🌱 add support for trivy SAST tool
Signed-off-by: Adam Korczynski <[email protected]>
1 parent 6a4529c commit 1b59140

File tree

8 files changed

+193
-6
lines changed

8 files changed

+193
-6
lines changed

checker/raw_result.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ const (
286286
PysaWorkflow SASTWorkflowType = "Pysa"
287287
// QodanaWorkflow represents a workflow that runs Qodana.
288288
QodanaWorkflow SASTWorkflowType = "Qodana"
289+
// TrivyWorkflow represents a workflow that runs Trivy.
290+
TrivyWorkflow SASTWorkflowType = "Trivy"
289291
)
290292

291293
// SASTWorkflow represents a SAST workflow.

checks/evaluation/sast_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,25 @@ func TestSAST(t *testing.T) {
160160
NumberOfInfo: 2,
161161
},
162162
},
163+
{
164+
name: "Trivy is installed, no other SAST tools are installed",
165+
findings: []finding.Finding{
166+
tool(checker.TrivyWorkflow),
167+
{
168+
Probe: sastToolRunsOnAllCommits.Probe,
169+
Outcome: finding.OutcomeTrue,
170+
Values: map[string]string{
171+
sastToolRunsOnAllCommits.AnalyzedPRsKey: "1",
172+
sastToolRunsOnAllCommits.TotalPRsKey: "3",
173+
},
174+
},
175+
},
176+
result: scut.TestReturn{
177+
Score: 10,
178+
NumberOfWarn: 0,
179+
NumberOfInfo: 2,
180+
},
181+
},
163182
}
164183
for _, tt := range tests {
165184
t.Run(tt.name, func(t *testing.T) {

checks/raw/sast.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var sastTools = map[string]bool{
4343
"lgtm-com": true,
4444
"sonarcloud": true,
4545
"sonarqubecloud": true,
46+
"aqua-security-trivy": true,
4647
}
4748

4849
var allowedConclusions = map[string]bool{"success": true, "neutral": true}
@@ -87,6 +88,12 @@ func SAST(c *checker.CheckRequest) (checker.SASTData, error) {
8788
}
8889
data.Workflows = append(data.Workflows, qodanaWorkflows...)
8990

91+
trivyWorkflows, err := getSastUsesWorkflows(c, "^aquasecurity/trivy-action$", checker.TrivyWorkflow)
92+
if err != nil {
93+
return data, err
94+
}
95+
data.Workflows = append(data.Workflows, trivyWorkflows...)
96+
9097
return data, nil
9198
}
9299

checks/raw/sast_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,29 @@ func TestSAST(t *testing.T) {
195195
},
196196
},
197197
},
198+
{
199+
name: "Has Trivy",
200+
files: []string{".github/workflows/github-trivy-workflow.yaml"},
201+
commits: []clients.Commit{
202+
{
203+
AssociatedMergeRequest: clients.PullRequest{
204+
Number: 1,
205+
},
206+
},
207+
},
208+
expected: checker.SASTData{
209+
Workflows: []checker.SASTWorkflow{
210+
{
211+
Type: checker.TrivyWorkflow,
212+
File: checker.File{
213+
Path: ".github/workflows/github-trivy-workflow.yaml",
214+
Offset: checker.OffsetDefault,
215+
Type: finding.FileTypeSource,
216+
},
217+
},
218+
},
219+
},
220+
},
198221
}
199222
for _, tt := range tests {
200223
t.Run(tt.name, func(t *testing.T) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: build
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
jobs:
8+
build:
9+
name: Build
10+
runs-on: ubuntu-24.04
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v3
14+
- name: Build an image from Dockerfile
15+
run: docker build -t docker.io/my-organization/my-app:${{ github.sha }} .
16+
- name: Run Trivy vulnerability scanner
17+
uses: aquasecurity/[email protected]
18+
with:
19+
image-ref: 'docker.io/my-organization/my-app:${{ github.sha }}'
20+
format: 'table'
21+
exit-code: '1'
22+
ignore-unfixed: true
23+
vuln-type: 'os,library'
24+
severity: 'CRITICAL,HIGH'

checks/sast_test.go

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ func Test_SAST(t *testing.T) {
7676
},
7777
},
7878
searchresult: clients.SearchResponse{},
79+
searchRequest: clients.SearchRequest{
80+
Query: "github/codeql-action/analyze",
81+
Path: "/.github/workflows",
82+
},
7983
checkRuns: []clients.CheckRun{
8084
{
8185
Status: "completed",
@@ -101,6 +105,10 @@ func Test_SAST(t *testing.T) {
101105
},
102106
},
103107
searchresult: clients.SearchResponse{},
108+
searchRequest: clients.SearchRequest{
109+
Query: "github/codeql-action/analyze",
110+
Path: "/.github/workflows",
111+
},
104112
checkRuns: []clients.CheckRun{
105113
{
106114
Status: "completed",
@@ -126,6 +134,10 @@ func Test_SAST(t *testing.T) {
126134
},
127135
},
128136
searchresult: clients.SearchResponse{},
137+
searchRequest: clients.SearchRequest{
138+
Query: "github/codeql-action/analyze",
139+
Path: "/.github/workflows",
140+
},
129141
checkRuns: []clients.CheckRun{
130142
{
131143
Status: "completed",
@@ -152,6 +164,10 @@ func Test_SAST(t *testing.T) {
152164
},
153165
},
154166
searchresult: clients.SearchResponse{},
167+
searchRequest: clients.SearchRequest{
168+
Query: "github/codeql-action/analyze",
169+
Path: "/.github/workflows",
170+
},
155171
checkRuns: []clients.CheckRun{
156172
{
157173
Status: "completed",
@@ -178,7 +194,11 @@ func Test_SAST(t *testing.T) {
178194
},
179195
},
180196
searchresult: clients.SearchResponse{},
181-
path: ".github/workflows/airflow-codeql-workflow.yaml",
197+
searchRequest: clients.SearchRequest{
198+
Query: "github/codeql-action/analyze",
199+
Path: "/.github/workflows",
200+
},
201+
path: ".github/workflows/airflow-codeql-workflow.yaml",
182202
expected: scut.TestReturn{
183203
Score: 7,
184204
NumberOfWarn: 1,
@@ -196,6 +216,10 @@ func Test_SAST(t *testing.T) {
196216
},
197217
},
198218
searchresult: clients.SearchResponse{},
219+
searchRequest: clients.SearchRequest{
220+
Query: "github/codeql-action/analyze",
221+
Path: "/.github/workflows",
222+
},
199223
checkRuns: []clients.CheckRun{
200224
{
201225
Status: "completed",
@@ -231,6 +255,10 @@ func Test_SAST(t *testing.T) {
231255
},
232256
},
233257
searchresult: clients.SearchResponse{},
258+
searchRequest: clients.SearchRequest{
259+
Query: "github/codeql-action/analyze",
260+
Path: "/.github/workflows",
261+
},
234262
checkRuns: []clients.CheckRun{
235263
{
236264
Status: "completed",
@@ -271,6 +299,10 @@ func Test_SAST(t *testing.T) {
271299
},
272300
},
273301
searchresult: clients.SearchResponse{},
302+
searchRequest: clients.SearchRequest{
303+
Query: "github/codeql-action/analyze",
304+
Path: "/.github/workflows",
305+
},
274306
checkRuns: []clients.CheckRun{
275307
{
276308
Status: "notCompletedForTestingOnly",
@@ -294,12 +326,51 @@ func Test_SAST(t *testing.T) {
294326
NumberOfInfo: 1,
295327
},
296328
},
329+
{
330+
name: `Trivy workflow with commits`,
331+
err: nil,
332+
commits: []clients.Commit{
333+
{
334+
AssociatedMergeRequest: clients.PullRequest{
335+
MergedAt: time.Now().Add(time.Hour - 1),
336+
},
337+
},
338+
{
339+
AssociatedMergeRequest: clients.PullRequest{
340+
MergedAt: time.Now().Add(time.Hour - 2),
341+
},
342+
},
343+
},
344+
searchresult: clients.SearchResponse{},
345+
searchRequest: clients.SearchRequest{
346+
Query: "github/aquasecurity/trivy-action",
347+
Path: "/.github/workflows",
348+
},
349+
checkRuns: []clients.CheckRun{
350+
{
351+
Status: "completed",
352+
Conclusion: "success",
353+
App: clients.CheckRunApp{
354+
Slug: "aqua-security-trivy",
355+
},
356+
},
357+
{
358+
Status: "completed",
359+
Conclusion: "success",
360+
App: clients.CheckRunApp{
361+
Slug: "aqua-security-trivy",
362+
},
363+
},
364+
},
365+
path: ".github/workflows/github-trivy-workflow.yaml",
366+
expected: scut.TestReturn{
367+
Score: checker.MaxResultScore,
368+
NumberOfDebug: 2,
369+
NumberOfInfo: 2,
370+
},
371+
},
297372
}
298373
for _, tt := range tests {
299-
searchRequest := clients.SearchRequest{
300-
Query: "github/codeql-action/analyze",
301-
Path: "/.github/workflows",
302-
}
303374
t.Run(tt.name, func(t *testing.T) {
304375
t.Parallel()
305376
ctrl := gomock.NewController(t)
@@ -311,7 +382,7 @@ func Test_SAST(t *testing.T) {
311382
return tt.commits, tt.err
312383
})
313384
mockRepoClient.EXPECT().ListCheckRunsForRef("").Return(tt.checkRuns, nil).AnyTimes()
314-
mockRepoClient.EXPECT().Search(searchRequest).Return(tt.searchresult, nil).AnyTimes()
385+
mockRepoClient.EXPECT().Search(tt.searchRequest).Return(tt.searchresult, nil).AnyTimes()
315386
mockRepoClient.EXPECT().ListFiles(gomock.Any()).DoAndReturn(
316387
func(predicate func(string) (bool, error)) ([]string, error) {
317388
if strings.Contains(tt.path, "pom") {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: build
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
jobs:
8+
build:
9+
name: Build
10+
runs-on: ubuntu-24.04
11+
steps:
12+
- name: Checkout code
13+
uses: actions/checkout@v3
14+
- name: Build an image from Dockerfile
15+
run: docker build -t docker.io/my-organization/my-app:${{ github.sha }} .
16+
- name: Run Trivy vulnerability scanner
17+
uses: aquasecurity/[email protected]
18+
with:
19+
image-ref: 'docker.io/my-organization/my-app:${{ github.sha }}'
20+
format: 'table'
21+
exit-code: '1'
22+
ignore-unfixed: true
23+
vuln-type: 'os,library'
24+
severity: 'CRITICAL,HIGH'

probes/sastToolConfigured/impl_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,17 @@ func Test_Run(t *testing.T) {
6767
{
6868
Type: checker.PysaWorkflow,
6969
},
70+
{
71+
Type: checker.TrivyWorkflow,
72+
},
7073
},
7174
},
7275
},
7376
outcomes: []finding.Outcome{
7477
finding.OutcomeTrue,
7578
finding.OutcomeTrue,
7679
finding.OutcomeTrue,
80+
finding.OutcomeTrue,
7781
},
7882
},
7983
}
@@ -148,6 +152,19 @@ func Test_Run_tools(t *testing.T) {
148152
},
149153
tools: []string{"Sonar", "Pysa"},
150154
},
155+
{
156+
name: "Trivy",
157+
raw: &checker.RawResults{
158+
SASTResults: checker.SASTData{
159+
Workflows: []checker.SASTWorkflow{
160+
{
161+
Type: checker.TrivyWorkflow,
162+
},
163+
},
164+
},
165+
},
166+
tools: []string{"Trivy"},
167+
},
151168
}
152169
for _, tt := range tests {
153170
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)