Skip to content

Commit e738946

Browse files
author
Prashant Balachandran
committed
changes for sarif format
changing version of testify removed stretchr from go.sum correcting dependencies in go.mod changing function call to support older version of go
1 parent 1438e2e commit e738946

File tree

6 files changed

+173
-5
lines changed

6 files changed

+173
-5
lines changed

analyses/stackanalyses/controller.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ const (
4040
)
4141

4242
//StackAnalyses is main controller function for analyse command. This function is responsible for all communications between cmd and custom packages.
43-
func StackAnalyses(ctx context.Context, requestParams driver.RequestType, jsonOut bool, verboseOut bool) (bool, error) {
43+
44+
func StackAnalyses(ctx context.Context, requestParams driver.RequestType, jsonOut bool, verboseOut bool, sarifFmt bool) (bool, error) {
4445
log.Debug().Msgf("Executing StackAnalyses.")
4546
var hasVul bool
4647
matcher, err := GetMatcher(requestParams.RawManifestFile)
@@ -60,7 +61,13 @@ func StackAnalyses(ctx context.Context, requestParams driver.RequestType, jsonOu
6061
verboseEligible := getResponse.RegistrationStatus == RegisteredStatus
6162
showVerboseMsg := verboseOut && !verboseEligible
6263

63-
if verboseOut && verboseEligible {
64+
if verboseEligible && sarifFmt {
65+
hasVul, err = verbose.ProcessSarif(getResponse, mc.fileStats.RawFilePath)
66+
if err != nil {
67+
log.Fatal().Err(err)
68+
return hasVul, err
69+
}
70+
} else if verboseOut && verboseEligible {
6471
hasVul = verbose.ProcessVerbose(ctx, getResponse, jsonOut)
6572
} else {
6673
hasVul = summary.ProcessSummary(ctx, getResponse, jsonOut, showVerboseMsg)

analyses/verbose/helper.go

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"sort"
1010

1111
"github.com/fabric8-analytics/cli-tools/utils"
12-
1312
"github.com/fatih/color"
1413
"github.com/rs/zerolog/log"
1514

analyses/verbose/sarif_helper.go

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package verbose
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"github.com/fabric8-analytics/cli-tools/analyses/driver"
7+
"github.com/owenrumney/go-sarif/models"
8+
"github.com/owenrumney/go-sarif/sarif"
9+
"github.com/rs/zerolog/log"
10+
"io/ioutil"
11+
"os"
12+
"regexp"
13+
"strings"
14+
)
15+
16+
type RegexDependencyLocator struct {
17+
FileContent string
18+
Ecosystem string
19+
EndIndices []int
20+
DependencyNodeIndex []int
21+
}
22+
23+
func ProcessSarif(analysedResult *driver.GetResponseType, manifestFilePath string) (bool, error) {
24+
var hasVuln bool
25+
report, err := sarif.New(sarif.Version210)
26+
27+
if err != nil {
28+
log.Fatal().Msg("Error forming SARIF respose")
29+
return false, errors.New("unable to create SARIF file")
30+
}
31+
32+
run := report.AddRun("CRDA", "https://github.com/fabric8-analytics")
33+
34+
regexDependencyLocator := RegexDependencyLocator{}
35+
if len(analysedResult.AnalysedDeps) == 0 {
36+
log.Fatal().Msg("Dependencies have not been analysed")
37+
return false, errors.New("dependencies have not been analysed")
38+
}
39+
err = regexDependencyLocator.SetUp(manifestFilePath, analysedResult.AnalysedDeps[0].Ecosystem)
40+
41+
if err != nil {
42+
return false, errors.New("unable to setup dependency locator")
43+
}
44+
45+
manifestParts := strings.Split(manifestFilePath, string(os.PathSeparator))
46+
manifest := manifestParts[len(manifestParts) - 1]
47+
for _, dep := range analysedResult.AnalysedDeps {
48+
line, column := regexDependencyLocator.LocateDependency(dep.Name)
49+
for _, publicVuln := range dep.PublicVulnerabilities {
50+
addVulnToReport(run, publicVuln, manifest, line, column)
51+
hasVuln = true
52+
}
53+
for _, privateVuln := range dep.PrivateVulnerabilities {
54+
addVulnToReport(run, privateVuln, manifest, line, column)
55+
hasVuln = true
56+
}
57+
}
58+
59+
report.Write(os.Stdout)
60+
return hasVuln, nil
61+
}
62+
63+
func addVulnToReport(run *models.Run, vuln driver.VulnerabilitiesType, manifestFilePath string, line int, column int) {
64+
rule := run.AddRule(vuln.ID).
65+
WithHelpURI(vuln.URL).WithDescription(vuln.Title)
66+
67+
run.AddResult(rule.ID).
68+
WithMessage(vuln.Title).
69+
WithLevel(vuln.Severity).
70+
WithLocationDetails(manifestFilePath, line, column)
71+
}
72+
73+
74+
func (r *RegexDependencyLocator) SetUp(manifestFilePath string, ecosystem string) error{
75+
content, err := ioutil.ReadFile(manifestFilePath)
76+
if err != nil {
77+
log.Fatal().Msg("Unable to load manifest File " + manifestFilePath)
78+
return fmt.Errorf("unable to load manifest file %s" ,manifestFilePath)
79+
}
80+
81+
r.FileContent = string(content)
82+
r.Ecosystem = ecosystem
83+
newLineRegex, _ := regexp.Compile("\n")
84+
85+
lines := newLineRegex.FindAllStringIndex(r.FileContent, -1)
86+
r.EndIndices = make([]int, len(lines))
87+
// Finding the end index for each end of line
88+
for i, line := range lines {
89+
r.EndIndices[i] = line[1]
90+
}
91+
92+
dependenciesRegex, _ := regexp.Compile(getDependencyNodeRegex(r.Ecosystem))
93+
// Find the index for the start of the dependency node ( <dependencies> in case of pom.xml,
94+
// dependencies: in case of package.json)
95+
r.DependencyNodeIndex = dependenciesRegex.FindStringIndex(r.FileContent)
96+
97+
return nil
98+
99+
}
100+
101+
func (r *RegexDependencyLocator) LocateDependency(dependency string) (int, int){
102+
// In case of maven the dependency consists groupId and artifactID
103+
// Picking up the artifact ID as the dependency
104+
if r.Ecosystem == "maven" {
105+
dependencyParts := strings.Split(dependency, ":")
106+
dependency = dependencyParts[len(dependencyParts) - 1]
107+
}
108+
// Adding the actual dependency in to the dependency regex
109+
dependencyRegexStr := strings.Replace(getDependencyRegex(r.Ecosystem), "?", dependency, 1)
110+
dependencyRegex, _ := regexp.Compile(dependencyRegexStr)
111+
dependencyIndex := dependencyRegex.FindStringIndex(r.FileContent)
112+
113+
var lineNum int
114+
var column int
115+
116+
// Check if the dependency index is within the dependency node
117+
if r.DependencyNodeIndex[0] < dependencyIndex[0] && dependencyIndex[0] < r.DependencyNodeIndex[1] {
118+
for i, val := range r.EndIndices {
119+
// Getting the line num and column number of the dependency
120+
if val <= dependencyIndex[0] && dependencyIndex[0] < r.EndIndices[i+1] {
121+
lineNum = i + 2
122+
column = dependencyIndex[0] - val + 2
123+
break
124+
}
125+
}
126+
}
127+
return lineNum, column
128+
}
129+
130+
func getDependencyNodeRegex(ecosystem string) string{
131+
switch ecosystem {
132+
case "npm":
133+
return "\"dependencies\"[\\s]*:[\\s\n]*{[\\s\na-z\"\\d.,\\-:^]*}"
134+
case "maven":
135+
return "<dependencies[\\s\\n]*>[\\s]*[\\s\\n]*[<>!\\s\\w\\/${}\"\\d.,\\-:^]*<\\/dependencies[\\s\\n]*>"
136+
default:
137+
return "[\\s\\S]*"
138+
139+
}
140+
}
141+
142+
func getDependencyRegex(ecosystem string) string{
143+
switch ecosystem{
144+
case "npm":
145+
return "\"?\"[\\s]*:[\\s\n]*\"[\\d\\.^\\-\\w]*\""
146+
case "maven":
147+
return "?[\\s\\n]*<\\/artifactId[\\s\\n]*>"
148+
default:
149+
return "?[\\s]*=="
150+
151+
}
152+
}
153+

cmd/analyse.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
var jsonOut bool
1717
var verboseOut bool
18+
var sarifOut bool
1819

1920
// analyseCmd represents the analyse command
2021
var analyseCmd = &cobra.Command{
@@ -31,6 +32,7 @@ func init() {
3132
rootCmd.AddCommand(analyseCmd)
3233
analyseCmd.Flags().BoolVarP(&jsonOut, "json", "j", false, "Set output format to JSON.")
3334
analyseCmd.Flags().BoolVarP(&verboseOut, "verbose", "v", false, "Detailed Analyses Report.")
35+
analyseCmd.Flags().BoolVarP(&sarifOut, "sarif", "s", false, "Report in Sarif format.")
3436
}
3537

3638
// destructor deletes intermediary files used to have stack analyses
@@ -81,7 +83,7 @@ func runAnalyse(cmd *cobra.Command, args []string) error {
8183
fmt.Println("Analysing your Dependency Stack! Please wait...")
8284
}
8385
name := sa.GetManifestName(manifestPath)
84-
hasVul, err := sa.StackAnalyses(cmd.Context(), requestParams, jsonOut, verboseOut)
86+
hasVul, err := sa.StackAnalyses(cmd.Context(), requestParams, jsonOut, verboseOut, sarifOut)
8587
telemetry.SetManifest(cmd.Context(), name)
8688
if err != nil {
8789
telemetry.SetExitCode(cmd.Context(), 1)

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ require (
1111
github.com/mitchellh/go-homedir v1.1.0
1212
github.com/onsi/ginkgo v1.16.1
1313
github.com/onsi/gomega v1.11.0
14+
github.com/owenrumney/go-sarif v0.0.8
1415
github.com/pborman/uuid v1.2.1
1516
github.com/rs/zerolog v1.20.0
1617
github.com/segmentio/analytics-go v3.0.1+incompatible
1718
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
1819
github.com/spf13/cobra v1.1.1
1920
github.com/spf13/viper v1.7.1
20-
github.com/stretchr/testify v1.6.1
21+
github.com/stretchr/testify v1.7.0
2122
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
2223
gopkg.in/yaml.v2 v2.4.0
24+
2325
)

go.sum

+5
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
181181
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
182182
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
183183
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
184+
github.com/owenrumney/go-sarif v0.0.8 h1:rxNjz+/hm8s4+NUtq1mnvY5NbAr6RqppTzlT+QH2c28=
185+
github.com/owenrumney/go-sarif v0.0.8/go.mod h1:fcYnVdYRfXWB943S0WaZrjAMuoTEj7vqS7JpOMf6CG0=
184186
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
185187
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
186188
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
@@ -242,6 +244,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
242244
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
243245
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
244246
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
247+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
248+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
245249
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
246250
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
247251
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -362,6 +366,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
362366
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
363367
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
364368
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
369+
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
365370
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
366371
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
367372
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

0 commit comments

Comments
 (0)