From ce2f76ca74a186548e57bfecccc28da88fbb0c8b Mon Sep 17 00:00:00 2001 From: atishj99 Date: Thu, 2 Jul 2026 16:54:49 +0530 Subject: [PATCH 1/3] combining all changes --- internal/commands/scan.go | 5 ++--- internal/commands/scan_test.go | 10 +++++----- internal/commands/util/remediation.go | 2 +- internal/services/projects.go | 1 - internal/wrappers/feature-flags-http.go | 13 +++++++++++++ internal/wrappers/feature-flags.go | 9 ++++----- 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/internal/commands/scan.go b/internal/commands/scan.go index 583c596b5..9e8b2e7c2 100644 --- a/internal/commands/scan.go +++ b/internal/commands/scan.go @@ -65,7 +65,7 @@ const ( containerVolumeFlag = "-v" containerNameFlag = "--name" containerRemove = "--rm" - containerImage = "checkmarx/kics:v2.1.20" + containerImage = "checkmarx/kics@sha256:643071cf0c1657eaea695a48b49d2d61b7e625bb87c51505530e624e0c0a1ad1" // v2.1.20 containerScan = "scan" containerScanPathFlag = "-p" containerScanPath = "/path" @@ -1184,9 +1184,8 @@ func overrideSastConfigValue(sastFastScanChanged, sastIncrementalChanged, sastLi func addAiscScan(featureFlagWrapper wrappers.FeatureFlagsWrapper, resubmitConfig []wrappers.Config) map[string]interface{} { // Add the aisc resubmit config, currently no value is passed in config - aiSupplyChainEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagWrapper, wrappers.AISupplyChainEnabled) aiSupplyChainGAEnabled, _ := wrappers.GetSpecificFeatureFlag(featureFlagWrapper, wrappers.AISupplyChainGAEnabled) - if scanTypeEnabled(commonParams.AiscType) && aiSupplyChainEnabled.Status && aiSupplyChainGAEnabled.Status { + if scanTypeEnabled(commonParams.AiscType) && aiSupplyChainGAEnabled.Status { aiscMapConfig := make(map[string]interface{}) aiscConfig := wrappers.AISCConfig{} aiscMapConfig[resultsMapType] = commonParams.AiscType diff --git a/internal/commands/scan_test.go b/internal/commands/scan_test.go index 971e3d02c..e44f607ee 100644 --- a/internal/commands/scan_test.go +++ b/internal/commands/scan_test.go @@ -836,7 +836,7 @@ func TestAddAiscScan_WhenAiscEnabledAndFeatureFlagEnabled_ShouldReturnConfig(t * var resubmitConfig []wrappers.Config mock.Flag = wrappers.FeatureFlagResponseModel{ - Name: wrappers.AISupplyChainEnabled, + Name: wrappers.AISupplyChainGAEnabled, Status: true, } defer clearFlags() @@ -862,7 +862,7 @@ func TestAddAiscScan_WhenAiscDisabled_ShouldReturnNil(t *testing.T) { wrappers.ClearCache() var resubmitConfig []wrappers.Config mock.Flag = wrappers.FeatureFlagResponseModel{ - Name: wrappers.AISupplyChainEnabled, + Name: wrappers.AISupplyChainGAEnabled, Status: true, } defer clearFlags() @@ -878,7 +878,7 @@ func TestAddAiscScan_WhenFeatureFlagDisabled_ShouldReturnNil(t *testing.T) { wrappers.ClearCache() var resubmitConfig []wrappers.Config mock.Flag = wrappers.FeatureFlagResponseModel{ - Name: wrappers.AISupplyChainEnabled, + Name: wrappers.AISupplyChainGAEnabled, Status: false, } defer clearFlags() @@ -900,7 +900,7 @@ func TestAddAiscScan_WithResubmitConfig_ShouldHandleCorrectly(t *testing.T) { }, } mock.Flag = wrappers.FeatureFlagResponseModel{ - Name: wrappers.AISupplyChainEnabled, + Name: wrappers.AISupplyChainGAEnabled, Status: true, } defer clearFlags() @@ -919,7 +919,7 @@ func TestAddAiscScan_ConfigStructure_ShouldHaveCorrectFormat(t *testing.T) { wrappers.ClearCache() var resubmitConfig []wrappers.Config mock.Flag = wrappers.FeatureFlagResponseModel{ - Name: wrappers.AISupplyChainEnabled, + Name: wrappers.AISupplyChainGAEnabled, Status: true, } defer clearFlags() diff --git a/internal/commands/util/remediation.go b/internal/commands/util/remediation.go index 7322a5fa8..a74c180ef 100644 --- a/internal/commands/util/remediation.go +++ b/internal/commands/util/remediation.go @@ -27,7 +27,7 @@ const ( filesContainerVolume = ":/files" resultsContainerLocation = "/kics/" containerRemove = "--rm" - ContainerImage = "checkmarx/kics:v2.1.20" + ContainerImage = "checkmarx/kics@sha256:643071cf0c1657eaea695a48b49d2d61b7e625bb87c51505530e624e0c0a1ad1" // v2.1.20 containerNameFlag = "--name" remediateCommand = "remediate" resultsFlag = "--results" diff --git a/internal/services/projects.go b/internal/services/projects.go index 875568746..090e6e78d 100644 --- a/internal/services/projects.go +++ b/internal/services/projects.go @@ -198,7 +198,6 @@ func updateProject(project *wrappers.ProjectResponseModel, } else { projModel.MainBranch = project.MainBranch } - projModel.RepoURL = project.RepoURL if projectTags == "" && projectPrivatePackage == "" && isBranchPrimary == false { logger.PrintIfVerbose("No tags or branch to update. Skipping project update.") diff --git a/internal/wrappers/feature-flags-http.go b/internal/wrappers/feature-flags-http.go index 3f0c77314..e98b60294 100644 --- a/internal/wrappers/feature-flags-http.go +++ b/internal/wrappers/feature-flags-http.go @@ -4,8 +4,11 @@ import ( "encoding/json" "fmt" "net/http" + "strconv" "strings" + "time" + "github.com/checkmarx/ast-cli/internal/logger" "github.com/pkg/errors" "github.com/spf13/viper" @@ -87,6 +90,16 @@ func (f FeatureFlagsHTTPWrapper) GetSpecificFlag(flagName string) (*FeatureFlagR return &model, nil case http.StatusNotFound: return nil, errors.New("feature flags not found") + case http.StatusTooManyRequests: + waitSeconds := defaultRateLimitWaitSeconds + if retryAfter := resp.Header.Get("Retry-After"); retryAfter != "" { + if parsed, parseErr := strconv.Atoi(retryAfter); parseErr == nil && parsed > 0 { + waitSeconds = parsed + } + } + logger.PrintIfVerbose(fmt.Sprintf("Feature flags rate limited (429). Waiting %d seconds before retry.", waitSeconds)) + time.Sleep(time.Duration(waitSeconds) * time.Second) + return nil, errors.New("failed to load feature flags for tenant") default: return nil, errors.New("failed to load feature flags for tenant") } diff --git a/internal/wrappers/feature-flags.go b/internal/wrappers/feature-flags.go index a5718fbd4..ec0a31bd4 100644 --- a/internal/wrappers/feature-flags.go +++ b/internal/wrappers/feature-flags.go @@ -22,9 +22,6 @@ const maxRetries = 3 const IncreaseFileUploadLimit = "INCREASE_FILE_UPLOAD_LIMIT" const ScaDeltaScanEnabled = "SCA_DELTASCAN_ENABLED" -// AISupplyChainEnabled is the feature flag for AI Supply Chain Engine. -const AISupplyChainEnabled = "AI_SUPPLY_CHAIN_ENGINE_ENABLED" - // AISupplyChainGAEnabled is the feature flag for AI Supply Chain Engine GA. const AISupplyChainGAEnabled = "AI_SUPPLY_CHAIN_ENGINE_GA_ENABLED" @@ -113,8 +110,10 @@ func GetSpecificFeatureFlag(featureFlagsWrapper FeatureFlagsWrapper, flagName st if len(featureFlags) == 0 || DefaultFFLoad { _ = HandleFeatureFlags(featureFlagsWrapper) } - // Take the value from FeatureFlags - return &FeatureFlagResponseModel{Name: flagName, Status: featureFlags[flagName]}, nil + defaultValue := featureFlags[flagName] + featureFlagsCache[flagName] = defaultValue // prevent re-fetch on next call + return &FeatureFlagResponseModel{Name: flagName, Status: defaultValue}, nil + } UpdateSpecificFeatureFlagMap(flagName, *specificFlag) From 0be8a2f9b6d43d466733d5400b5b03fe508d8b6f Mon Sep 17 00:00:00 2001 From: atishj99 Date: Thu, 2 Jul 2026 18:08:00 +0530 Subject: [PATCH 2/3] fixing lint issue --- internal/commands/util/remediation.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/commands/util/remediation.go b/internal/commands/util/remediation.go index a74c180ef..c30438aff 100644 --- a/internal/commands/util/remediation.go +++ b/internal/commands/util/remediation.go @@ -27,6 +27,7 @@ const ( filesContainerVolume = ":/files" resultsContainerLocation = "/kics/" containerRemove = "--rm" + // ContainerImage is the KICS container image with pinned SHA256 digest. ContainerImage = "checkmarx/kics@sha256:643071cf0c1657eaea695a48b49d2d61b7e625bb87c51505530e624e0c0a1ad1" // v2.1.20 containerNameFlag = "--name" remediateCommand = "remediate" From 69aa46db96436bc52120d51ba15adf10044d2c60 Mon Sep 17 00:00:00 2001 From: atishj99 Date: Fri, 3 Jul 2026 12:50:28 +0530 Subject: [PATCH 3/3] Adding check in astcli to check supported manifest files --- .../ossrealtime/oss-realtime.go | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/internal/services/realtimeengine/ossrealtime/oss-realtime.go b/internal/services/realtimeengine/ossrealtime/oss-realtime.go index 9316b1a7e..bf65b0c39 100644 --- a/internal/services/realtimeengine/ossrealtime/oss-realtime.go +++ b/internal/services/realtimeengine/ossrealtime/oss-realtime.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "strings" "github.com/Checkmarx/manifest-parser/pkg/parser" @@ -74,6 +75,10 @@ func (o *OssRealtimeService) RunOssRealtimeScan(filePath, ignoredFilePath string return nil, errorconstants.NewRealtimeEngineError("invalid file path").Error() } + if err := validateSupportedManifestFile(filePath); err != nil { + return nil, err + } + pkgs, err := parseManifest(filePath) if err != nil { logger.PrintfIfVerbose("Failed to parse manifest file %s: %v", filePath, err) @@ -174,6 +179,55 @@ func getPackageEntryFromPackageMap( return &entry } +// validateSupportedManifestFile checks if the manifest file format is supported by OSS realtime scanner. +func validateSupportedManifestFile(filePath string) error { + manifestFileName := filepath.Base(filePath) + manifestFileExtension := filepath.Ext(manifestFileName) + + // Check supported extensions + supportedExtensions := map[string]bool{ + ".csproj": true, + ".sbt": true, + } + + // Check supported filenames + supportedFilenames := map[string]bool{ + "pom.xml": true, + "package.json": true, + "Directory.Packages.props": true, + "packages.config": true, + "go.mod": true, + "build.gradle": true, + "build.gradle.kts": true, + "libs.versions.toml": true, + "setup.cfg": true, + "setup.py": true, + "pyproject.toml": true, + } + + // Check by extension + if supportedExtensions[manifestFileExtension] { + return nil + } + + // Check by filename + if supportedFilenames[manifestFileName] { + return nil + } + + // Special handling for .txt files (check prefix) + if manifestFileExtension == ".txt" { + if strings.HasPrefix(manifestFileName, "requirement") || + strings.HasPrefix(manifestFileName, "packages") || + strings.HasPrefix(manifestFileName, "constraint") { + return nil + } + } + + // Manifest format is not supported + return errorconstants.NewRealtimeEngineError(fmt.Sprintf("OSS Realtime scanner doesn't currently support scanning '%s' file.", manifestFileName)).Error() +} + // parseManifest parses the manifest file and returns a list of packages. func parseManifest(filePath string) ([]models.Package, error) { manifestParser := parser.ParsersFactory(filePath)