diff --git a/audit_test.go b/audit_test.go
index 0f08f63e..54856d43 100644
--- a/audit_test.go
+++ b/audit_test.go
@@ -808,7 +808,7 @@ type auditCommandTestParams struct {
// --project flag value if provided.
ProjectKey string
// --fail flag value if provided, must be provided with 'createWatchesFuncs' to create watches for the test
- FailOnFailedBuildFlag bool
+ DisableFailOnFailedBuildFlag bool
// -- vuln flag 'True' value must be provided with 'createWatchesFuncs' to create watches for the test
WithVuln bool
// --licenses flag value if provided
@@ -836,12 +836,9 @@ func testAuditCommand(t *testing.T, testCli *coreTests.JfrogCli, params auditCom
if len(params.Watches) > 0 {
args = append(args, "--watches="+strings.Join(params.Watches, ","))
}
- if params.FailOnFailedBuildFlag {
- if len(params.Watches) == 0 {
- // Verify params consistency no fail flag
- assert.False(t, params.FailOnFailedBuildFlag, "Fail flag provided without watches")
- }
- args = append(args, "--fail")
+ // Default value for --fail flag is 'true'. Unless we directly pass DisableFailOnFailedBuildFlag=true, the flow will fail when security issues are found
+ if params.DisableFailOnFailedBuildFlag {
+ args = append(args, "--fail=false")
}
if params.WithVuln {
args = append(args, "--vuln")
diff --git a/commands/audit/sca/python/python.go b/commands/audit/sca/python/python.go
index c8578fbd..c9005130 100644
--- a/commands/audit/sca/python/python.go
+++ b/commands/audit/sca/python/python.go
@@ -112,7 +112,7 @@ func getDependencies(auditPython *AuditPython) (dependenciesGraph map[string][]s
if err != nil {
return
}
- dependenciesGraph, directDependencies, err = pythonutils.GetPythonDependencies(auditPython.Tool, tempDirPath, localDependenciesPath)
+ dependenciesGraph, directDependencies, err = pythonutils.GetPythonDependencies(auditPython.Tool, tempDirPath, localDependenciesPath, log.GetLogger())
if err != nil {
sca.LogExecutableVersion("python")
sca.LogExecutableVersion(string(auditPython.Tool))
diff --git a/commands/audit/scarunner.go b/commands/audit/scarunner.go
index abbe9451..df4fbc43 100644
--- a/commands/audit/scarunner.go
+++ b/commands/audit/scarunner.go
@@ -169,7 +169,7 @@ func runScaWithTech(tech techutils.Technology, params *AuditParams, serverDetail
if err != nil {
return
}
- log.Debug(fmt.Sprintf("Finished '%s' dependency tree scan. %s", tech.ToFormal(), utils.GetScanFindingsLog(utils.ScaScan, len(techResults[0].Vulnerabilities), len(techResults[0].Violations), -1)))
+ log.Info(fmt.Sprintf("Finished '%s' dependency tree scan. %s", tech.ToFormal(), utils.GetScanFindingsLog(utils.ScaScan, len(techResults[0].Vulnerabilities), len(techResults[0].Violations), -1)))
techResults = sca.BuildImpactPathsForScanResponse(techResults, fullDependencyTrees)
return
}
diff --git a/go.mod b/go.mod
index bb324514..63e4fc20 100644
--- a/go.mod
+++ b/go.mod
@@ -6,18 +6,18 @@ require (
github.com/beevik/etree v1.4.0
github.com/google/go-github/v56 v56.0.0
github.com/gookit/color v1.5.4
- github.com/jfrog/build-info-go v1.10.7
+ github.com/jfrog/build-info-go v1.10.8
github.com/jfrog/froggit-go v1.16.2
github.com/jfrog/gofrog v1.7.6
github.com/jfrog/jfrog-apps-config v1.0.1
- github.com/jfrog/jfrog-cli-core/v2 v2.57.5
- github.com/jfrog/jfrog-client-go v1.48.6
+ github.com/jfrog/jfrog-cli-core/v2 v2.57.6
+ github.com/jfrog/jfrog-client-go v1.49.0
github.com/magiconair/properties v1.8.9
github.com/owenrumney/go-sarif/v2 v2.3.0
github.com/stretchr/testify v1.10.0
github.com/urfave/cli v1.22.16
github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74
- golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
+ golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
golang.org/x/sync v0.10.0
golang.org/x/text v0.21.0
gopkg.in/yaml.v3 v3.0.1
@@ -100,21 +100,21 @@ require (
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
- golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/crypto v0.32.0 // indirect
golang.org/x/mod v0.22.0 // indirect
- golang.org/x/net v0.33.0 // indirect
+ golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
- golang.org/x/sys v0.28.0 // indirect
- golang.org/x/term v0.27.0 // indirect
+ golang.org/x/sys v0.29.0 // indirect
+ golang.org/x/term v0.28.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.27.0 // indirect
+ golang.org/x/tools v0.29.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
-replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20241230154616-e342ed5065f1
+// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go dev
-replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6
+// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 dev
// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev
diff --git a/go.sum b/go.sum
index 25024829..3ce66d00 100644
--- a/go.sum
+++ b/go.sum
@@ -119,18 +119,18 @@ github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3N
github.com/jedib0t/go-pretty/v6 v6.6.5/go.mod h1:Uq/HrbhuFty5WSVNfjpQQe47x16RwVGXIveNGEyGtHs=
github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI=
github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw=
-github.com/jfrog/build-info-go v1.10.7 h1:10NVHYg0193gJpQft+S4WQfvYMtj5jlwwhJRvkFJtBE=
-github.com/jfrog/build-info-go v1.10.7/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE=
+github.com/jfrog/build-info-go v1.10.8 h1:8D4wtvKzLS1hzfDWtfH4OliZLtLCgL62tXCnGWDXuac=
+github.com/jfrog/build-info-go v1.10.8/go.mod h1:JcISnovFXKx3wWf3p1fcMmlPdt6adxScXvoJN4WXqIE=
github.com/jfrog/froggit-go v1.16.2 h1:F//S83iXH14qsCwYzv0zB2JtjS2pJVEsUoEmYA+37dQ=
github.com/jfrog/froggit-go v1.16.2/go.mod h1:5VpdQfAcbuyFl9x/x8HGm7kVk719kEtW/8YJFvKcHPA=
github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s=
github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4=
github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY=
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
-github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6 h1:/i1sIQS0q0gRN531ChVToQWcjaVZOKZ4KuGk7j7vDTc=
-github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6/go.mod h1:LfKvCRXbvwgE0V6aX3/GabkzCedghXq0Y6lmsEuxr44=
-github.com/jfrog/jfrog-client-go v1.28.1-0.20241230154616-e342ed5065f1 h1:JQvbTSPDkPNpts1NLHGTKvtG4cMFY1ptBHTNMYFyMhs=
-github.com/jfrog/jfrog-client-go v1.28.1-0.20241230154616-e342ed5065f1/go.mod h1:2ySOMva54L3EYYIlCBYBTcTgqfrrQ19gtpA/MWfA/ec=
+github.com/jfrog/jfrog-cli-core/v2 v2.57.6 h1:kI5BqDW8Q4R5HkTUPSAObTqyIgQ9z7DqeFYGOEC1zPk=
+github.com/jfrog/jfrog-cli-core/v2 v2.57.6/go.mod h1:h5pzOZUb5ChGcGrXCYr3nPyXcTZjeGW2Rm1Zceo8Afg=
+github.com/jfrog/jfrog-client-go v1.49.0 h1:NaTK6+LQBEJafL//6ntnS/eVx1dZMJnxydALwWHKORQ=
+github.com/jfrog/jfrog-client-go v1.49.0/go.mod h1:ohIfKpMBCQsE9kunrKQ1wvoExpqsPLaluRFO186B5EM=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
@@ -287,10 +287,10 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
-golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
-golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
-golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
+golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
+golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
+golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
@@ -308,8 +308,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
-golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
-golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@@ -346,16 +346,16 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
-golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
-golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -373,8 +373,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
-golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
+golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
+golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
diff --git a/jas/runner/jasrunner.go b/jas/runner/jasrunner.go
index 21f1d543..534a2053 100644
--- a/jas/runner/jasrunner.go
+++ b/jas/runner/jasrunner.go
@@ -1,7 +1,7 @@
package runner
import (
- "encoding/json"
+ "errors"
"fmt"
"github.com/jfrog/gofrog/parallel"
@@ -141,7 +141,7 @@ func runSecretsScan(securityParallelRunner *utils.SecurityParallelRunner, scanne
if err = jas.ParseAnalyzerManagerError(jasutils.Secrets, err); err != nil {
return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error())
}
- return dumpSarifRunToFileIfNeeded(vulnerabilitiesResults, scansOutputDir, jasutils.Secrets)
+ return dumpSarifRunToFileIfNeeded(scansOutputDir, jasutils.Secrets, vulnerabilitiesResults, violationsResults)
}
}
@@ -159,7 +159,7 @@ func runIacScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *j
if err = jas.ParseAnalyzerManagerError(jasutils.IaC, err); err != nil {
return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error())
}
- return dumpSarifRunToFileIfNeeded(vulnerabilitiesResults, scansOutputDir, jasutils.IaC)
+ return dumpSarifRunToFileIfNeeded(scansOutputDir, jasutils.IaC, vulnerabilitiesResults, violationsResults)
}
}
@@ -177,7 +177,7 @@ func runSastScan(securityParallelRunner *utils.SecurityParallelRunner, scanner *
if err = jas.ParseAnalyzerManagerError(jasutils.Sast, err); err != nil {
return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error())
}
- return dumpSarifRunToFileIfNeeded(vulnerabilitiesResults, scansOutputDir, jasutils.Sast)
+ return dumpSarifRunToFileIfNeeded(scansOutputDir, jasutils.Sast, vulnerabilitiesResults, violationsResults)
}
}
@@ -193,22 +193,29 @@ func runContextualScan(securityParallelRunner *utils.SecurityParallelRunner, sca
securityParallelRunner.ResultsMu.Lock()
defer securityParallelRunner.ResultsMu.Unlock()
// 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
- scanResults.JasResults.NewApplicabilityScanResults(jas.GetAnalyzerManagerExitCode(err), caScanResults...)
+ scanResults.JasResults.AddApplicabilityScanResults(jas.GetAnalyzerManagerExitCode(err), caScanResults...)
if err = jas.ParseAnalyzerManagerError(jasutils.Applicability, err); err != nil {
return fmt.Errorf("%s%s", clientutils.GetLogMsgPrefix(threadId, false), err.Error())
}
- return dumpSarifRunToFileIfNeeded(caScanResults, scansOutputDir, jasutils.Applicability)
+ return dumpSarifRunToFileIfNeeded(scansOutputDir, jasutils.Applicability, caScanResults)
}
}
// If an output dir was provided through --output-dir flag, we create in the provided path new file containing the scan results
-func dumpSarifRunToFileIfNeeded(results []*sarif.Run, scanResultsOutputDir string, scanType jasutils.JasScanType) (err error) {
- if scanResultsOutputDir == "" || results == nil {
+func dumpSarifRunToFileIfNeeded(scanResultsOutputDir string, scanType jasutils.JasScanType, scanResults ...[]*sarif.Run) (err error) {
+ if scanResultsOutputDir == "" || len(scanResults) == 0 {
return
}
- fileContent, err := json.Marshal(results)
- if err != nil {
- return fmt.Errorf("failed to write %s scan results to file: %s", scanType, err.Error())
+ var fileContent []byte
+ for _, resultsToDump := range scanResults {
+ if len(resultsToDump) == 0 {
+ continue
+ }
+ if fileContent, err = utils.GetAsJsonBytes(resultsToDump, true, true); err != nil {
+ err = errors.Join(err, fmt.Errorf("failed to write %s scan results to file", scanType))
+ } else {
+ err = errors.Join(err, utils.DumpContentToFile(fileContent, scanResultsOutputDir, scanType.String()))
+ }
}
- return utils.DumpContentToFile(fileContent, scanResultsOutputDir, scanType.String())
+ return
}
diff --git a/tests/testdata/output/jobSummary/binary_analytics_vulnerabilities.md b/tests/testdata/output/jobSummary/binary_analytics_vulnerabilities.md
index 90496612..fe04d2d3 100644
--- a/tests/testdata/output/jobSummary/binary_analytics_vulnerabilities.md
+++ b/tests/testdata/output/jobSummary/binary_analytics_vulnerabilities.md
@@ -1 +1 @@
-
44 Security issues are grouped by CVE number:	44 SCA
❗️ 33 Critical
🟡 11 Low
See the results of the scan in JFrog
\ No newline at end of file
+44 Security issues are grouped by CVE number:	44 SCA
❗️ 33 Critical
🟡 11 Low
See the results of the scan in JFrog
\ No newline at end of file
diff --git a/tests/testdata/output/jobSummary/build_scan_analytics_vulnerabilities.md b/tests/testdata/output/jobSummary/build_scan_analytics_vulnerabilities.md
index 904377a1..ffd0946a 100644
--- a/tests/testdata/output/jobSummary/build_scan_analytics_vulnerabilities.md
+++ b/tests/testdata/output/jobSummary/build_scan_analytics_vulnerabilities.md
@@ -1 +1 @@
-24 Security Issues:	24 SCA
🔴 3 High
🟠 1 Medium
⚪️ 20 Unknown
See the results of the scan in JFrog
\ No newline at end of file
+24 Security Issues:	24 SCA
🔴 3 High
🟠 1 Medium
⚪️ 20 Unknown
See the results of the scan in JFrog
\ No newline at end of file
diff --git a/tests/testdata/output/jobSummary/violations_analytics.md b/tests/testdata/output/jobSummary/violations_analytics.md
index 15766051..4fcf9906 100644
--- a/tests/testdata/output/jobSummary/violations_analytics.md
+++ b/tests/testdata/output/jobSummary/violations_analytics.md
@@ -1 +1 @@
-watches:
watch1, watch2, watch3, watch4
watch5
23 Policy Violations:	17 Security	2 Operational	1 License	3 Secrets
❗️ 8 Critical (2 Not Applicable)
🔴 6 High
🟠 3 Medium
🟡 5 Low (3 Not Applicable)
⚪️ 1 Unknown
See the results of the scan in JFrog
\ No newline at end of file
+watches:
watch1, watch2, watch3, watch4
watch5
23 Policy Violations:	17 Security	2 Operational	1 License	3 Secrets
❗️ 8 Critical (2 Not Applicable)
🔴 6 High
🟠 3 Medium
🟡 5 Low (3 Not Applicable)
⚪️ 1 Unknown
See the results of the scan in JFrog
\ No newline at end of file
diff --git a/tests/testdata/projects/package-managers/python/poetry/poetry-project/poetry.lock b/tests/testdata/projects/package-managers/python/poetry/poetry-project/poetry.lock
index 832846f6..f071fc52 100644
--- a/tests/testdata/projects/package-managers/python/poetry/poetry-project/poetry.lock
+++ b/tests/testdata/projects/package-managers/python/poetry/poetry-project/poetry.lock
@@ -1,10 +1,15 @@
+# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
+
[[package]]
name = "django"
version = "1.11.15"
description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design."
-category = "main"
optional = false
python-versions = "*"
+files = [
+ {file = "Django-1.11.15-py2.py3-none-any.whl", hash = "sha256:8176ac7985fe6737ce3d6b2531b4a2453cb7c3377c9db00bacb2b3320f4a1311"},
+ {file = "Django-1.11.15.tar.gz", hash = "sha256:b18235d82426f09733d2de9910cee975cf52ff05e5f836681eb957d105a05a40"},
+]
[package.dependencies]
pytz = "*"
@@ -15,50 +20,41 @@ bcrypt = ["bcrypt"]
[[package]]
name = "pytz"
-version = "2022.2.1"
+version = "2024.2"
description = "World timezone definitions, modern and historical"
-category = "main"
optional = false
python-versions = "*"
+files = [
+ {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
+ {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
+]
[[package]]
name = "urllib3"
version = "1.22"
description = "HTTP library with thread-safe connection pooling, file post, and more."
-category = "main"
optional = false
python-versions = "*"
+files = [
+ {file = "urllib3-1.22-py2.py3-none-any.whl", hash = "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b"},
+ {file = "urllib3-1.22.tar.gz", hash = "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"},
+]
[package.extras]
-secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "werkzeug"
version = "0.9.6"
description = "The Swiss Army knife of Python web development"
-category = "main"
optional = false
python-versions = "*"
+files = [
+ {file = "Werkzeug-0.9.6.tar.gz", hash = "sha256:7f11e7e2e73eb22677cac1b11113eb6106f66cedef13d140e83cf6563c90b79c"},
+]
[metadata]
-lock-version = "1.1"
+lock-version = "2.0"
python-versions = "*"
-content-hash = "ca39a9fcd59a5de98126ed6aa586f5730905182cc671df01d5df02f4a15ef417"
-
-[metadata.files]
-django = [
- {file = "Django-1.11.15-py2.py3-none-any.whl", hash = "sha256:8176ac7985fe6737ce3d6b2531b4a2453cb7c3377c9db00bacb2b3320f4a1311"},
- {file = "Django-1.11.15.tar.gz", hash = "sha256:b18235d82426f09733d2de9910cee975cf52ff05e5f836681eb957d105a05a40"},
-]
-pytz = [
- {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"},
- {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"},
-]
-urllib3 = [
- {file = "urllib3-1.22-py2.py3-none-any.whl", hash = "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b"},
- {file = "urllib3-1.22.tar.gz", hash = "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"},
-]
-werkzeug = [
- {file = "Werkzeug-0.9.6.tar.gz", hash = "sha256:7f11e7e2e73eb22677cac1b11113eb6106f66cedef13d140e83cf6563c90b79c"},
-]
+content-hash = "7b951bed28e7a8ff330c4741df89a9ff94d508e1922c43a6bd27940460be400e"
diff --git a/tests/testdata/projects/package-managers/python/poetry/poetry-project/pyproject.toml b/tests/testdata/projects/package-managers/python/poetry/poetry-project/pyproject.toml
index 71980436..d1293a06 100644
--- a/tests/testdata/projects/package-managers/python/poetry/poetry-project/pyproject.toml
+++ b/tests/testdata/projects/package-managers/python/poetry/poetry-project/pyproject.toml
@@ -3,6 +3,7 @@ name = "poetry-project"
version = "0.1.0"
description = ""
authors = ["Your Name "]
+package-mode = false
[tool.poetry.dependencies]
python = "*"
@@ -10,7 +11,7 @@ urllib3 = "<1.24"
django = "<1.11.16"
Werkzeug = "<0.10"
-[tool.poetry.dev-dependencies]
+[tool.poetry.group.dev.dependencies]
[build-system]
requires = ["poetry-core>=1.0.0"]
diff --git a/tests/testdata/projects/package-managers/python/poetry/poetry/pyproject.toml b/tests/testdata/projects/package-managers/python/poetry/poetry/pyproject.toml
index 00c4eb5a..5c4946d9 100644
--- a/tests/testdata/projects/package-managers/python/poetry/poetry/pyproject.toml
+++ b/tests/testdata/projects/package-managers/python/poetry/poetry/pyproject.toml
@@ -3,6 +3,7 @@ name = "my-poetry-project"
version = "1.1.0"
description = ""
authors = ["Severus Snape "]
+package-mode = false
[tool.poetry.dependencies]
python = "^3.10"
diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go
index d7e5771e..97ed1b9b 100644
--- a/tests/utils/test_utils.go
+++ b/tests/utils/test_utils.go
@@ -59,13 +59,8 @@ func ValidateXrayVersion(t *testing.T, minVersion string) {
}
}
-func ValidateXscVersion(t *testing.T, minVersion string) {
- xscVersion, err := getTestsXscVersion()
- if err != nil {
- t.Skip(err)
- }
- err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, xscVersion.GetVersion(), minVersion)
- if err != nil {
+func ValidateXscVersion(t *testing.T, xscVersion, minVersion string) {
+ if err := clientUtils.ValidateMinimumVersion(clientUtils.Xsc, xscVersion, minVersion); err != nil {
t.Skip(err)
}
}
@@ -99,11 +94,6 @@ func GetTestsXrayVersion() (version.Version, error) {
return *version.NewVersion(xrayVersion), err
}
-func getTestsXscVersion() (version.Version, error) {
- xscVersion, err := configTests.XscAuth.GetVersion()
- return *version.NewVersion(xscVersion), err
-}
-
func ChangeWD(t *testing.T, newPath string) string {
prevDir, err := os.Getwd()
assert.NoError(t, err, "Failed to get current dir")
@@ -297,11 +287,11 @@ func CreateSecurityPolicy(t *testing.T, policyName string, rules ...xrayUtils.Po
}
}
-func CreateTestSecurityPolicy(t *testing.T, policyName string, severity xrayUtils.Severity, failBuild bool) (string, func()) {
+func CreateTestSecurityPolicy(t *testing.T, policyName string, severity xrayUtils.Severity, failBuild bool, skipNotApplicable bool) (string, func()) {
return CreateSecurityPolicy(t, policyName,
xrayUtils.PolicyRule{
Name: "sca_rule",
- Criteria: *xrayUtils.CreateSeverityPolicyCriteria(severity),
+ Criteria: *xrayUtils.CreateSeverityPolicyCriteria(severity, skipNotApplicable),
Actions: getBuildFailAction(failBuild),
Priority: 1,
},
@@ -382,7 +372,7 @@ func CreateTestPolicyAndWatch(t *testing.T, policyName, watchName string, severi
Type: xrayUtils.Security,
Rules: []xrayUtils.PolicyRule{{
Name: "sec_rule",
- Criteria: *xrayUtils.CreateSeverityPolicyCriteria(severity),
+ Criteria: *xrayUtils.CreateSeverityPolicyCriteria(severity, false),
Priority: 1,
Actions: &xrayUtils.PolicyAction{
FailBuild: clientUtils.Pointer(true),
diff --git a/utils/results/common.go b/utils/results/common.go
index 1eb57635..a9c987f7 100644
--- a/utils/results/common.go
+++ b/utils/results/common.go
@@ -116,7 +116,7 @@ func ApplyHandlerToScaVulnerabilities(target ScanTarget, vulnerabilities []servi
return nil
}
-// ApplyHandlerToScaViolations allows to iterate over the provided SCA violations and call the provided handler for each impacted component/package with a violation to process it.
+// Allows to iterate over the provided SCA violations and call the provided handler for each impacted component/package with a violation to process it.
func ApplyHandlerToScaViolations(target ScanTarget, violations []services.Violation, entitledForJas bool, applicabilityRuns []*sarif.Run, securityHandler ParseScaViolationFunc, licenseHandler ParseScaViolationFunc, operationalRiskHandler ParseScaViolationFunc) (watches []string, failBuild bool, err error) {
if securityHandler == nil && licenseHandler == nil && operationalRiskHandler == nil {
return
@@ -145,6 +145,13 @@ func ApplyHandlerToScaViolations(target ScanTarget, violations []services.Violat
// No handler was provided for security violations
continue
}
+
+ var skipNotApplicable bool
+ if skipNotApplicable, err = shouldSkipNotApplicable(violation, applicabilityStatus); skipNotApplicable {
+ log.Debug("A non-applicable violation was found and will be removed from final results as requested by its policies")
+ continue
+ }
+
for compIndex := 0; compIndex < len(impactedPackagesNames); compIndex++ {
if e := securityHandler(
violation, cves, applicabilityStatus, severity,
@@ -645,3 +652,31 @@ func ScanResultsToRuns(results []ScanResult[[]*sarif.Run]) (runs []*sarif.Run) {
}
return
}
+
+// Resolve the actual technology from multiple sources:
+func GetIssueTechnology(responseTechnology string, targetTech techutils.Technology) techutils.Technology {
+ if responseTechnology != "" {
+ // technology returned in the vulnerability/violation obj is the most specific technology
+ return techutils.Technology(responseTechnology)
+ }
+ // if no technology is provided, use the target technology
+ return targetTech
+}
+
+// Checks if the violation's applicability status is NotApplicable and if all of its policies states that non-applicable CVEs should be skipped
+func shouldSkipNotApplicable(violation services.Violation, applicabilityStatus jasutils.ApplicabilityStatus) (bool, error) {
+ if applicabilityStatus != jasutils.NotApplicable {
+ return false, nil
+ }
+
+ if len(violation.Policies) == 0 {
+ return false, errors.New("A violation with no policies was provided")
+ }
+
+ for _, policy := range violation.Policies {
+ if !policy.SkipNotApplicable {
+ return false, nil
+ }
+ }
+ return true, nil
+}
diff --git a/utils/results/common_test.go b/utils/results/common_test.go
index f56b2036..6fc8da1e 100644
--- a/utils/results/common_test.go
+++ b/utils/results/common_test.go
@@ -701,3 +701,109 @@ func TestGetFinalApplicabilityStatus(t *testing.T) {
})
}
}
+
+func TestShouldSkipNotApplicable(t *testing.T) {
+ testCases := []struct {
+ name string
+ violation services.Violation
+ applicabilityStatus jasutils.ApplicabilityStatus
+ shouldSkip bool
+ errorExpected bool
+ }{
+ {
+ name: "Applicable CVE - should NOT skip",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.Applicable,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Undetermined CVE - should NOT skip",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.ApplicabilityUndetermined,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Not covered CVE - should NOT skip",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.NotCovered,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Missing Context CVE - should NOT skip",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.MissingContext,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Not scanned CVE - should NOT skip",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.NotScanned,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Non applicable CVE with skip-non-applicable in ALL policies - SHOULD skip",
+ violation: services.Violation{
+ Policies: []services.Policy{
+ {
+ Policy: "policy-1",
+ SkipNotApplicable: true,
+ },
+ {
+ Policy: "policy-2",
+ SkipNotApplicable: true,
+ },
+ },
+ },
+ applicabilityStatus: jasutils.NotApplicable,
+ shouldSkip: true,
+ errorExpected: false,
+ },
+ {
+ name: "Non applicable CVE with skip-non-applicable in SOME policies - should NOT skip",
+ violation: services.Violation{
+ Policies: []services.Policy{
+ {
+ Policy: "policy-1",
+ SkipNotApplicable: true,
+ },
+ {
+ Policy: "policy-2",
+ SkipNotApplicable: false,
+ },
+ },
+ },
+ applicabilityStatus: jasutils.NotApplicable,
+ shouldSkip: false,
+ errorExpected: false,
+ },
+ {
+ name: "Violation without policy - error expected",
+ violation: services.Violation{},
+ applicabilityStatus: jasutils.NotApplicable,
+ shouldSkip: false,
+ errorExpected: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ shouldSkip, err := shouldSkipNotApplicable(tc.violation, tc.applicabilityStatus)
+ if tc.errorExpected {
+ assert.Error(t, err)
+ } else {
+ assert.NoError(t, err)
+ }
+
+ if tc.shouldSkip {
+ assert.True(t, shouldSkip)
+ } else {
+ assert.False(t, shouldSkip)
+ }
+ })
+ }
+}
diff --git a/utils/results/conversion/convertor_test.go b/utils/results/conversion/convertor_test.go
index 540b6b2a..19a63f09 100644
--- a/utils/results/conversion/convertor_test.go
+++ b/utils/results/conversion/convertor_test.go
@@ -335,7 +335,7 @@ func getAuditTestResults(unique bool) (*results.SecurityCommandResults, validati
ScannedStatus: "completed",
})
// Contextual analysis scan results
- npmTargetResults.JasResults.NewApplicabilityScanResults(0,
+ npmTargetResults.JasResults.AddApplicabilityScanResults(0,
&sarif.Run{
Tool: sarif.Tool{
Driver: sarifutils.CreateDummyDriver(validations.ContextualAnalysisToolName,
@@ -537,7 +537,7 @@ func getDockerScanTestResults(unique bool) (*results.SecurityCommandResults, val
ScannedStatus: "completed",
})
// Contextual analysis scan results
- dockerImageTarget.JasResults.NewApplicabilityScanResults(0,
+ dockerImageTarget.JasResults.AddApplicabilityScanResults(0,
&sarif.Run{
Tool: sarif.Tool{
Driver: sarifutils.CreateDummyDriver(validations.ContextualAnalysisToolName,
diff --git a/utils/results/conversion/sarifparser/sarifparser.go b/utils/results/conversion/sarifparser/sarifparser.go
index f017ed73..fdf90dd3 100644
--- a/utils/results/conversion/sarifparser/sarifparser.go
+++ b/utils/results/conversion/sarifparser/sarifparser.go
@@ -649,7 +649,7 @@ func patchRules(platformBaseUrl string, commandType utils.CommandType, subScanTy
}
// Add analytics hidden pixel to the help content if needed (Github code scanning)
if analytics := getAnalyticsHiddenPixel(platformBaseUrl, subScanType); rule.Help != nil && analytics != "" {
- rule.Help.Markdown = utils.NewStringPtr(fmt.Sprintf("%s %s", sarifutils.GetRuleHelpMarkdown(rule), analytics))
+ rule.Help.Markdown = utils.NewStringPtr(fmt.Sprintf("%s\n%s", analytics, sarifutils.GetRuleHelpMarkdown(rule)))
}
patched = append(patched, rule)
}
@@ -936,7 +936,7 @@ func getAnalyticsHiddenPixel(baseUrl string, resultOfSubScan utils.SubScanType)
return fmt.Sprintf(
"![](%sui/api/v1/u?s=1&m=2&job_id=%s&run_id=%s&git_repo=%s&type=%s)",
baseUrl,
- url.PathEscape(jobId),
+ url.QueryEscape(jobId),
runId,
gitRepo,
resultOfSubScan.String(),
diff --git a/utils/results/conversion/sarifparser/sarifparser_test.go b/utils/results/conversion/sarifparser/sarifparser_test.go
index 498302db..3aa9bd93 100644
--- a/utils/results/conversion/sarifparser/sarifparser_test.go
+++ b/utils/results/conversion/sarifparser/sarifparser_test.go
@@ -371,7 +371,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) {
),
},
expectedResults: []*sarif.Run{
- sarifutils.CreateRunWithDummyResultsWithRuleInformation("", "", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)", wd,
+ sarifutils.CreateRunWithDummyResultsWithRuleInformation("", "", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)\nrule-markdown", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)\nrule-markdown", wd,
sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "eda26ae830c578197aeda65a82d7f093",
sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation(
sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation(filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml"))),
@@ -393,7 +393,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) {
),
},
expectedResults: []*sarif.Run{
- sarifutils.CreateRunWithDummyResultsWithRuleInformation("", "", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)", dockerfileDir,
+ sarifutils.CreateRunWithDummyResultsWithRuleInformation("", "", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)\nrule-markdown", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=sca)\nrule-markdown", dockerfileDir,
sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("some-msg\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha256): f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml")), "some-msg", jfrogFingerprintAlgorithmName, "8cbd7268a4d20f2358ba2667ebd18956",
sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "f752cb05a39e65f231a3c47c2e08cbeac1c15e4daff0188cb129c12a3ea3049d", "layer", "algorithm", "sha256").WithPhysicalLocation(
sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation("Dockerfile")),
@@ -436,7 +436,7 @@ func TestPatchRunsToPassIngestionRules(t *testing.T) {
}),
},
expectedResults: []*sarif.Run{
- sarifutils.CreateRunWithDummyResultsWithRuleInformation(BinarySecretScannerToolName, "[Secret in Binary found] ", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=secrets)", "rule-msg", "rule-markdown ![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=secrets)", wd,
+ sarifutils.CreateRunWithDummyResultsWithRuleInformation(BinarySecretScannerToolName, "[Secret in Binary found] ", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=secrets)\nrule-markdown", "rule-msg", "![](url/ui/api/v1/u?s=1&m=2&job_id=job-id&run_id=run-id&git_repo=repo&type=secrets)\nrule-markdown", wd,
sarifutils.CreateDummyResultWithFingerprint(fmt.Sprintf("🔒 Found Secrets in Binary docker scanning:\nGithub Actions Workflow: %s\nRun: 123\nImage: dockerImage:imageVersion\nLayer (sha1): 9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0\nFilepath: %s\nEvidence: snippet", filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml"), filepath.Join("usr", "src", "app", "server", "index.js")), "result-msg", jfrogFingerprintAlgorithmName, "e721eacf317da6090eca3522308abd28",
sarifutils.CreateDummyLocationWithPathAndLogicalLocation("", "9e88ea9de1b44baba5e96a79e33e4af64334b2bf129e838e12f6dae71b5c86f0", "layer", "algorithm", "sha1").WithPhysicalLocation(
sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewSimpleArtifactLocation(filepath.Join(GithubBaseWorkflowDir, "workflowFile.yml"))),
diff --git a/utils/results/conversion/simplejsonparser/simplejsonparser.go b/utils/results/conversion/simplejsonparser/simplejsonparser.go
index d2ac34b7..269c7706 100644
--- a/utils/results/conversion/simplejsonparser/simplejsonparser.go
+++ b/utils/results/conversion/simplejsonparser/simplejsonparser.go
@@ -10,7 +10,6 @@ import (
"github.com/jfrog/jfrog-cli-security/utils/jasutils"
"github.com/jfrog/jfrog-cli-security/utils/results"
"github.com/jfrog/jfrog-cli-security/utils/severityutils"
- "github.com/jfrog/jfrog-cli-security/utils/techutils"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/owenrumney/go-sarif/v2/sarif"
)
@@ -236,10 +235,6 @@ func PrepareSimpleJsonVulnerabilities(target results.ScanTarget, scaResponse ser
func addSimpleJsonVulnerability(target results.ScanTarget, vulnerabilitiesRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.ParseScaVulnerabilityFunc {
return func(vulnerability services.Vulnerability, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error {
- tech := target.Technology
- if tech == "" {
- tech = techutils.Technology(impactedPackagesType)
- }
*vulnerabilitiesRows = append(*vulnerabilitiesRows,
formats.VulnerabilityOrViolationRow{
Summary: vulnerability.Summary,
@@ -256,7 +251,7 @@ func addSimpleJsonVulnerability(target results.ScanTarget, vulnerabilitiesRows *
References: vulnerability.References,
JfrogResearchInformation: convertJfrogResearchInformation(vulnerability.ExtendedInformation),
ImpactPaths: impactPaths,
- Technology: tech,
+ Technology: results.GetIssueTechnology(vulnerability.Technology, target.Technology),
Applicable: applicabilityStatus.ToString(pretty),
},
)
@@ -266,10 +261,6 @@ func addSimpleJsonVulnerability(target results.ScanTarget, vulnerabilitiesRows *
func addSimpleJsonSecurityViolation(target results.ScanTarget, securityViolationsRows *[]formats.VulnerabilityOrViolationRow, pretty bool) results.ParseScaViolationFunc {
return func(violation services.Violation, cves []formats.CveRow, applicabilityStatus jasutils.ApplicabilityStatus, severity severityutils.Severity, impactedPackagesName, impactedPackagesVersion, impactedPackagesType string, fixedVersion []string, directComponents []formats.ComponentRow, impactPaths [][]formats.ComponentRow) error {
- tech := target.Technology
- if tech == "" {
- tech = techutils.Technology(impactedPackagesType)
- }
*securityViolationsRows = append(*securityViolationsRows,
formats.VulnerabilityOrViolationRow{
Summary: violation.Summary,
@@ -290,7 +281,7 @@ func addSimpleJsonSecurityViolation(target results.ScanTarget, securityViolation
References: violation.References,
JfrogResearchInformation: convertJfrogResearchInformation(violation.ExtendedInformation),
ImpactPaths: impactPaths,
- Technology: tech,
+ Technology: results.GetIssueTechnology(violation.Technology, target.Technology),
Applicable: applicabilityStatus.ToString(pretty),
},
)
diff --git a/utils/results/output/securityJobSummary.go b/utils/results/output/securityJobSummary.go
index dffc3106..4e95c27f 100644
--- a/utils/results/output/securityJobSummary.go
+++ b/utils/results/output/securityJobSummary.go
@@ -549,7 +549,8 @@ func addAnalyticsQueryParamsIfNeeded(platformUrl string, index commandsummary.In
// Not running in Github no need to add analytics
return platformUrl
}
- suffixValues := []string{fmt.Sprintf("gh_job_id=%s", url.PathEscape(githubJobId))}
+ // M=3 (type of event)
+ suffixValues := []string{"s=1", "m=3", fmt.Sprintf("gh_job_id=%s", url.QueryEscape(githubJobId))}
// Add section analytics
indexValue := "gh_section="
switch index {
@@ -561,7 +562,7 @@ func addAnalyticsQueryParamsIfNeeded(platformUrl string, index commandsummary.In
suffixValues = append(suffixValues, indexValue)
// Add the suffix to the url
if strings.Contains(platformUrl, "?") {
- return fmt.Sprintf("%s%s", platformUrl, strings.Join(suffixValues, "&"))
+ return fmt.Sprintf("%s&%s", platformUrl, strings.Join(suffixValues, "&"))
}
return fmt.Sprintf("%s?%s", platformUrl, strings.Join(suffixValues, "&"))
}
diff --git a/utils/results/results.go b/utils/results/results.go
index 925e58f8..0c3f2a6f 100644
--- a/utils/results/results.go
+++ b/utils/results/results.go
@@ -442,7 +442,7 @@ func (ssr *ScaScanResults) HasFindings() bool {
return false
}
-func (jsr *JasScansResults) NewApplicabilityScanResults(exitCode int, runs ...*sarif.Run) {
+func (jsr *JasScansResults) AddApplicabilityScanResults(exitCode int, runs ...*sarif.Run) {
jsr.ApplicabilityScanResults = append(jsr.ApplicabilityScanResults, ScanResult[[]*sarif.Run]{Scan: runs, StatusCode: exitCode})
}
diff --git a/xsc_test.go b/xsc_test.go
index 96f92eba..740afc15 100644
--- a/xsc_test.go
+++ b/xsc_test.go
@@ -3,6 +3,7 @@ package main
import (
"encoding/json"
"errors"
+ "os"
"path/filepath"
"testing"
@@ -30,7 +31,8 @@ import (
)
func TestReportError(t *testing.T) {
- xrayVersion, xscVersion, cleanUp := integration.InitXscTest(t, func() { securityTestUtils.ValidateXscVersion(t, xsc.MinXscVersionForErrorReport) })
+ xrayVersion, xscVersion, cleanUp := integration.InitXscTest(t)
+ securityTestUtils.ValidateXscVersion(t, xscVersion, xsc.MinXscVersionForErrorReport)
defer cleanUp()
errorToReport := errors.New("THIS IS NOT A REAL ERROR! This Error is posted as part of TestReportError test")
assert.NoError(t, xsc.ReportError(xrayVersion, xscVersion, tests.XscDetails, errorToReport, "cli"))
@@ -66,7 +68,7 @@ func TestXscAuditViolationsWithIgnoreRule(t *testing.T) {
_, cleanUpProject := securityTestUtils.CreateTestProjectEnvAndChdir(t, filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "projects", "jas", "jas"))
defer cleanUpProject()
// Create policy and watch for the git repo so we will also get violations (unknown = all vulnerabilities will be reported as violations)
- policyName, cleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "git-repo-ignore-rule-policy", utils.Unknown, true)
+ policyName, cleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "git-repo-ignore-rule-policy", utils.Unknown, true, false)
defer cleanUpPolicy()
_, cleanUpWatch := securityTestUtils.CreateWatchForTests(t, policyName, "git-repo-ignore-rule-watch", xscutils.GetGitRepoUrlKey(validations.TestMockGitInfo.GitRepoHttpsCloneUrl))
defer cleanUpWatch()
@@ -100,10 +102,63 @@ func TestXscAuditViolationsWithIgnoreRule(t *testing.T) {
validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{ExactResultsMatch: true, Total: &validations.TotalCount{}, Violations: &validations.ViolationCount{ValidateScan: &validations.ScanCount{}}})
}
+func TestXrayAuditJasSkipNotApplicableCvesViolations(t *testing.T) {
+ // Init XSC tests also enabled analytics reporting.
+ _, _, cleanUpXsc := integration.InitXscTest(t, func() { securityTestUtils.ValidateXrayVersion(t, services.MinXrayVersionGitRepoKey) })
+ defer cleanUpXsc()
+ // Create the audit command with git repo context injected.
+ cliToRun, cleanUpHome := integration.InitTestWithMockCommandOrParams(t, false, getAuditCommandWithXscGitContext(validations.TestMockGitInfo))
+ defer cleanUpHome()
+ // Create the project to scan
+ _, cleanUpProject := securityTestUtils.CreateTestProjectEnvAndChdir(t, filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "projects", "jas", "jas"))
+ defer cleanUpProject()
+ // Create policy and watch for the git repo so we will also get violations - This watch DO NOT skip not-applicable results
+ var firstPolicyCleaned, firstWatchCleaned bool
+ policyName, cleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "without-skip-non-applicable-policy", utils.Low, false, false)
+ defer func() {
+ if !firstPolicyCleaned {
+ cleanUpPolicy()
+ }
+ }()
+ watchName, cleanUpWatch := securityTestUtils.CreateWatchForTests(t, policyName, "without-skip-not-applicable-watch", xscutils.GetGitRepoUrlKey(validations.TestMockGitInfo.GitRepoHttpsCloneUrl))
+ defer func() {
+ if !firstWatchCleaned {
+ cleanUpWatch()
+ }
+ }()
+ // Run the audit command with git repo and verify violations are reported to the platform.
+ output, err := testAuditCommand(t, cliToRun, auditCommandTestParams{Format: string(format.SimpleJson), Watches: []string{watchName}, DisableFailOnFailedBuildFlag: true})
+ assert.NoError(t, err)
+ validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{
+ Violations: &validations.ViolationCount{ValidateScan: &validations.ScanCount{Sca: 17, Sast: 1, Secrets: 15}},
+ ExactResultsMatch: true,
+ })
+
+ // We clean the initially created Policy and Watch that are related to the Git Repo resource, because we must have all related policies with skipNotApplicable=true
+ cleanUpWatch()
+ firstWatchCleaned = true
+ cleanUpPolicy()
+ firstPolicyCleaned = true
+
+ // Create policy and watch for the git repo so we will also get violations - This watch DO NOT skip not-applicable results
+ skipPolicyName, skipCleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "skip-non-applicable-policy", utils.Low, false, true)
+ defer skipCleanUpPolicy()
+ skipWatchName, skipCleanUpWatch := securityTestUtils.CreateWatchForTests(t, skipPolicyName, "skip-not-applicable-watch", xscutils.GetGitRepoUrlKey(validations.TestMockGitInfo.GitRepoHttpsCloneUrl))
+ defer skipCleanUpWatch()
+ output, err = testAuditCommand(t, cliToRun, auditCommandTestParams{Format: string(format.SimpleJson), Watches: []string{skipWatchName}, DisableFailOnFailedBuildFlag: true})
+ assert.NoError(t, err)
+ validations.VerifySimpleJsonResults(t, output, validations.ValidationParams{
+ Violations: &validations.ViolationCount{ValidateScan: &validations.ScanCount{Sca: 12, Sast: 1, Secrets: 15}},
+ ExactResultsMatch: true,
+ })
+
+}
+
func TestAuditJasViolationsProjectKeySimpleJson(t *testing.T) {
_, _, cleanUpXsc := integration.InitXscTest(t, func() { securityTestUtils.ValidateXrayVersion(t, services.MinXrayVersionGitRepoKey) })
defer cleanUpXsc()
- if tests.TestJfrogPlatformProjectKeyEnvVar == "" {
+ testsJfrogPlatformProjectKey := os.Getenv(tests.TestJfrogPlatformProjectKeyEnvVar)
+ if testsJfrogPlatformProjectKey == "" {
t.Skipf("skipping test. %s is not set.", tests.TestJfrogPlatformProjectKeyEnvVar)
}
// Create the audit command with git repo context injected.
@@ -114,7 +169,7 @@ func TestAuditJasViolationsProjectKeySimpleJson(t *testing.T) {
_, cleanUpProject := securityTestUtils.CreateTestProjectEnvAndChdir(t, filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "projects", "jas", "jas"))
defer cleanUpProject()
// Create policy and watch for the project so we will get violations (unknown = all vulnerabilities will be reported as violations)
- policyName, cleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "project-key-jas-violations-policy", utils.Unknown, true)
+ policyName, cleanUpPolicy := securityTestUtils.CreateTestSecurityPolicy(t, "project-key-jas-violations-policy", utils.Unknown, true, false)
defer cleanUpPolicy()
_, cleanUpWatch := securityTestUtils.CreateTestProjectKeyWatch(t, policyName, "project-key-jas-violations-watch", *tests.JfrogTestProjectKey)
defer cleanUpWatch()