Skip to content

Commit e30a441

Browse files
Fix KICS container shutdown race condition and add OneAssist license support
- Create kicsshutdown package with thread-safe container name management - Update signal handler to read container name from kicsshutdown instead of viper - Prevents race conditions during SIGTERM cleanup - Add support for OneAssist license in addition to Developer Assist - Update GetUniqueID() to check both license types
1 parent 273676a commit e30a441

7 files changed

Lines changed: 63 additions & 10 deletions

File tree

cmd/main.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"syscall"
1010

1111
"github.com/checkmarx/ast-cli/internal/commands"
12+
"github.com/checkmarx/ast-cli/internal/kicsshutdown"
1213
"github.com/checkmarx/ast-cli/internal/logger"
1314
"github.com/checkmarx/ast-cli/internal/params"
1415
"github.com/checkmarx/ast-cli/internal/wrappers"
@@ -191,10 +192,6 @@ func exitListener() {
191192
}
192193

193194
func signalHandler(signalChanel chan os.Signal) {
194-
kicsRunArgs := []string{
195-
killCommand,
196-
viper.GetString(params.KicsContainerNameKey),
197-
}
198195
for {
199196
s := <-signalChanel
200197
switch s {
@@ -204,7 +201,12 @@ func signalHandler(signalChanel chan os.Signal) {
204201
os.Exit(failureExitCode)
205202
}
206203
logger.PrintIfVerbose(string(out))
207-
if strings.Contains(string(out), viper.GetString(params.KicsContainerNameKey)) {
204+
kicsContainerName := kicsshutdown.GetKicsContainerName()
205+
if kicsContainerName != "" && strings.Contains(string(out), kicsContainerName) {
206+
kicsRunArgs := []string{
207+
killCommand,
208+
kicsContainerName,
209+
}
208210
out, err = exec.Command("docker", kicsRunArgs...).CombinedOutput()
209211
logger.PrintIfVerbose(string(out))
210212
if err != nil {

internal/commands/scan.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/pkg/errors"
3636

3737
"github.com/MakeNowJust/heredoc"
38+
"github.com/checkmarx/ast-cli/internal/kicsshutdown"
3839
commonParams "github.com/checkmarx/ast-cli/internal/params"
3940
"github.com/checkmarx/ast-cli/internal/wrappers"
4041
"github.com/mssola/user_agent"
@@ -279,7 +280,9 @@ func NewScanCommand(
279280

280281
func scanRealtimeSubCommand() *cobra.Command {
281282
kicsContainerID := uuid.New()
282-
viper.Set(commonParams.KicsContainerNameKey, kicsContainerPrefixName+kicsContainerID.String())
283+
kicsName := kicsContainerPrefixName + kicsContainerID.String()
284+
viper.Set(commonParams.KicsContainerNameKey, kicsName)
285+
kicsshutdown.SetKicsContainerName(kicsName)
283286
realtimeScanCmd := &cobra.Command{
284287
Use: "kics-realtime",
285288
Short: "Create and run kics scan",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Package kicsshutdown holds the current KICS Docker container name for SIGTERM cleanup.
2+
// It is updated alongside viper wherever KicsContainerNameKey is set so the signal handler
3+
// can read the latest name without concurrent access to viper.
4+
package kicsshutdown
5+
6+
import "sync"
7+
8+
var (
9+
mu sync.RWMutex
10+
name string
11+
)
12+
13+
// SetKicsContainerName records the container name used for shutdown handling.
14+
func SetKicsContainerName(n string) {
15+
mu.Lock()
16+
defer mu.Unlock()
17+
name = n
18+
}
19+
20+
// GetKicsContainerName returns the last recorded container name.
21+
func GetKicsContainerName() string {
22+
mu.RLock()
23+
defer mu.RUnlock()
24+
return name
25+
}

internal/services/realtimeengine/iacrealtime/container-manager.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88

99
"github.com/checkmarx/ast-cli/internal/commands/util"
10+
"github.com/checkmarx/ast-cli/internal/kicsshutdown"
1011
"github.com/checkmarx/ast-cli/internal/logger"
1112
commonParams "github.com/checkmarx/ast-cli/internal/params"
1213
"github.com/google/uuid"
@@ -32,6 +33,7 @@ func (dm *ContainerManager) GenerateContainerID() string {
3233
containerID := uuid.New().String()
3334
containerName := KicsContainerPrefix + containerID
3435
viper.Set(commonParams.KicsContainerNameKey, containerName)
36+
kicsshutdown.SetKicsContainerName(containerName)
3537
return containerName
3638
}
3739

internal/services/realtimeengine/iacrealtime/container-manager_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88
"testing"
99

10+
"github.com/checkmarx/ast-cli/internal/kicsshutdown"
1011
commonParams "github.com/checkmarx/ast-cli/internal/params"
1112
"github.com/google/uuid"
1213
"github.com/spf13/viper"
@@ -46,6 +47,7 @@ func (m *MockContainerManager) GenerateContainerID() string {
4647
containerName := KicsContainerPrefix + containerID
4748
m.GeneratedContainerIDs = append(m.GeneratedContainerIDs, containerName)
4849
viper.Set(commonParams.KicsContainerNameKey, containerName)
50+
kicsshutdown.SetKicsContainerName(containerName)
4951
return containerName
5052
}
5153

@@ -102,6 +104,7 @@ func TestMockContainerManager_GenerateContainerID(t *testing.T) {
102104

103105
// Clear any existing value
104106
viper.Set(commonParams.KicsContainerNameKey, "")
107+
kicsshutdown.SetKicsContainerName("")
105108

106109
containerName := dm.GenerateContainerID()
107110

@@ -125,6 +128,9 @@ func TestMockContainerManager_GenerateContainerID(t *testing.T) {
125128
if viperValue != containerName {
126129
t.Errorf("Viper should be set to '%s', got '%s'", containerName, viperValue)
127130
}
131+
if kicsshutdown.GetKicsContainerName() != containerName {
132+
t.Errorf("kicsshutdown should be set to '%s', got '%s'", containerName, kicsshutdown.GetKicsContainerName())
133+
}
128134

129135
// Test that mock recorded the generated ID
130136
if len(dm.GeneratedContainerIDs) != 1 {
@@ -164,6 +170,7 @@ func TestMockContainerManager_RunKicsContainer(t *testing.T) {
164170
// Set up test parameters
165171
containerName := "test-container"
166172
viper.Set(commonParams.KicsContainerNameKey, containerName)
173+
kicsshutdown.SetKicsContainerName(containerName)
167174

168175
tests := []struct {
169176
name string
@@ -263,6 +270,9 @@ func TestMockContainerManager_Integration(t *testing.T) {
263270
if viper.GetString(commonParams.KicsContainerNameKey) != containerName {
264271
t.Error("Container name should be set in viper after generation")
265272
}
273+
if kicsshutdown.GetKicsContainerName() != containerName {
274+
t.Error("Container name should be set in kicsshutdown after generation")
275+
}
266276

267277
// Test running container
268278
err := dm.RunKicsContainer("docker", "/tmp:/path")
@@ -379,6 +389,7 @@ func TestContainerManager_GenerateContainerID(t *testing.T) {
379389

380390
// Clear any existing value
381391
viper.Set(commonParams.KicsContainerNameKey, "")
392+
kicsshutdown.SetKicsContainerName("")
382393

383394
containerName := cm.GenerateContainerID()
384395

@@ -402,6 +413,9 @@ func TestContainerManager_GenerateContainerID(t *testing.T) {
402413
if viperValue != containerName {
403414
t.Errorf("Viper should be set to '%s', got '%s'", containerName, viperValue)
404415
}
416+
if kicsshutdown.GetKicsContainerName() != containerName {
417+
t.Errorf("kicsshutdown should be set to '%s', got '%s'", containerName, kicsshutdown.GetKicsContainerName())
418+
}
405419

406420
// Test that subsequent calls generate different IDs
407421
containerName2 := cm.GenerateContainerID()

internal/wrappers/jwt-helper.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,19 @@ func GetUniqueID() string {
203203
var uniqueID string
204204
// Check License first
205205
jwtWrapper := NewJwtWrapper()
206-
isAllowed, err := jwtWrapper.IsAllowedEngine(commonParams.CheckmarxDevAssistType)
206+
devAssistAllowed, err := jwtWrapper.IsAllowedEngine(commonParams.CheckmarxDevAssistType)
207207
if err != nil {
208208
logger.PrintIfVerbose("Failed to check engine allowance: " + err.Error())
209209
return ""
210210
}
211-
if !isAllowed {
211+
212+
oneAssistAllowed, err := jwtWrapper.IsAllowedEngine(commonParams.CheckmarxOneAssistType)
213+
if err != nil {
214+
logger.PrintIfVerbose("Failed to check engine allowance: " + err.Error())
215+
return ""
216+
}
217+
218+
if !devAssistAllowed && !oneAssistAllowed {
212219
return ""
213220
}
214221

internal/wrappers/jwt-helper_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func TestGetUniqueID(t *testing.T) {
9090
if result != "" {
9191
assert.Equal(t, existingID, result)
9292
} else {
93-
t.Skip("Requires valid auth and 'Checkmarx Developer Assist' license")
93+
t.Skip("Requires valid auth and 'Checkmarx Developer Assist' or 'Checkmarx OneAssist' license")
9494
}
9595
})
9696

@@ -101,7 +101,7 @@ func TestGetUniqueID(t *testing.T) {
101101
result := GetUniqueID()
102102

103103
if result == "" {
104-
t.Skip("Requires valid auth and 'Checkmarx Developer Assist' license")
104+
t.Skip("Requires valid auth and 'Checkmarx Developer Assist' or 'Checkmarx OneAssist' license")
105105
return
106106
}
107107

0 commit comments

Comments
 (0)