Skip to content

Commit 9c7e63d

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

File tree

8 files changed

+206
-8
lines changed

8 files changed

+206
-8
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+
// KicsWorkflow represents a workflow that runs KICS.
290+
KicsWorkflow SASTWorkflowType = "KICS"
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: "KICS is installed, no other SAST tools are installed",
165+
findings: []finding.Finding{
166+
tool(checker.KicsWorkflow),
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+
"kics-github-action": 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+
kicsWorkflows, err := getSastUsesWorkflows(c, "^Checkmarx/kics-github-action", checker.KicsWorkflow)
92+
if err != nil {
93+
return data, err
94+
}
95+
data.Workflows = append(data.Workflows, kicsWorkflows...)
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 KICS",
200+
files: []string{".github/workflows/github-kics-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.KicsWorkflow,
212+
File: checker.File{
213+
Path: ".github/workflows/github-kics-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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: "Security Scans"
2+
on:
3+
schedule:
4+
- cron: '0 3 * * 1' # run tests at 1 AM (UTC), every monday (1)
5+
workflow_dispatch:
6+
inputs:
7+
branch:
8+
description: 'Take CI build artifacts from branch (e.g., master, release-x.y.z)'
9+
required: true
10+
default: 'main'
11+
12+
# Declare default permissions as read only.
13+
permissions: read-all
14+
15+
defaults:
16+
run:
17+
shell: bash
18+
19+
env:
20+
GO_VERSION: "~1.23"
21+
22+
jobs:
23+
security-scans:
24+
steps:
25+
- name: KICS Scan
26+
if: matrix.tool == 'kics'
27+
uses: Checkmarx/kics-github-action@94469746ec2c43de89a42fb9d2a80070f5d25b16 # v2.1.3
28+
with:
29+
path: scans
30+
config_path: .github/kics-config.yml
31+
fail_on: high,medium
32+
output_formats: json,sarif

checks/sast_test.go

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ func Test_SAST(t *testing.T) {
4949
name: "SAST checker should return min score when no PRs are found",
5050
commits: []clients.Commit{},
5151
searchresult: clients.SearchResponse{},
52-
checkRuns: []clients.CheckRun{},
52+
searchRequest: clients.SearchRequest{
53+
Query: "github/codeql-action/analyze",
54+
Path: "/.github/workflows",
55+
},
56+
checkRuns: []clients.CheckRun{},
5357
expected: scut.TestReturn{
5458
Score: checker.MinResultScore,
5559
NumberOfWarn: 1,
@@ -60,7 +64,11 @@ func Test_SAST(t *testing.T) {
6064
err: errors.New("error"),
6165
commits: []clients.Commit{},
6266
searchresult: clients.SearchResponse{},
63-
checkRuns: []clients.CheckRun{},
67+
searchRequest: clients.SearchRequest{
68+
Query: "github/codeql-action/analyze",
69+
Path: "/.github/workflows",
70+
},
71+
checkRuns: []clients.CheckRun{},
6472
expected: scut.TestReturn{
6573
Score: checker.InconclusiveResultScore,
6674
Error: sce.ErrScorecardInternal,
@@ -76,6 +84,10 @@ func Test_SAST(t *testing.T) {
7684
},
7785
},
7886
searchresult: clients.SearchResponse{},
87+
searchRequest: clients.SearchRequest{
88+
Query: "github/codeql-action/analyze",
89+
Path: "/.github/workflows",
90+
},
7991
checkRuns: []clients.CheckRun{
8092
{
8193
Status: "completed",
@@ -101,6 +113,10 @@ func Test_SAST(t *testing.T) {
101113
},
102114
},
103115
searchresult: clients.SearchResponse{},
116+
searchRequest: clients.SearchRequest{
117+
Query: "github/codeql-action/analyze",
118+
Path: "/.github/workflows",
119+
},
104120
checkRuns: []clients.CheckRun{
105121
{
106122
Status: "completed",
@@ -126,6 +142,10 @@ func Test_SAST(t *testing.T) {
126142
},
127143
},
128144
searchresult: clients.SearchResponse{},
145+
searchRequest: clients.SearchRequest{
146+
Query: "github/codeql-action/analyze",
147+
Path: "/.github/workflows",
148+
},
129149
checkRuns: []clients.CheckRun{
130150
{
131151
Status: "completed",
@@ -152,6 +172,10 @@ func Test_SAST(t *testing.T) {
152172
},
153173
},
154174
searchresult: clients.SearchResponse{},
175+
searchRequest: clients.SearchRequest{
176+
Query: "github/codeql-action/analyze",
177+
Path: "/.github/workflows",
178+
},
155179
checkRuns: []clients.CheckRun{
156180
{
157181
Status: "completed",
@@ -178,7 +202,11 @@ func Test_SAST(t *testing.T) {
178202
},
179203
},
180204
searchresult: clients.SearchResponse{},
181-
path: ".github/workflows/airflow-codeql-workflow.yaml",
205+
searchRequest: clients.SearchRequest{
206+
Query: "github/codeql-action/analyze",
207+
Path: "/.github/workflows",
208+
},
209+
path: ".github/workflows/airflow-codeql-workflow.yaml",
182210
expected: scut.TestReturn{
183211
Score: 7,
184212
NumberOfWarn: 1,
@@ -196,6 +224,10 @@ func Test_SAST(t *testing.T) {
196224
},
197225
},
198226
searchresult: clients.SearchResponse{},
227+
searchRequest: clients.SearchRequest{
228+
Query: "github/codeql-action/analyze",
229+
Path: "/.github/workflows",
230+
},
199231
checkRuns: []clients.CheckRun{
200232
{
201233
Status: "completed",
@@ -231,6 +263,10 @@ func Test_SAST(t *testing.T) {
231263
},
232264
},
233265
searchresult: clients.SearchResponse{},
266+
searchRequest: clients.SearchRequest{
267+
Query: "github/codeql-action/analyze",
268+
Path: "/.github/workflows",
269+
},
234270
checkRuns: []clients.CheckRun{
235271
{
236272
Status: "completed",
@@ -271,6 +307,10 @@ func Test_SAST(t *testing.T) {
271307
},
272308
},
273309
searchresult: clients.SearchResponse{},
310+
searchRequest: clients.SearchRequest{
311+
Query: "github/codeql-action/analyze",
312+
Path: "/.github/workflows",
313+
},
274314
checkRuns: []clients.CheckRun{
275315
{
276316
Status: "notCompletedForTestingOnly",
@@ -294,12 +334,51 @@ func Test_SAST(t *testing.T) {
294334
NumberOfInfo: 1,
295335
},
296336
},
337+
{
338+
name: `KICS workflow with commits`,
339+
err: nil,
340+
commits: []clients.Commit{
341+
{
342+
AssociatedMergeRequest: clients.PullRequest{
343+
MergedAt: time.Now().Add(time.Hour - 1),
344+
},
345+
},
346+
{
347+
AssociatedMergeRequest: clients.PullRequest{
348+
MergedAt: time.Now().Add(time.Hour - 2),
349+
},
350+
},
351+
},
352+
searchresult: clients.SearchResponse{},
353+
searchRequest: clients.SearchRequest{
354+
Query: "github/Checkmarx/kics-github-action",
355+
Path: "/.github/workflows",
356+
},
357+
checkRuns: []clients.CheckRun{
358+
{
359+
Status: "completed",
360+
Conclusion: "success",
361+
App: clients.CheckRunApp{
362+
Slug: "kics-github-action",
363+
},
364+
},
365+
{
366+
Status: "completed",
367+
Conclusion: "success",
368+
App: clients.CheckRunApp{
369+
Slug: "kics-github-action",
370+
},
371+
},
372+
},
373+
path: ".github/workflows/github-kics-workflow.yaml",
374+
expected: scut.TestReturn{
375+
Score: checker.MaxResultScore,
376+
NumberOfDebug: 2,
377+
NumberOfInfo: 2,
378+
},
379+
},
297380
}
298381
for _, tt := range tests {
299-
searchRequest := clients.SearchRequest{
300-
Query: "github/codeql-action/analyze",
301-
Path: "/.github/workflows",
302-
}
303382
t.Run(tt.name, func(t *testing.T) {
304383
t.Parallel()
305384
ctrl := gomock.NewController(t)
@@ -311,7 +390,7 @@ func Test_SAST(t *testing.T) {
311390
return tt.commits, tt.err
312391
})
313392
mockRepoClient.EXPECT().ListCheckRunsForRef("").Return(tt.checkRuns, nil).AnyTimes()
314-
mockRepoClient.EXPECT().Search(searchRequest).Return(tt.searchresult, nil).AnyTimes()
393+
mockRepoClient.EXPECT().Search(tt.searchRequest).Return(tt.searchresult, nil).AnyTimes()
315394
mockRepoClient.EXPECT().ListFiles(gomock.Any()).DoAndReturn(
316395
func(predicate func(string) (bool, error)) ([]string, error) {
317396
if strings.Contains(tt.path, "pom") {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: "Security Scans"
2+
on:
3+
schedule:
4+
- cron: '0 3 * * 1' # run tests at 1 AM (UTC), every monday (1)
5+
workflow_dispatch:
6+
inputs:
7+
branch:
8+
description: 'Take CI build artifacts from branch (e.g., master, release-x.y.z)'
9+
required: true
10+
default: 'main'
11+
12+
# Declare default permissions as read only.
13+
permissions: read-all
14+
15+
defaults:
16+
run:
17+
shell: bash
18+
19+
env:
20+
GO_VERSION: "~1.23"
21+
22+
jobs:
23+
security-scans:
24+
steps:
25+
- name: KICS Scan
26+
if: matrix.tool == 'kics'
27+
uses: Checkmarx/kics-github-action@94469746ec2c43de89a42fb9d2a80070f5d25b16 # v2.1.3
28+
with:
29+
path: scans
30+
config_path: .github/kics-config.yml
31+
fail_on: high,medium
32+
output_formats: json,sarif

probes/sastToolConfigured/impl_test.go

Lines changed: 4 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.KicsWorkflow,
72+
},
7073
},
7174
},
7275
},
7376
outcomes: []finding.Outcome{
7477
finding.OutcomeTrue,
7578
finding.OutcomeTrue,
7679
finding.OutcomeTrue,
80+
finding.OutcomeTrue,
7781
},
7882
},
7983
}

0 commit comments

Comments
 (0)