Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ func shouldIncludeVulnerabilities(includeVulnerabilities bool, watches []string,

func shouldIncludeSnippetDetection(params *AuditParams) bool {
if profile := params.GetConfigProfile(); profile != nil && len(profile.Modules) > 0 {
if profile.Modules[0].ScanConfig.ScaScannerConfig.EnableSnippetDetection {
return true
for _, module := range profile.Modules {
if module.ScanConfig.ScaScannerConfig.EnableSnippetDetection {
return true
}
}
}
if params.resultsContext.IncludeSnippetDetection {
Expand Down Expand Up @@ -282,14 +284,14 @@ func (auditCmd *AuditCommand) Run() (err error) {

func (auditCmd *AuditCommand) getResultWriter(cmdResults *results.SecurityCommandResults) *output.ResultsWriter {
var messages []string
if !cmdResults.EntitledForJas {
if !cmdResults.Entitlements.Jas {
messages = []string{coreutils.PrintTitle("In addition to SCA, the ‘jf audit’ command supports the following Advanced Security scans: 'Contextual Analysis', 'Secrets Detection', 'IaC', and ‘SAST’.\nThese scans are available within Advanced Security license. Read more - ") + coreutils.PrintLink(utils.JasInfoURL)}
}
if cmdResults.ResultsPlatformUrl != "" && auditCmd.gitContext != nil {
messages = append(messages, output.GetCommandResultsPlatformUrlMessage(cmdResults, true))
}
var tableNotes []string
if cmdResults.EntitledForJas && cmdResults.HasViolationContext() && len(cmdResults.ResultContext.GitRepoHttpsCloneUrl) == 0 {
if cmdResults.Entitlements.Jas && cmdResults.HasViolationContext() && len(cmdResults.ResultContext.GitRepoHttpsCloneUrl) == 0 {
tableNotes = []string{"Note: The following vulnerability violations are NOT supported by this audit:\n- Secrets\n- Infrastructure as Code (IaC)\n- Static Application Security Testing (SAST)"}
}
return output.NewResultsWriter(cmdResults).
Expand Down Expand Up @@ -377,7 +379,6 @@ func getScanLogicOptions(params *AuditParams) (bomGenOptions []bom.SbomGenerator
xrayplugin.WithBinaryPath(params.CustomBomGenBinaryPath()),
xrayplugin.WithIgnorePatterns(params.Exclusions()),
xrayplugin.WithSpecificTechnologies(params.Technologies()),
xrayplugin.WithSnippetDetection(shouldIncludeSnippetDetection(params)),
}
// Scan Strategies Options
scanGraphParams, err := params.ToXrayScanGraphParams()
Expand Down Expand Up @@ -418,17 +419,29 @@ func initAuditCmdResults(params *AuditParams) (cmdResults *results.SecurityComma
entitledForJas, err := isEntitledForJas(xrayManager, params)
if err != nil {
return cmdResults.AddGeneralError(err, false)
} else {
cmdResults.SetEntitledForJas(entitledForJas)
}
cmdResults.SetEntitledForJas(entitledForJas)
if entitledForJas {
// Validate required installed software
if utils.IsJASRequested(cmdResults.CmdType, params.ScansToPerform()...) {
if err = jas.ValidateRequiredInstalledSoftware(); err != nil {
return cmdResults.AddGeneralError(err, false)
}
}
// Validate secret validation entitlement
cmdResults.SetSecretValidation(jas.CheckForSecretValidation(xrayManager, params.GetXrayVersion(), slices.Contains(params.ScansToPerform(), utils.SecretTokenValidationScan)))
}
// Snippet detection requires JAS entitlement and also the Snippet Detection feature is enabled in Xray.
if shouldIncludeSnippetDetection(params) {
entitledForSnippetDetection, err := isEntitledForSnippetDetection(entitledForJas, xrayManager, params)
if err != nil {
return cmdResults.AddGeneralError(err, false)
}
if !entitledForSnippetDetection {
return cmdResults.AddGeneralError(fmt.Errorf("snippet detection is requested but the JFrog instance is not entitled for it"), false)
}
cmdResults.SetEntitledForSnippetDetection(entitledForSnippetDetection)
}
return
}

Expand All @@ -440,6 +453,14 @@ func isEntitledForJas(xrayManager *xray.XrayServicesManager, auditParams *AuditP
return jas.IsEntitledForJas(xrayManager, auditParams.GetXrayVersion())
}

func isEntitledForSnippetDetection(isEntitledForJas bool, xrayManager *xray.XrayServicesManager, auditParams *AuditParams) (entitled bool, err error) {
if !isEntitledForJas {
return false, nil
}
// Snippet detection requires JAS entitlement and also the Snippet Detection feature is enabled in Xray.
return xrayutils.IsEntitled(xrayManager, auditParams.GetXrayVersion(), xrayplugin.SnippetDetectionFeatureId)
}

func populateScanTargets(cmdResults *results.SecurityCommandResults, params *AuditParams) {
// Populate the scan targets based on the provided parameters.
detectScanTargets(cmdResults, params)
Expand All @@ -458,7 +479,10 @@ func populateScanTargets(cmdResults *results.SecurityCommandResults, params *Aud
// No need to generate the SBOM if we are not going to use it.
continue
}
bom.GenerateSbomForTarget(params.BomGenerator().WithOptions(buildinfo.WithDescriptors(targetResult.GetDescriptors())),
bom.GenerateSbomForTarget(params.BomGenerator().WithOptions(
buildinfo.WithDescriptors(targetResult.GetDescriptors()),
xrayplugin.WithSnippetDetection(shouldIncludeSnippetDetection(params)),
),
bom.SbomGeneratorParams{
Target: targetResult,
AllowPartialResults: params.AllowPartialResults(),
Expand Down Expand Up @@ -616,7 +640,7 @@ func addScaScansToRunner(auditParallelRunner *utils.SecurityParallelRunner, audi
}

func addJasScansToRunner(auditParallelRunner *utils.SecurityParallelRunner, auditParams *AuditParams, scanResults *results.SecurityCommandResults, isNewFlow bool) (jasScanner *jas.JasScanner, generalError error) {
if !scanResults.EntitledForJas {
if !scanResults.Entitlements.Jas {
log.Info("Advanced Security is not enabled on this system, so Advanced Security scans were skipped...")
return
}
Expand Down
2 changes: 1 addition & 1 deletion commands/git/audit/gitaudit.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func RunGitAudit(params GitAuditParams) (scanResults *results.SecurityCommandRes

func (gaCmd *GitAuditCommand) getResultWriter(cmdResults *results.SecurityCommandResults) *output.ResultsWriter {
var messages []string
if !cmdResults.EntitledForJas {
if !cmdResults.Entitlements.Jas {
messages = []string{coreutils.PrintTitle("In addition to SCA, the ‘jf git audit’ command supports the following Advanced Security scans: 'Contextual Analysis', 'Secrets Detection', 'IaC', and ‘SAST’.\nThese scans are available within Advanced Security license. Read more - ") + coreutils.PrintLink(utils.JasInfoURL)}
}
if cmdResults.ResultsPlatformUrl != "" {
Expand Down
4 changes: 2 additions & 2 deletions commands/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ func (scanCmd *ScanCommand) initScanCmdResults(cmdType utils.CommandType) (xrayM
func (scanCmd *ScanCommand) prepareForScan(cmdResults *results.SecurityCommandResults, xrayManager *xrayClient.XrayServicesManager) (err error) {
// Download (if needed) the analyzer manager in a background routine.
AnalyzerErrGroup := new(errgroup.Group)
if cmdResults.EntitledForJas && utils.IsJASRequested(cmdResults.CmdType, scanCmd.scansToPerform...) {
if cmdResults.Entitlements.Jas && utils.IsJASRequested(cmdResults.CmdType, scanCmd.scansToPerform...) {
if scanCmd.customAnalyzerManagerPath == "" {
AnalyzerErrGroup.Go(func() error {
return jas.DownloadAnalyzerManagerIfNeeded(0)
Expand Down Expand Up @@ -444,7 +444,7 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, cmdResults
}
// SCA scan
targetCompId, graphScanResults, err := scanCmd.RunBinaryScaScan(file.Target, cmdResults, targetResults, deprecatedGraph, scanThreadId)
if err != nil || !cmdResults.EntitledForJas {
if err != nil || !cmdResults.Entitlements.Jas {
return
}
// Run Jas scans
Expand Down
8 changes: 4 additions & 4 deletions git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ func TestGitAuditJasSkipNotApplicableCvesViolations(t *testing.T) {
xrayVersion, xscVersion, "",
validations.ValidationParams{
Violations: &validations.ViolationCount{
ValidateScan: &validations.ScanCount{Sca: 10, Sast: 2, Secrets: 2},
ValidateApplicabilityStatus: &validations.ApplicabilityStatusCount{NotApplicable: 5, NotCovered: 5, Inactive: 2},
ValidateScan: &validations.ScanCount{Sca: 11, Sast: 2, Secrets: 2},
ValidateApplicabilityStatus: &validations.ApplicabilityStatusCount{NotApplicable: 5, NotCovered: 6, Inactive: 2},
},
ExactResultsMatch: true,
},
Expand All @@ -299,8 +299,8 @@ func TestGitAuditJasSkipNotApplicableCvesViolations(t *testing.T) {
xrayVersion, xscVersion, "",
validations.ValidationParams{
Violations: &validations.ViolationCount{
ValidateScan: &validations.ScanCount{Sca: 5, Sast: 2, Secrets: 2},
ValidateApplicabilityStatus: &validations.ApplicabilityStatusCount{NotCovered: 5, Inactive: 2},
ValidateScan: &validations.ScanCount{Sca: 6, Sast: 2, Secrets: 2},
ValidateApplicabilityStatus: &validations.ApplicabilityStatusCount{NotCovered: 6, Inactive: 2},
},
ExactResultsMatch: true,
},
Expand Down
2 changes: 1 addition & 1 deletion policy/enforcer/policyenforcer.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func locateJasVulnerabilityInfo(cmdResults *results.SecurityCommandResults, jasT
log.Debug(fmt.Sprintf("Skipping %s violation search for target %s with no Jas results", jasType, target.ScanTarget))
continue
}
if err := results.ForEachJasIssue(target.JasResults.GetVulnerabilitiesResults(jasType), cmdResults.EntitledForJas,
if err := results.ForEachJasIssue(target.JasResults.GetVulnerabilitiesResults(jasType), cmdResults.Entitlements.Jas,
func(run *sarif.Run, rule *sarif.ReportingDescriptor, severity severityutils.Severity, result *sarif.Result, location *sarif.Location) error {
if !found && isMatchingJasViolation(id, jasType, rule, location, run.Invocations, violation) {
// Found a relevant issue (JAS Violations only provide abbreviation and file name, no region so we match only by those)
Expand Down
8 changes: 4 additions & 4 deletions policy/local/localconvertor.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,24 @@ func (d *DeprecatedViolationGenerator) GenerateViolations(cmdResults *results.Se
for _, target := range cmdResults.Targets {
// SCA violations (from DeprecatedXrayResults)
if target.ScaResults != nil {
if e := d.generateScaViolations(target, &convertedViolations, cmdResults.EntitledForJas); e != nil {
if e := d.generateScaViolations(target, &convertedViolations, cmdResults.Entitlements.Jas); e != nil {
err = errors.Join(err, fmt.Errorf("failed to convert SCA violations for target %s: %w", target.Target, e))
}
}
// JAS violations (from JasResults)
if target.JasResults != nil {
if len(target.JasResults.JasViolations.SecretsScanResults) > 0 {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.SecretsScanResults, cmdResults.EntitledForJas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.Secrets)); e != nil {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.SecretsScanResults, cmdResults.Entitlements.Jas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.Secrets)); e != nil {
err = errors.Join(err, fmt.Errorf("failed to convert JAS Secret violations for target %s: %w", target.Target, e))
}
}
if len(target.JasResults.JasViolations.IacScanResults) > 0 {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.IacScanResults, cmdResults.EntitledForJas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.IaC)); e != nil {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.IacScanResults, cmdResults.Entitlements.Jas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.IaC)); e != nil {
err = errors.Join(err, fmt.Errorf("failed to convert JAS IaC violations for target %s: %w", target.Target, e))
}
}
if len(target.JasResults.JasViolations.SastScanResults) > 0 {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.SastScanResults, cmdResults.EntitledForJas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.Sast)); e != nil {
if e := results.ForEachJasIssue(target.JasResults.JasViolations.SastScanResults, cmdResults.Entitlements.Jas, convertJasViolationsToPolicyViolations(&convertedViolations, jasutils.Sast)); e != nil {
err = errors.Join(err, fmt.Errorf("failed to convert JAS SAST violations for target %s: %w", target.Target, e))
}
}
Expand Down
4 changes: 2 additions & 2 deletions sca/bom/buildinfo/technologies/pnpm/pnpm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestBuildDependencyTreeLimitedDepth(t *testing.T) {
name: "With transitive dependencies",
treeDepth: "1",
expectedUniqueDeps: []string{
"npm://axios:1.13.6",
"npm://axios:1.14.0",
"npm://balaganjs:1.0.0",
"npm://yargs:13.3.0",
"npm://zen-website:1.0.0",
Expand All @@ -53,7 +53,7 @@ func TestBuildDependencyTreeLimitedDepth(t *testing.T) {
Nodes: []*xrayUtils.GraphNode{
{
Id: "npm://balaganjs:1.0.0",
Nodes: []*xrayUtils.GraphNode{{Id: "npm://axios:1.13.6"}, {Id: "npm://yargs:13.3.0"}},
Nodes: []*xrayUtils.GraphNode{{Id: "npm://axios:1.14.0"}, {Id: "npm://yargs:13.3.0"}},
},
},
},
Expand Down
3 changes: 3 additions & 0 deletions sca/bom/xrayplugin/xraylibbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import (
"github.com/jfrog/jfrog-client-go/utils/log"
)

// SnippetDetectionFeatureId is "curation" because snippet detection is gated by the curation entitlement on the Xray server.
const SnippetDetectionFeatureId = "curation"

type XrayLibBomGenerator struct {
binaryPath string
snippetDetection bool
Expand Down
2 changes: 1 addition & 1 deletion utils/results/conversion/convertor.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func parseCommandResults[T interface{}](params ResultConvertParams, parser Resul
if err = parseScaResults(params, parser, cmdResults.CmdType, targetScansResults); err != nil {
return
}
if !cmdResults.EntitledForJas {
if !cmdResults.Entitlements.Jas {
continue
}
if err = parseJasResults(params, parser, targetScansResults); err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (cdc *CmdResultsCycloneDxConverter) Get() (bom *cdxutils.FullBOM, err error
}

func (cdc *CmdResultsCycloneDxConverter) Reset(metadata results.ResultsMetaData, statusCodes results.ResultsStatus, multipleTargets bool) (err error) {
cdc.entitledForJas = metadata.EntitledForJas
cdc.entitledForJas = metadata.Entitlements.Jas
cdc.gitContext = metadata.GitContext
cdc.xrayVersion = metadata.XrayVersion
// Reset the BOM
Expand Down
2 changes: 1 addition & 1 deletion utils/results/conversion/sarifparser/sarifparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (sc *CmdResultsSarifConverter) Reset(metadata results.ResultsMetaData, stat
// Reset the current stream general information
sc.currentCmdType = metadata.CmdType
sc.xrayVersion = metadata.XrayVersion
sc.entitledForJas = metadata.EntitledForJas
sc.entitledForJas = metadata.Entitlements.Jas
sc.status = statusCodes
// Reset the current stream cache information
sc.currentTargetConvertedRuns = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (sjc *CmdResultsSimpleJsonConverter) Reset(metadata results.ResultsMetaData
SastStatusCode: statusCodes.SastScanStatusCode,
},
}
sjc.entitledForJas = metadata.EntitledForJas
sjc.entitledForJas = metadata.Entitlements.Jas
sjc.multipleRoots = multipleTargets
if metadata.GeneralError != nil {
sjc.current.Errors = append(sjc.current.Errors, formats.SimpleJsonError{ErrorMessage: metadata.GeneralError.Error()})
Expand Down
2 changes: 1 addition & 1 deletion utils/results/conversion/summaryparser/summaryparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (sc *CmdResultsSummaryConverter) Get() (formats.ResultsSummary, error) {

func (sc *CmdResultsSummaryConverter) Reset(metadata results.ResultsMetaData, statusCodes results.ResultsStatus, multipleTargets bool) (err error) {
sc.current = &formats.ResultsSummary{}
sc.entitledForJas = metadata.EntitledForJas
sc.entitledForJas = metadata.Entitlements.Jas
sc.status = statusCodes
return
}
Expand Down
4 changes: 2 additions & 2 deletions utils/results/output/resultwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,14 +302,14 @@ func (rw *ResultsWriter) printJasTablesIfNeeded(tableContent formats.ResultsTabl
return
}
if (rw.showViolations || rw.commandResults.HasViolationContext()) && len(rw.commandResults.ResultContext.GitRepoHttpsCloneUrl) > 0 {
if err = PrintJasTable(tableContent, rw.commandResults.EntitledForJas, scanType, true); err != nil {
if err = PrintJasTable(tableContent, rw.commandResults.Entitlements.Jas, scanType, true); err != nil {
return
}
}
if !rw.commandResults.IncludesVulnerabilities() {
return
}
return PrintJasTable(tableContent, rw.commandResults.EntitledForJas, scanType, false)
return PrintJasTable(tableContent, rw.commandResults.Entitlements.Jas, scanType, false)
}

func (rw *ResultsWriter) shouldPrintSecretValidationExtraMessage() bool {
Expand Down
2 changes: 1 addition & 1 deletion utils/results/output/securityJobSummary.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ func RecordSarifOutput(cmdResults *results.SecurityCommandResults, serverDetails
}

func ifNoJasNoGHAS(cmdResults *results.SecurityCommandResults, serverDetails *config.ServerDetails) (extended bool, err error) {
if !cmdResults.EntitledForJas {
if !cmdResults.Entitlements.Jas {
return
}
return commandsummary.CheckExtendedSummaryEntitled(serverDetails.Url)
Expand Down
2 changes: 1 addition & 1 deletion utils/results/output/securityJobSummary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestSaveSarifOutputOnlyForJasEntitled(t *testing.T) {
}

func createDummyJasResult(entitled bool) *results.SecurityCommandResults {
return &results.SecurityCommandResults{ResultsMetaData: results.ResultsMetaData{EntitledForJas: entitled}}
return &results.SecurityCommandResults{ResultsMetaData: results.ResultsMetaData{Entitlements: results.Entitlements{Jas: entitled}}}
}

func hasFilesInDir(t *testing.T, dir string) bool {
Expand Down
36 changes: 23 additions & 13 deletions utils/results/results.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,26 @@ type SecurityCommandResults struct {
}

type ResultsMetaData struct {
XrayVersion string `json:"xray_version"`
XscVersion string `json:"xsc_version,omitempty"`
EntitledForJas bool `json:"jas_entitled"`
SecretValidation bool `json:"secret_validation"`
CmdType utils.CommandType `json:"command_type"`
ResultContext ResultContext `json:"result_context,omitempty"`
GitContext *xscServices.XscGitInfoContext `json:"git_context,omitempty"`
StartTime time.Time `json:"start_time"`
// MultiScanId is a unique identifier that is used to group multiple scans together.
MultiScanId string `json:"multi_scan_id,omitempty"`
ResultsPlatformUrl string `json:"results_platform_url,omitempty"`
MultiScanId string `json:"multi_scan_id,omitempty"`
XrayVersion string `json:"xray_version"`
XscVersion string `json:"xsc_version,omitempty"`
Entitlements Entitlements `json:"entitlements"`
SecretValidation bool `json:"secret_validation"`
CmdType utils.CommandType `json:"command_type"`
ResultContext ResultContext `json:"result_context"`
GitContext *xscServices.XscGitInfoContext `json:"git_context,omitempty"`
StartTime time.Time `json:"start_time"`
ResultsPlatformUrl string `json:"results_platform_url,omitempty"`
// GeneralError that occurred during the command execution
GeneralError error `json:"general_error,omitempty"`
}

type Entitlements struct {
Jas bool `json:"jas"`
SnippetDetection bool `json:"snippet_detection"`
}

// We have three types of results: vulnerabilities, violations and licenses.
// If the user provides a violation context (watches, repo_path, project_key, git_repo_key) the results will only include violations.
// If the user provides a violation context and requests vulnerabilities, the results will include both vulnerabilities and violations.
Expand Down Expand Up @@ -257,7 +262,12 @@ func (r *SecurityCommandResults) SetXscVersion(xscVersion string) *SecurityComma
}

func (r *SecurityCommandResults) SetEntitledForJas(entitledForJas bool) *SecurityCommandResults {
r.EntitledForJas = entitledForJas
r.Entitlements.Jas = entitledForJas
return r
}

func (r *SecurityCommandResults) SetEntitledForSnippetDetection(entitledForSnippetDetection bool) *SecurityCommandResults {
r.Entitlements.SnippetDetection = entitledForSnippetDetection
return r
}

Expand Down Expand Up @@ -354,7 +364,7 @@ func (r *SecurityCommandResults) GetScaScansXrayResults() (results []services.Sc
}

func (r *SecurityCommandResults) HasJasScansResults(scanType jasutils.JasScanType) bool {
if !r.EntitledForJas {
if !r.Entitlements.Jas {
return false
}
for _, target := range r.Targets {
Expand Down Expand Up @@ -441,7 +451,7 @@ func (r *SecurityCommandResults) GetStatusCodes() ResultsStatus {

func (r *SecurityCommandResults) NewScanResults(target ScanTarget) *TargetResults {
targetResults := &TargetResults{ScanTarget: target, errorsMutex: sync.Mutex{}}
if r.EntitledForJas {
if r.Entitlements.Jas {
targetResults.JasResults = &JasScansResults{JasVulnerabilities: JasScanResults{}, JasViolations: JasScanResults{}}
}

Expand Down
Loading