diff --git a/Dockerfile b/Dockerfile index c88dfbb34..14084b85e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM checkmarx/bash:5.2.37-r2-cbecd9aeaadc77@sha256:cbecd9aeaadc775906af3b4b0b03e05d5a4e68cb300d7db4579d88129b2eb028 +FROM checkmarx/bash:5.2.37-r2-c5dcfc6a2fbe1c@sha256:c5dcfc6a2fbe1c8f9d11bdf902b5485bb78b4733864a99806749d5e244a6b75e USER nonroot COPY cx /app/bin/cx diff --git a/internal/wrappers/client.go b/internal/wrappers/client.go index c1e7ade53..67209798d 100644 --- a/internal/wrappers/client.go +++ b/internal/wrappers/client.go @@ -12,6 +12,7 @@ import ( "net/http/httptrace" "net/url" "strings" + "sync" "time" applicationErrors "github.com/checkmarx/ast-cli/internal/constants/errors" @@ -44,6 +45,10 @@ const ( jsonContentType = "application/json" ) +var ( + credentialsMutex sync.Mutex +) + type ClientCredentialsInfo struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` @@ -478,6 +483,9 @@ func getClientCredentialsFromCache(tokenExpirySeconds int) string { } func writeCredentialsToCache(accessToken string) { + credentialsMutex.Lock() + defer credentialsMutex.Unlock() + logger.PrintIfVerbose("Storing API access token to cache.") viper.Set(commonParams.AstToken, accessToken) cachedAccessToken = accessToken diff --git a/internal/wrappers/client_test.go b/internal/wrappers/client_test.go index f79577ce3..35663e4a7 100644 --- a/internal/wrappers/client_test.go +++ b/internal/wrappers/client_test.go @@ -2,10 +2,17 @@ package wrappers import ( "errors" - "github.com/stretchr/testify/assert" + "fmt" "net/http" + "strconv" + "strings" + "sync" "testing" "time" + + commonParams "github.com/checkmarx/ast-cli/internal/params" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" ) type mockReadCloser struct{} @@ -78,3 +85,31 @@ func TestRetryHTTPRequest_EndWithBadGateway(t *testing.T) { assert.NotNil(t, resp) assert.Equal(t, http.StatusBadGateway, resp.StatusCode) } + +func TestConcurrentWriteCredentialsToCache(t *testing.T) { + var wg sync.WaitGroup + + for i := 0; i < 1000; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + writeCredentialsToCache(fmt.Sprintf("testToken_%d", i)) + }(i) + } + wg.Wait() + + token := viper.Get(commonParams.AstToken) + assert.NotNil(t, token, "Token should not be nil") + + tokenStr, ok := token.(string) + assert.True(t, ok, "Token should be a string") + + splitToken := strings.Split(tokenStr, "_") + assert.Equal(t, 2, len(splitToken), "Token should split into 2 parts") + assert.Equal(t, "testToken", splitToken[0], "Token prefix should be 'testToken'") + + testTokenNumber, err := strconv.Atoi(splitToken[1]) + assert.NoError(t, err, "The token suffix should be a valid number") + assert.True(t, testTokenNumber >= 0 && testTokenNumber < 1000, + "The token number should be within the expected range") +}