@@ -15,6 +15,7 @@ import (
1515 "github.com/jfrog/froggit-go/vcsclient"
1616 "github.com/jfrog/froggit-go/vcsutils"
1717 "github.com/jfrog/gofrog/version"
18+ "github.com/jfrog/jfrog-cli-security/policy"
1819 "github.com/jfrog/jfrog-cli-security/utils/formats"
1920 "github.com/jfrog/jfrog-cli-security/utils/jasutils"
2021 "github.com/jfrog/jfrog-cli-security/utils/results"
@@ -73,18 +74,25 @@ func (cfp *ScanRepositoryCmd) scanAndFixRepository(repository *utils.Repository,
7374 return
7475 }
7576 log .Debug (fmt .Sprintf ("Detected branches for scan: %s" , strings .Join (repository .Branches , ", " )))
77+ anyHasFailBuild := false
7678 for _ , branch := range repository .Branches {
7779 log .Debug (fmt .Sprintf ("Scanning '%s' branch..." , branch ))
7880 cfp .scanDetails .SetBaseBranch (branch )
7981 cfp .scanDetails .SetXscGitInfoContext (branch , repository .Project , client )
80- if err = cfp .scanAndFixBranch (repository ); err != nil {
81- return
82+ hadFailBuild , e := cfp .scanAndFixBranch (repository )
83+ if e != nil {
84+ return e
8285 }
86+ anyHasFailBuild = anyHasFailBuild || hadFailBuild
87+ }
88+ // Check if we need to output error due to fail the build flag on violations if repository configuration requires it
89+ if repository .FailBuildOnViolations != nil && * repository .FailBuildOnViolations && anyHasFailBuild {
90+ return policy .NewFailBuildError ()
8391 }
8492 return
8593}
8694
87- func (cfp * ScanRepositoryCmd ) scanAndFixBranch (repository * utils.Repository ) (err error ) {
95+ func (cfp * ScanRepositoryCmd ) scanAndFixBranch (repository * utils.Repository ) (hasFailBuild bool , err error ) {
8896 repoDir , restoreBaseDir , err := cfp .cloneRepositoryOrUseLocalAndCheckoutToBranch ()
8997 if err != nil {
9098 return
@@ -115,10 +123,11 @@ func (cfp *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (er
115123 for i := range repository .Projects {
116124 cfp .scanDetails .Project = & repository .Projects [i ]
117125 cfp .projectTech = []techutils.Technology {}
118- if findings , e := cfp .scanAndFixProject (repository ); e != nil {
119- return e
126+ if hasFailBuildInProject , findings , e := cfp .scanAndFixProject (repository ); e != nil {
127+ return false , e
120128 } else {
121129 totalFindings += findings
130+ hasFailBuild = hasFailBuild || hasFailBuildInProject
122131 }
123132 }
124133
@@ -161,8 +170,9 @@ func (cfp *ScanRepositoryCmd) setCommandPrerequisites(repository *utils.Reposito
161170 return
162171}
163172
164- func (cfp * ScanRepositoryCmd ) scanAndFixProject (repository * utils.Repository ) (int , error ) {
173+ func (cfp * ScanRepositoryCmd ) scanAndFixProject (repository * utils.Repository ) (bool , int , error ) {
165174 var isFixNeeded bool
175+ shouldFailBuild := false
166176 totalFindings := 0
167177 // A map that contains the full project paths as a keys
168178 // The value is a map of vulnerable package names -> the scanDetails of the vulnerable packages.
@@ -173,20 +183,12 @@ func (cfp *ScanRepositoryCmd) scanAndFixProject(repository *utils.Repository) (i
173183 scanResults , err := cfp .scan (fullPathWd )
174184 if err != nil {
175185 if err = utils .CreateErrorIfPartialResultsDisabled (cfp .scanDetails .AllowPartialResults (), fmt .Sprintf ("An error occurred during Audit execution for '%s' working directory. Fixes will be skipped for this working directory" , fullPathWd ), err ); err != nil {
176- return totalFindings , err
186+ return shouldFailBuild , totalFindings , err
177187 }
178188 continue
179189 }
180- if summary , err := conversion .NewCommandResultsConvertor (conversion.ResultConvertParams {IncludeVulnerabilities : scanResults .IncludesVulnerabilities (), HasViolationContext : scanResults .HasViolationContext ()}).ConvertToSummary (scanResults ); err != nil {
181- return totalFindings , err
182- } else {
183- findingCount := summary .GetTotalViolations ()
184- if findingCount == 0 {
185- findingCount = summary .GetTotalVulnerabilities ()
186- }
187- totalFindings += findingCount
188- }
189-
190+ totalFindings += getTotalFindingsFromScanResults (scanResults )
191+ shouldFailBuild = shouldFailBuild || (scanResults .Violations != nil && scanResults .Violations .ShouldFailBuild ())
190192 if repository .GitProvider .String () == vcsutils .GitHub .String () {
191193 // Uploads Sarif results to GitHub in order to view the scan in the code scanning UI
192194 // Currently available on GitHub only
@@ -203,42 +205,56 @@ func (cfp *ScanRepositoryCmd) scanAndFixProject(repository *utils.Repository) (i
203205 if repository .DetectionOnly {
204206 continue
205207 }
206-
207208 for _ , target := range scanResults .Targets {
208- targetPath := target .Target
209- convertor := conversion .NewCommandResultsConvertor (conversion.ResultConvertParams {
210- IncludeVulnerabilities : scanResults .IncludesVulnerabilities (),
211- HasViolationContext : scanResults .HasViolationContext (),
212- IncludeTargets : []string {targetPath },
213- })
214- simpleJsonResult , err := convertor .ConvertToSimpleJson (scanResults )
215- if err != nil {
216- if err = utils .CreateErrorIfPartialResultsDisabled (cfp .scanDetails .AllowPartialResults (), fmt .Sprintf ("An error occurred while preparing the vulnerabilities map for '%s' working directory. Fixes will be skipped for this working directory" , targetPath ), err ); err != nil {
217- return totalFindings , err
218- }
219- continue
220- }
221-
222- currPathVulnerabilities , err := cfp .createVulnerabilitiesMapFromSimpleJson (simpleJsonResult )
209+ currPathVulnerabilities , err := cfp .populateTargetResultsInVulnMap (target , scanResults )
223210 if err != nil {
224- if err = utils .CreateErrorIfPartialResultsDisabled (cfp .scanDetails .AllowPartialResults (), fmt .Sprintf ("An error occurred while preparing the vulnerabilities map for '%s' working directory. Fixes will be skipped for this working directory" , targetPath ), err ); err != nil {
225- return totalFindings , err
211+ if err = utils .CreateErrorIfPartialResultsDisabled (cfp .scanDetails .AllowPartialResults (), fmt .Sprintf ("An error occurred while preparing the vulnerabilities map for '%s' working directory. Fixes will be skipped for this working directory" , target . Target ), err ); err != nil {
212+ return shouldFailBuild , totalFindings , err
226213 }
227214 continue
228215 }
229216 if len (currPathVulnerabilities ) > 0 {
230217 isFixNeeded = true
231- log .Debug (fmt .Sprintf ("Found %d fixable vulnerabilities in '%s': %s" , len (currPathVulnerabilities ), targetPath , strings .Join (maps .Keys (currPathVulnerabilities ), ", " )))
218+ log .Debug (fmt .Sprintf ("Found %d fixable vulnerabilities in '%s': %s" , len (currPathVulnerabilities ), target . Target , strings .Join (maps .Keys (currPathVulnerabilities ), ", " )))
232219 }
233- vulnerabilitiesByPathMap [targetPath ] = currPathVulnerabilities
220+ vulnerabilitiesByPathMap [target . Target ] = currPathVulnerabilities
234221 }
235222 }
236223 if repository .DetectionOnly {
237224 log .Info (fmt .Sprintf ("This command is running in detection mode only. To enable automatic fixing of issues, set the '%s' environment variable to 'false'." , utils .DetectionOnlyEnv ))
238225 } else if isFixNeeded {
239- return totalFindings , cfp .fixVulnerablePackages (repository , vulnerabilitiesByPathMap )
226+ return shouldFailBuild , totalFindings , cfp .fixVulnerablePackages (repository , vulnerabilitiesByPathMap )
227+ }
228+ return shouldFailBuild , totalFindings , nil
229+ }
230+
231+ func getTotalFindingsFromScanResults (scanResults * results.SecurityCommandResults ) int {
232+ summary , err := conversion .NewCommandResultsConvertor (conversion.ResultConvertParams {IncludeVulnerabilities : scanResults .IncludesVulnerabilities (), HasViolationContext : scanResults .HasViolationContext ()}).ConvertToSummary (scanResults )
233+ if err != nil {
234+ return 0
235+ }
236+ findingCount := summary .GetTotalViolations ()
237+ if findingCount == 0 {
238+ findingCount = summary .GetTotalVulnerabilities ()
239+ }
240+ return findingCount
241+ }
242+
243+ func (cfp * ScanRepositoryCmd ) populateTargetResultsInVulnMap (target * results.TargetResults , scanResults * results.SecurityCommandResults ) (map [string ]* utils.VulnerabilityDetails , error ) {
244+ convertor := conversion .NewCommandResultsConvertor (conversion.ResultConvertParams {
245+ IncludeVulnerabilities : scanResults .IncludesVulnerabilities (),
246+ HasViolationContext : scanResults .HasViolationContext (),
247+ IncludeTargets : []string {target .Target },
248+ })
249+ simpleJsonResult , err := convertor .ConvertToSimpleJson (scanResults )
250+ if err != nil {
251+ return nil , fmt .Errorf ("an error occurred while converting scan results to simple json for target '%s': %w" , target .Target , err )
252+ }
253+ currPathVulnerabilities , err := cfp .createVulnerabilitiesMapFromSimpleJson (simpleJsonResult )
254+ if err != nil {
255+ return nil , fmt .Errorf ("an error occurred while creating vulnerabilities map from simple json for target '%s': %w" , target .Target , err )
240256 }
241- return totalFindings , nil
257+ return currPathVulnerabilities , nil
242258}
243259
244260// Audit the dependencies of the current commit.
0 commit comments