From 5bc1f9a7d24858d74385c2f7b578c06b943d2935 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 4 Nov 2025 15:32:10 +0200 Subject: [PATCH 1/7] Add validation error if required package not installed for the AM --- cli/gitcommands.go | 3 +++ cli/scancommands.go | 4 ++++ cli/utils.go | 10 ++++++++++ jas/analyzermanager.go | 13 +++++++++++++ 4 files changed, 30 insertions(+) diff --git a/cli/gitcommands.go b/cli/gitcommands.go index f79292002..bb2290e9e 100644 --- a/cli/gitcommands.go +++ b/cli/gitcommands.go @@ -64,6 +64,9 @@ func GitAuditCmd(c *components.Context) error { if subScans, err := getSubScansToPreform(c); err != nil { return err } else if len(subScans) > 0 { + if err := validateAnalyzerManagerRequirements(subScans); err != nil { + return err + } gitAuditCmd.SetScansToPerform(subScans) } if threads, err := pluginsCommon.GetThreadsCount(c); err != nil { diff --git a/cli/scancommands.go b/cli/scancommands.go index f6319d935..d95db4302 100644 --- a/cli/scancommands.go +++ b/cli/scancommands.go @@ -415,6 +415,10 @@ func AuditCmd(c *components.Context) error { auditCmd.SetScansToPerform(subScans) } + if err := validateAnalyzerManagerRequirements(auditCmd.ScansToPerform()); err != nil { + return err + } + // Validate that there is a sast scan before setting the sast rules if sastRulesFile := c.GetStringFlagValue(flags.AddSastRules); sastRulesFile != "" { // Check if file exists diff --git a/cli/utils.go b/cli/utils.go index 2f57276a2..6835c30c2 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "os" + "slices" "strings" "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" @@ -16,6 +17,7 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/sca/bom" "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo" "github.com/jfrog/jfrog-cli-security/sca/bom/xrayplugin" @@ -85,6 +87,14 @@ func getSubScansToPreform(c *components.Context) (subScans []utils.SubScanType, return } +func validateAnalyzerManagerRequirements(subScans []utils.SubScanType) error { + if len(subScans) != 0 && (!slices.Contains(subScans, utils.SecretsScan) && !slices.Contains(subScans, utils.ContextualAnalysisScan) && !slices.Contains(subScans, utils.IacScan) && !slices.Contains(subScans, utils.SastScan)) { + // No analyzer manager related sub-scan is requested + return nil + } + return jas.ValidateRequiredInstalledSoftware() +} + func shouldAddSubScan(subScan utils.SubScanType, c *components.Context) bool { return c.GetBoolFlagValue(subScan.String()) || (subScan == utils.ContextualAnalysisScan && c.GetBoolFlagValue(flags.Sca) && !c.GetBoolFlagValue(flags.WithoutCA)) || (subScan == utils.SecretTokenValidationScan && c.GetBoolFlagValue(flags.Secrets) && c.GetBoolFlagValue(flags.SecretValidation)) diff --git a/jas/analyzermanager.go b/jas/analyzermanager.go index e8f78bafe..07c0e1307 100644 --- a/jas/analyzermanager.go +++ b/jas/analyzermanager.go @@ -57,6 +57,10 @@ const ( type JasDiffScanEnvValue string +var scannersRequiredInstalledSoftwares = []string{ + "git", "unzip", "curl", +} + var exitCodeErrorsMap = map[int]string{ notEntitledExitCode: "got not entitled error from analyzer manager", unsupportedCommandExitCode: "got unsupported scan command error from analyzer manager", @@ -212,3 +216,12 @@ func DownloadAnalyzerManagerIfNeeded(threadId int) error { } return utils.DownloadResourceFromPlatformIfNeeded("Analyzer Manager", downloadPath, analyzerManagerDir, AnalyzerManagerZipName, true, threadId) } + +func ValidateRequiredInstalledSoftware() (err error) { + for _, software := range scannersRequiredInstalledSoftwares { + if softwarePath, e := exec.LookPath(software); e != nil || softwarePath == "" { + err = errors.Join(err, fmt.Errorf("could not find the required '%s' executable in the system PATH to run the Advanced Security Scans", software)) + } + } + return +} From 1acba2de3d9e0c02d5f3b0b3cbf124b4cd38efc0 Mon Sep 17 00:00:00 2001 From: attiasas Date: Sun, 23 Nov 2025 12:01:35 +0200 Subject: [PATCH 2/7] fix static tests --- go.mod | 3 --- go.sum | 4 ++-- jas/analyzermanager.go | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 9ed9ea9cf..681a1c414 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,6 @@ module github.com/jfrog/jfrog-cli-security go 1.24.6 -// TODO: update xray-scan lib to latest version that supports CycloneDX v0.9.3 (not yet released) -replace github.com/CycloneDX/cyclonedx-go => github.com/CycloneDX/cyclonedx-go v0.9.2 - require ( github.com/CycloneDX/cyclonedx-go v0.9.3 github.com/beevik/etree v1.4.0 diff --git a/go.sum b/go.sum index 1454a6be4..ac4c57e7a 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/CycloneDX/cyclonedx-go v0.9.2 h1:688QHn2X/5nRezKe2ueIVCt+NRqf7fl3AVQk+vaFcIo= -github.com/CycloneDX/cyclonedx-go v0.9.2/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg= +github.com/CycloneDX/cyclonedx-go v0.9.3 h1:Pyk/lwavPz7AaZNvugKFkdWOm93MzaIyWmBwmBo3aUI= +github.com/CycloneDX/cyclonedx-go v0.9.3/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= diff --git a/jas/analyzermanager.go b/jas/analyzermanager.go index 07c0e1307..1c493b573 100644 --- a/jas/analyzermanager.go +++ b/jas/analyzermanager.go @@ -57,7 +57,7 @@ const ( type JasDiffScanEnvValue string -var scannersRequiredInstalledSoftwares = []string{ +var scannersRequiredInstalledSoftware = []string{ "git", "unzip", "curl", } @@ -218,7 +218,7 @@ func DownloadAnalyzerManagerIfNeeded(threadId int) error { } func ValidateRequiredInstalledSoftware() (err error) { - for _, software := range scannersRequiredInstalledSoftwares { + for _, software := range scannersRequiredInstalledSoftware { if softwarePath, e := exec.LookPath(software); e != nil || softwarePath == "" { err = errors.Join(err, fmt.Errorf("could not find the required '%s' executable in the system PATH to run the Advanced Security Scans", software)) } From ea717945ff080e3ad2e59b00fd30fac44b366631 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 2 Mar 2026 09:36:54 +0200 Subject: [PATCH 3/7] fix merge --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 96a86899a..d4437ff95 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 golang.org/x/sync v0.18.0 + golang.org/x/sys v0.38.0 golang.org/x/text v0.31.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -125,7 +126,6 @@ require ( golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect golang.org/x/term v0.37.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect From 9f66bd3115ac9ac9c3d738f2d40a6952aea5e8cb Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 2 Mar 2026 09:46:04 +0200 Subject: [PATCH 4/7] add malicious sub scan --- cli/utils.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cli/utils.go b/cli/utils.go index bb5b2f86b..47c902e90 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -146,8 +146,13 @@ func getSubScansToPreform(c *components.Context) (subScans []utils.SubScanType, } func validateAnalyzerManagerRequirements(subScans []utils.SubScanType) error { - if len(subScans) != 0 && (!slices.Contains(subScans, utils.SecretsScan) && !slices.Contains(subScans, utils.ContextualAnalysisScan) && !slices.Contains(subScans, utils.IacScan) && !slices.Contains(subScans, utils.SastScan)) { - // No analyzer manager related sub-scan is requested + if len(subScans) != 0 && ( + !slices.Contains(subScans, utils.SecretsScan) && + !slices.Contains(subScans, utils.ContextualAnalysisScan) && + !slices.Contains(subScans, utils.IacScan) && + !slices.Contains(subScans, utils.SastScan) && + !slices.Contains(subScans, utils.MaliciousCodeScan)) { + // No analyzer manager related sub-scan is requested return nil } return jas.ValidateRequiredInstalledSoftware() From 375f8cd9ec4c28aa526eb2f600a1d3bf387fc719 Mon Sep 17 00:00:00 2001 From: attiasas Date: Mon, 2 Mar 2026 09:48:57 +0200 Subject: [PATCH 5/7] also validate if all scans requested for git audit --- cli/gitcommands.go | 6 +++--- commands/git/audit/gitauditparams.go | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cli/gitcommands.go b/cli/gitcommands.go index ea7d28f1f..daea78b10 100644 --- a/cli/gitcommands.go +++ b/cli/gitcommands.go @@ -73,11 +73,11 @@ func GitAuditCmd(c *components.Context) error { if subScans, err := getSubScansToPreform(c); err != nil { return err } else if len(subScans) > 0 { - if err := validateAnalyzerManagerRequirements(subScans); err != nil { - return err - } gitAuditCmd.SetScansToPerform(subScans) } + if err := validateAnalyzerManagerRequirements(gitAuditCmd.GetScansToPerform()); err != nil { + return err + } gitAuditCmd.SetIncludeSbom(shouldIncludeSbom(c, format)) if threads, err := pluginsCommon.GetThreadsCount(c); err != nil { return err diff --git a/commands/git/audit/gitauditparams.go b/commands/git/audit/gitauditparams.go index 2931977c9..7b87d64a5 100644 --- a/commands/git/audit/gitauditparams.go +++ b/commands/git/audit/gitauditparams.go @@ -87,6 +87,10 @@ func (gap *GitAuditParams) SetScansToPerform(scansToPerform []utils.SubScanType) return gap } +func (gap *GitAuditParams) GetScansToPerform() []utils.SubScanType { + return gap.scansToPerform +} + func (gap *GitAuditParams) SetOutputFormat(outputFormat format.OutputFormat) *GitAuditParams { gap.outputFormat = outputFormat return gap From 77de9959a8797585407b2f4a8e6a650de4dd4e25 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 10 Mar 2026 16:07:24 +0200 Subject: [PATCH 6/7] add to binary scans as well --- cli/scancommands.go | 6 ++++++ cli/utils.go | 5 ++--- commands/scan/scan.go | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cli/scancommands.go b/cli/scancommands.go index 5e86d2aeb..af19faa53 100644 --- a/cli/scancommands.go +++ b/cli/scancommands.go @@ -383,6 +383,9 @@ func ScanCmd(c *components.Context) error { } else if len(subScans) > 0 { scanCmd.SetScansToPerform(subScans) } + if err := validateAnalyzerManagerRequirements(scanCmd.ScansToPerform()); err != nil { + return err + } return commandsCommon.Exec(scanCmd) } @@ -811,6 +814,9 @@ func DockerScan(c *components.Context, image string) error { } else if len(subScans) > 0 { containerScanCommand.SetScansToPerform(subScans) } + if err := validateAnalyzerManagerRequirements(containerScanCommand.ScansToPerform()); err != nil { + return err + } containerScanCommand. SetImageTag(image). SetBomGenerator(indexer.NewIndexerBomGenerator()). diff --git a/cli/utils.go b/cli/utils.go index 3978beb8f..e57b42993 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -174,13 +174,12 @@ func getSubScansToPreform(c *components.Context) (subScans []utils.SubScanType, } func validateAnalyzerManagerRequirements(subScans []utils.SubScanType) error { - if len(subScans) != 0 && ( - !slices.Contains(subScans, utils.SecretsScan) && + if len(subScans) != 0 && (!slices.Contains(subScans, utils.SecretsScan) && !slices.Contains(subScans, utils.ContextualAnalysisScan) && !slices.Contains(subScans, utils.IacScan) && !slices.Contains(subScans, utils.SastScan) && !slices.Contains(subScans, utils.MaliciousCodeScan)) { - // No analyzer manager related sub-scan is requested + // No analyzer manager related sub-scan is requested return nil } return jas.ValidateRequiredInstalledSoftware() diff --git a/commands/scan/scan.go b/commands/scan/scan.go index 582a97af9..d2e1adf85 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -216,6 +216,10 @@ func (scanCmd *ScanCommand) SetScansToPerform(scansToPerform []utils.SubScanType return scanCmd } +func (scanCmd *ScanCommand) ScansToPerform() []utils.SubScanType { + return scanCmd.scansToPerform +} + func (scanCmd *ScanCommand) Run() (err error) { return scanCmd.RunAndRecordResults(utils.Binary, scanCmd.recordResults) } From d3b600d58e2efa62b4862631f69b27ab33a2df63 Mon Sep 17 00:00:00 2001 From: attiasas Date: Tue, 10 Mar 2026 16:20:21 +0200 Subject: [PATCH 7/7] validate only if entitled --- cli/gitcommands.go | 3 --- cli/scancommands.go | 10 ---------- cli/utils.go | 14 -------------- commands/audit/audit.go | 5 +++++ commands/git/audit/gitauditparams.go | 4 ---- commands/scan/scan.go | 9 +++++---- 6 files changed, 10 insertions(+), 35 deletions(-) diff --git a/cli/gitcommands.go b/cli/gitcommands.go index 16055b6a4..8ea37082f 100644 --- a/cli/gitcommands.go +++ b/cli/gitcommands.go @@ -75,9 +75,6 @@ func GitAuditCmd(c *components.Context) error { } else if len(subScans) > 0 { gitAuditCmd.SetScansToPerform(subScans) } - if err := validateAnalyzerManagerRequirements(gitAuditCmd.GetScansToPerform()); err != nil { - return err - } gitAuditCmd.SetIncludeSbom(shouldIncludeSbom(c, format)) if threads, err := pluginsCommon.GetThreadsCount(c); err != nil { return err diff --git a/cli/scancommands.go b/cli/scancommands.go index af19faa53..9246b8946 100644 --- a/cli/scancommands.go +++ b/cli/scancommands.go @@ -383,9 +383,6 @@ func ScanCmd(c *components.Context) error { } else if len(subScans) > 0 { scanCmd.SetScansToPerform(subScans) } - if err := validateAnalyzerManagerRequirements(scanCmd.ScansToPerform()); err != nil { - return err - } return commandsCommon.Exec(scanCmd) } @@ -496,10 +493,6 @@ func AuditCmd(c *components.Context) error { auditCmd.SetScansToPerform(subScans) } - if err := validateAnalyzerManagerRequirements(auditCmd.ScansToPerform()); err != nil { - return err - } - // Validate that there is a sast scan before setting the sast rules if sastRulesFile := c.GetStringFlagValue(flags.AddSastRules); sastRulesFile != "" { // Check if file exists @@ -814,9 +807,6 @@ func DockerScan(c *components.Context, image string) error { } else if len(subScans) > 0 { containerScanCommand.SetScansToPerform(subScans) } - if err := validateAnalyzerManagerRequirements(containerScanCommand.ScansToPerform()); err != nil { - return err - } containerScanCommand. SetImageTag(image). SetBomGenerator(indexer.NewIndexerBomGenerator()). diff --git a/cli/utils.go b/cli/utils.go index e57b42993..311c0df46 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "regexp" - "slices" "strings" "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" @@ -20,7 +19,6 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" - "github.com/jfrog/jfrog-cli-security/jas" "github.com/jfrog/jfrog-cli-security/sca/bom" "github.com/jfrog/jfrog-cli-security/sca/bom/buildinfo" "github.com/jfrog/jfrog-cli-security/sca/bom/xrayplugin" @@ -173,18 +171,6 @@ func getSubScansToPreform(c *components.Context) (subScans []utils.SubScanType, return } -func validateAnalyzerManagerRequirements(subScans []utils.SubScanType) error { - if len(subScans) != 0 && (!slices.Contains(subScans, utils.SecretsScan) && - !slices.Contains(subScans, utils.ContextualAnalysisScan) && - !slices.Contains(subScans, utils.IacScan) && - !slices.Contains(subScans, utils.SastScan) && - !slices.Contains(subScans, utils.MaliciousCodeScan)) { - // No analyzer manager related sub-scan is requested - return nil - } - return jas.ValidateRequiredInstalledSoftware() -} - func shouldAddSubScan(subScan utils.SubScanType, c *components.Context) bool { return c.GetBoolFlagValue(subScan.String()) || (subScan == utils.ContextualAnalysisScan && c.GetBoolFlagValue(flags.Sca) && !c.GetBoolFlagValue(flags.WithoutCA)) || (subScan == utils.SecretTokenValidationScan && c.GetBoolFlagValue(flags.Secrets) && c.GetBoolFlagValue(flags.SecretValidation)) diff --git a/commands/audit/audit.go b/commands/audit/audit.go index 5a0803b36..b22dfc9cb 100644 --- a/commands/audit/audit.go +++ b/commands/audit/audit.go @@ -421,6 +421,11 @@ func initAuditCmdResults(params *AuditParams) (cmdResults *results.SecurityComma cmdResults.SetEntitledForJas(entitledForJas) } if entitledForJas { + if utils.IsJASRequested(cmdResults.CmdType, params.ScansToPerform()...) { + if err = jas.ValidateRequiredInstalledSoftware(); err != nil { + return cmdResults.AddGeneralError(err, false) + } + } cmdResults.SetSecretValidation(jas.CheckForSecretValidation(xrayManager, params.GetXrayVersion(), slices.Contains(params.ScansToPerform(), utils.SecretTokenValidationScan))) } return diff --git a/commands/git/audit/gitauditparams.go b/commands/git/audit/gitauditparams.go index 1a7c92028..9a0180bc7 100644 --- a/commands/git/audit/gitauditparams.go +++ b/commands/git/audit/gitauditparams.go @@ -94,10 +94,6 @@ func (gap *GitAuditParams) SetScansToPerform(scansToPerform []utils.SubScanType) return gap } -func (gap *GitAuditParams) GetScansToPerform() []utils.SubScanType { - return gap.scansToPerform -} - func (gap *GitAuditParams) SetOutputFormat(outputFormat format.OutputFormat) *GitAuditParams { gap.outputFormat = outputFormat return gap diff --git a/commands/scan/scan.go b/commands/scan/scan.go index d2e1adf85..a48c811c9 100644 --- a/commands/scan/scan.go +++ b/commands/scan/scan.go @@ -216,10 +216,6 @@ func (scanCmd *ScanCommand) SetScansToPerform(scansToPerform []utils.SubScanType return scanCmd } -func (scanCmd *ScanCommand) ScansToPerform() []utils.SubScanType { - return scanCmd.scansToPerform -} - func (scanCmd *ScanCommand) Run() (err error) { return scanCmd.RunAndRecordResults(utils.Binary, scanCmd.recordResults) } @@ -342,6 +338,11 @@ func (scanCmd *ScanCommand) initScanCmdResults(cmdType utils.CommandType) (xrayM } else { cmdResults.SetEntitledForJas(entitledForJas) if entitledForJas { + if utils.IsJASRequested(cmdResults.CmdType, scanCmd.scansToPerform...) { + if err = jas.ValidateRequiredInstalledSoftware(); err != nil { + return xrayManager, cmdResults.AddGeneralError(err, false) + } + } cmdResults.SetSecretValidation(jas.CheckForSecretValidation(xrayManager, scanCmd.xrayVersion, scanCmd.validateSecrets)) } }