Skip to content

Commit 76dabd9

Browse files
authored
XRAY-128408 - Add Sast rules flag to audit command (jfrog#598)
1 parent eb980ad commit 76dabd9

File tree

7 files changed

+67
-10
lines changed

7 files changed

+67
-10
lines changed

cli/docs/flags.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ const (
5656
Sast = "sast"
5757
Secrets = "secrets"
5858
WithoutCA = "without-contextual-analysis"
59+
60+
// Sast related flags
61+
AddSastRules = "add-sast-rules"
5962
)
6063

6164
const (
@@ -171,7 +174,7 @@ var commandFlags = map[string][]string{
171174
useWrapperAudit, DepType, RequirementsFile, Fail, ExtendedTable, WorkingDirs, ExclusionsAudit, Mvn, Gradle, Npm,
172175
Pnpm, Yarn, Go, Swift, Cocoapods, Nuget, Pip, Pipenv, Poetry, MinSeverity, FixableOnly, ThirdPartyContextualAnalysis, Threads,
173176
Sca, Iac, Sast, Secrets, WithoutCA, ScanVuln, SecretValidation, OutputDir, SkipAutoInstall, AllowPartialResults, MaxTreeDepth,
174-
StaticSca, XrayLibPluginBinaryCustomPath, AnalyzerManagerCustomPath,
177+
StaticSca, XrayLibPluginBinaryCustomPath, AnalyzerManagerCustomPath, AddSastRules,
175178
},
176179
UploadCdx: {
177180
UploadRepoPath, uploadProjectKey,
@@ -187,7 +190,7 @@ var commandFlags = map[string][]string{
187190
// Output params
188191
Licenses, OutputFormat, ExtendedTable, OutputDir,
189192
// Scan Logic params
190-
StaticSca, XrayLibPluginBinaryCustomPath, AnalyzerManagerCustomPath,
193+
StaticSca, XrayLibPluginBinaryCustomPath, AnalyzerManagerCustomPath, AddSastRules,
191194
},
192195
CurationAudit: {
193196
CurationOutput, WorkingDirs, Threads, RequirementsFile, InsecureTls, useWrapperAudit,
@@ -307,6 +310,8 @@ var flagsMap = map[string]components.Flag{
307310
WithoutCA: components.NewBoolFlag(WithoutCA, fmt.Sprintf("Selective scanners mode: Disable Contextual Analysis scanner after SCA. Relevant only with --%s flag.", Sca)),
308311
SecretValidation: components.NewBoolFlag(SecretValidation, fmt.Sprintf("Selective scanners mode: Triggers token validation on found secrets. Relevant only with --%s flag.", Secrets)),
309312

313+
AddSastRules: components.NewStringFlag(AddSastRules, "Incorporate any additional SAST rules (in JSON format, with absolute path) into this local scan."),
314+
310315
// Git flags
311316
InputFile: components.NewStringFlag(InputFile, "Path to an input file in YAML format contains multiple git providers. With this option, all other scm flags will be ignored and only git servers mentioned in the file will be examined.."),
312317
ScmType: components.NewStringFlag(ScmType, fmt.Sprintf("SCM type. Possible values are: %s.", contributors.NewScmType().GetValidScmTypeString()), components.SetMandatory()),

cli/scancommands.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"os"
7+
"slices"
78
"strings"
89

910
buildInfoUtils "github.com/jfrog/build-info-go/utils"
@@ -27,11 +28,13 @@ import (
2728
dockerScanDocs "github.com/jfrog/jfrog-cli-security/cli/docs/scan/dockerscan"
2829
scanDocs "github.com/jfrog/jfrog-cli-security/cli/docs/scan/scan"
2930
uploadCdxDocs "github.com/jfrog/jfrog-cli-security/cli/docs/upload"
31+
"github.com/jfrog/jfrog-cli-security/utils"
3032

3133
"github.com/jfrog/jfrog-cli-security/commands/enrich"
3234
"github.com/jfrog/jfrog-cli-security/commands/source_mcp"
3335
"github.com/jfrog/jfrog-cli-security/sca/bom/indexer"
3436
"github.com/jfrog/jfrog-cli-security/utils/xray"
37+
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
3538
"github.com/jfrog/jfrog-client-go/utils/log"
3639
"github.com/urfave/cli"
3740

@@ -412,6 +415,21 @@ func AuditCmd(c *components.Context) error {
412415
auditCmd.SetScansToPerform(subScans)
413416
}
414417

418+
// Validate that there is a sast scan before setting the sast rules
419+
if sastRulesFile := c.GetStringFlagValue(flags.AddSastRules); sastRulesFile != "" {
420+
// Check if file exists
421+
if exists, err := fileutils.IsFileExists(sastRulesFile, false); err != nil || !exists {
422+
return pluginsCommon.PrintHelpAndReturnError(fmt.Sprintf("file '%s' does not exist: %s", sastRulesFile, err.Error()), c)
423+
}
424+
425+
// Validate scan is performed
426+
if len(auditCmd.ScansToPerform()) > 0 && !slices.Contains(auditCmd.ScansToPerform(), utils.SastScan) {
427+
return pluginsCommon.PrintHelpAndReturnError(fmt.Sprintf("flag '--%s' can only be used with '--%s'", flags.AddSastRules, flags.Sast), c)
428+
}
429+
430+
auditCmd.SetSastRules(sastRulesFile)
431+
}
432+
415433
threads, err := pluginsCommon.GetThreadsCount(c)
416434
if err != nil {
417435
return err

commands/audit/audit.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ func createJasScansTask(auditParallelRunner *utils.SecurityParallelRunner, scanR
625625
ThirdPartyApplicabilityScan: auditParams.thirdPartyApplicabilityScan,
626626
ApplicableScanType: applicability.ApplicabilityScannerType,
627627
SignedDescriptions: getSignedDescriptions(auditParams.OutputFormat()),
628+
SastRules: auditParams.SastRules(),
628629
ScanResults: targetResult,
629630
TargetOutputDir: auditParams.scanResultsOutputDir,
630631
AllowPartialResults: auditParams.AllowPartialResults(),

commands/audit/auditparams.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type AuditParams struct {
3535
bomGenerator bom.SbomGenerator
3636
customBomGenBinaryPath string
3737
scaScanStrategy scan.SbomScanStrategy
38+
sastRules string
3839
// Diff mode, scan only the files affected by the diff.
3940
diffMode bool
4041
filesToScan []string
@@ -100,6 +101,15 @@ func (params *AuditParams) CustomAnalyzerManagerBinaryPath() string {
100101
return params.customAnalyzerManagerBinaryPath
101102
}
102103

104+
func (params *AuditParams) SetSastRules(sastRules string) *AuditParams {
105+
params.sastRules = sastRules
106+
return params
107+
}
108+
109+
func (params *AuditParams) SastRules() string {
110+
return params.sastRules
111+
}
112+
103113
func (params *AuditParams) SetScaScanStrategy(scaScanStrategy scan.SbomScanStrategy) *AuditParams {
104114
params.scaScanStrategy = scaScanStrategy
105115
return params

jas/runner/jasrunner.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type JasRunnerParams struct {
4343
ThirdPartyApplicabilityScan bool
4444
// SAST scan flags
4545
SignedDescriptions bool
46+
SastRules string
4647
// Outputs
4748
ScanResults *results.TargetResults
4849
TargetOutputDir string
@@ -177,7 +178,7 @@ func runSastScan(params *JasRunnerParams) parallel.TaskFunc {
177178
defer func() {
178179
params.Runner.JasScannersWg.Done()
179180
}()
180-
vulnerabilitiesResults, violationsResults, err := sast.RunSastScan(params.Scanner, params.Module, params.SignedDescriptions, threadId, getSourceRunsToCompare(params, jasutils.Sast)...)
181+
vulnerabilitiesResults, violationsResults, err := sast.RunSastScan(params.Scanner, params.Module, params.SignedDescriptions, params.SastRules, threadId, getSourceRunsToCompare(params, jasutils.Sast)...)
181182
params.Runner.ResultsMu.Lock()
182183
defer params.Runner.ResultsMu.Unlock()
183184
// We first add the scan results and only then check for errors, so we can store the exit code in order to report it in the end

jas/sast/sastscanner.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@ const (
2424
type SastScanManager struct {
2525
scanner *jas.JasScanner
2626
signedDescriptions bool
27+
sastRules string
2728

2829
resultsToCompareFileName string
2930
configFileName string
3031
resultsFileName string
3132
}
3233

33-
func RunSastScan(scanner *jas.JasScanner, module jfrogappsconfig.Module, signedDescriptions bool, threadId int, resultsToCompare ...*sarif.Run) (vulnerabilitiesResults []*sarif.Run, violationsResults []*sarif.Run, err error) {
34+
func RunSastScan(scanner *jas.JasScanner, module jfrogappsconfig.Module, signedDescriptions bool, sastRules string, threadId int, resultsToCompare ...*sarif.Run) (vulnerabilitiesResults []*sarif.Run, violationsResults []*sarif.Run, err error) {
3435
var scannerTempDir string
3536
if scannerTempDir, err = jas.CreateScannerTempDirectory(scanner, jasutils.Sast.String(), threadId); err != nil {
3637
return
3738
}
38-
sastScanManager, err := newSastScanManager(scanner, scannerTempDir, signedDescriptions, resultsToCompare...)
39+
sastScanManager, err := newSastScanManager(scanner, scannerTempDir, signedDescriptions, sastRules, resultsToCompare...)
3940
if err != nil {
4041
return
4142
}
@@ -47,10 +48,11 @@ func RunSastScan(scanner *jas.JasScanner, module jfrogappsconfig.Module, signedD
4748
return
4849
}
4950

50-
func newSastScanManager(scanner *jas.JasScanner, scannerTempDir string, signedDescriptions bool, resultsToCompare ...*sarif.Run) (manager *SastScanManager, err error) {
51+
func newSastScanManager(scanner *jas.JasScanner, scannerTempDir string, signedDescriptions bool, sastRules string, resultsToCompare ...*sarif.Run) (manager *SastScanManager, err error) {
5152
manager = &SastScanManager{
5253
scanner: scanner,
5354
signedDescriptions: signedDescriptions,
55+
sastRules: sastRules,
5456
configFileName: filepath.Join(scannerTempDir, "config.yaml"),
5557
resultsFileName: filepath.Join(scannerTempDir, "results.sarif"),
5658
}
@@ -94,6 +96,7 @@ type scanConfiguration struct {
9496
ExcludePatterns []string `yaml:"exclude_patterns,omitempty"`
9597
ExcludedRules []string `yaml:"excluded-rules,omitempty"`
9698
SastParameters sastParameters `yaml:"sast_parameters,omitempty"`
99+
UserRules string `yaml:"user_rules,omitempty"`
97100
}
98101

99102
type sastParameters struct {
@@ -122,6 +125,7 @@ func (ssm *SastScanManager) createConfigFile(module jfrogappsconfig.Module, sign
122125
SignedDescriptions: signedDescriptions,
123126
},
124127
ExcludePatterns: jas.GetExcludePatterns(module, &sastScanner.Scanner, exclusions...),
128+
UserRules: ssm.sastRules,
125129
},
126130
},
127131
}

jas/sast/sastscanner_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestNewSastScanManager(t *testing.T) {
2323
jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{"currentDir"})
2424
assert.NoError(t, err)
2525
// Act
26-
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", true)
26+
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", true, "")
2727
assert.NoError(t, err)
2828

2929
// Assert
@@ -33,6 +33,7 @@ func TestNewSastScanManager(t *testing.T) {
3333
assert.NotEmpty(t, sastScanManager.resultsFileName)
3434
assert.NotEmpty(t, jfrogAppsConfigForTest.Modules[0].SourceRoot)
3535
assert.Equal(t, &jas.FakeServerDetails, sastScanManager.scanner.ServerDetails)
36+
assert.Empty(t, sastScanManager.sastRules)
3637
}
3738
}
3839

@@ -46,7 +47,7 @@ func TestNewSastScanManagerWithFilesToCompare(t *testing.T) {
4647
scannerTempDir, err := jas.CreateScannerTempDirectory(scanner, jasutils.Secrets.String(), 0)
4748
require.NoError(t, err)
4849

49-
sastScanManager, err := newSastScanManager(scanner, scannerTempDir, false, sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyResult("test-markdown", "test-msg", "test-rule-id", "note")))
50+
sastScanManager, err := newSastScanManager(scanner, scannerTempDir, false, "", sarifutils.CreateRunWithDummyResults(sarifutils.CreateDummyResult("test-markdown", "test-msg", "test-rule-id", "note")))
5051
require.NoError(t, err)
5152

5253
// Check if path value exists and file is created
@@ -61,7 +62,7 @@ func TestSastParseResults_EmptyResults(t *testing.T) {
6162
assert.NoError(t, err)
6263

6364
// Arrange
64-
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", true)
65+
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", true, "")
6566
assert.NoError(t, err)
6667
sastScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "sast-scan", "no-violations.sarif")
6768

@@ -84,7 +85,7 @@ func TestSastParseResults_ResultsContainIacViolations(t *testing.T) {
8485
jfrogAppsConfigForTest, err := jas.CreateJFrogAppsConfig([]string{})
8586
assert.NoError(t, err)
8687
// Arrange
87-
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", false)
88+
sastScanManager, err := newSastScanManager(scanner, "temoDirPath", false, "")
8889
assert.NoError(t, err)
8990
sastScanManager.resultsFileName = filepath.Join(jas.GetTestDataPath(), "sast-scan", "contains-sast-violations.sarif")
9091

@@ -186,3 +187,20 @@ func TestGroupResultsByLocation(t *testing.T) {
186187
assert.ElementsMatch(t, test.expectedOutput.Results, test.run.Results)
187188
}
188189
}
190+
191+
func TestSastRules(t *testing.T) {
192+
scanner, cleanUp := jas.InitJasTest(t)
193+
defer cleanUp()
194+
tempDir, cleanUpTempDir := coreTests.CreateTempDirWithCallbackAndAssert(t)
195+
defer cleanUpTempDir()
196+
197+
scanner.TempDir = tempDir
198+
scannerTempDir, err := jas.CreateScannerTempDirectory(scanner, jasutils.Sast.String(), 0)
199+
require.NoError(t, err)
200+
201+
sastScanManager, err := newSastScanManager(scanner, scannerTempDir, false, "test-rules.json")
202+
require.NoError(t, err)
203+
assert.Equal(t, "test-rules.json", sastScanManager.sastRules)
204+
assert.Equal(t, filepath.Join(scannerTempDir, "config.yaml"), sastScanManager.configFileName)
205+
assert.Equal(t, filepath.Join(scannerTempDir, "results.sarif"), sastScanManager.resultsFileName)
206+
}

0 commit comments

Comments
 (0)