diff --git a/cmd/kube-score/main.go b/cmd/kube-score/main.go index 920ae6cf..eebadcdc 100644 --- a/cmd/kube-score/main.go +++ b/cmd/kube-score/main.go @@ -225,7 +225,10 @@ Use "-" as filename to read from STDIN.`, execName(binName)) case *outputFormat == "ci" && version == "v1": r = ci.CI(scoreCard) case *outputFormat == "sarif": - r = sarif.Output(scoreCard) + err, r = sarif.Output(scoreCard) + if err != nil { + return err + } default: return fmt.Errorf("error: Unknown --output-format or --output-version") } diff --git a/go.mod b/go.mod index e428a4b2..46dacbbd 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ require ( github.com/eidolon/wordwrap v0.0.0-20161011182207-e0f54129b8bb github.com/fatih/color v1.13.0 github.com/google/go-cmp v0.5.8 + github.com/owenrumney/go-sarif v1.1.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.7.1 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 diff --git a/go.sum b/go.sum index 80755bc5..112a9622 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -38,7 +39,9 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -101,6 +104,8 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE= +github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -115,9 +120,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= +github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -134,9 +143,11 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -175,6 +186,7 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX 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= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -193,6 +205,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= diff --git a/renderer/sarif/sarif.go b/renderer/sarif/sarif.go index d784133e..f98d6164 100644 --- a/renderer/sarif/sarif.go +++ b/renderer/sarif/sarif.go @@ -6,25 +6,21 @@ import ( "io" "github.com/zegl/kube-score/domain" - "github.com/zegl/kube-score/sarif" "github.com/zegl/kube-score/scorecard" + + "github.com/owenrumney/go-sarif/sarif" ) -func Output(input *scorecard.Scorecard) io.Reader { - var results []sarif.Results - var rules []sarif.Rules +func Output(input *scorecard.Scorecard) (error, io.Reader) { + report, err := sarif.New(sarif.Version210) + if err != nil { + return err, nil + } - addRule := func(check domain.Check) { - for _, r := range rules { - if r.ID == check.ID { - return - } - } + run := sarif.NewRun("kube-score", "https://kube-score.com/") - rules = append(rules, sarif.Rules{ - ID: check.ID, - Name: check.Name, - }) + addRule := func(check domain.Check) { + run.AddRule(check.ID).WithDescription(check.Name) } for _, v := range *input { @@ -45,52 +41,37 @@ func Output(input *scorecard.Scorecard) io.Reader { addRule(check.Check) + pb := sarif.NewPropertyBag() + pb.Add("confidence", "High") + pb.Add("severity", "High") + for _, comment := range check.Comments { - results = append(results, sarif.Results{ - Message: sarif.Message{ - Text: comment.Summary, - }, - RuleID: check.Check.ID, - Level: level, - Properties: sarif.ResultsProperties{ - IssueConfidence: "HIGH", - IssueSeverity: "HIGH", - }, - Locations: []sarif.Locations{ - { - PhysicalLocation: sarif.PhysicalLocation{ - ArtifactLocation: sarif.ArtifactLocation{ - URI: "file://" + v.FileLocation.Name, - }, - ContextRegion: sarif.ContextRegion{ - StartLine: v.FileLocation.Line, - }, - }, - }, - }, - }) + run.AddResult(check.Check.ID). + WithLevel(level). + WithMessage(sarif.NewTextMessage(comment.Summary)). + WithProperties(pb.Properties). + WithLocation( + sarif.NewLocationWithPhysicalLocation( + sarif.NewPhysicalLocation(). + WithArtifactLocation( + sarif.NewSimpleArtifactLocation("file://" + v.FileLocation.Name), + ).WithRegion( + sarif.NewSimpleRegion( + v.FileLocation.Line, + v.FileLocation.Line, + ), + ), + ), + ) } } } - run := sarif.Run{ - Tool: sarif.Tool{ - Driver: sarif.Driver{ - Name: "kube-score", - Rules: rules, - }, - }, - Results: results, - } - res := sarif.Sarif{ - Runs: []sarif.Run{run}, - Version: "2.1.0", - Schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json", - } + report.AddRun(run) - j, err := json.MarshalIndent(res, "", " ") + j, err := json.MarshalIndent(report, "", " ") if err != nil { - panic(err) + return err, nil } - return bytes.NewBuffer(j) + return nil, bytes.NewBuffer(j) } diff --git a/sarif/sarif.go b/sarif/sarif.go deleted file mode 100644 index 7746c023..00000000 --- a/sarif/sarif.go +++ /dev/null @@ -1,107 +0,0 @@ -package sarif - -import ( - "time" -) - -type Sarif struct { - Runs []Run `json:"runs,omitempty"` - Version string `json:"version,omitempty"` - Schema string `json:"$schema,omitempty"` -} - -type Rules struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - HelpURI string `json:"helpUri,omitempty"` -} - -type Driver struct { - Name string `json:"name,omitempty"` - Rules []Rules `json:"rules,omitempty"` -} - -type Tool struct { - Driver Driver `json:"driver,omitempty"` -} - -type WorkingDirectory struct { - URI string `json:"uri,omitempty"` -} - -type Invocation struct { - Arguments []string `json:"arguments,omitempty"` - ExecutionSuccessful bool `json:"executionSuccessful,omitempty"` - CommandLine string `json:"commandLine,omitempty"` - EndTimeUtc time.Time `json:"endTimeUtc,omitempty"` - WorkingDirectory WorkingDirectory `json:"workingDirectory,omitempty"` -} - -type Conversion struct { - Tool Tool `json:"tool,omitempty"` - Invocation Invocation `json:"invocation,omitempty"` -} - -type Invocations struct { - ExecutionSuccessful bool `json:"executionSuccessful,omitempty"` - EndTimeUtc time.Time `json:"endTimeUtc,omitempty"` - WorkingDirectory WorkingDirectory `json:"workingDirectory,omitempty"` -} - -type Properties struct { -} - -type Message struct { - Text string `json:"text,omitempty"` -} - -type Snippet struct { - Text string `json:"text,omitempty"` -} - -type Region struct { - Snippet Snippet `json:"snippet,omitempty"` - StartLine int `json:"startLine,omitempty"` -} - -type ArtifactLocation struct { - URI string `json:"uri,omitempty"` -} - -type ContextRegion struct { - Snippet Snippet `json:"snippet,omitempty"` - EndLine int `json:"endLine,omitempty"` - StartLine int `json:"startLine,omitempty"` -} - -type PhysicalLocation struct { - Region Region `json:"region,omitempty"` - ArtifactLocation ArtifactLocation `json:"artifactLocation,omitempty"` - ContextRegion ContextRegion `json:"contextRegion,omitempty"` -} - -type Locations struct { - PhysicalLocation PhysicalLocation `json:"physicalLocation,omitempty"` -} - -type ResultsProperties struct { - IssueConfidence string `json:"issue_confidence,omitempty"` - IssueSeverity string `json:"issue_severity,omitempty"` -} - -type Results struct { - Message Message `json:"message,omitempty"` - Level string `json:"level,omitempty"` - Locations []Locations `json:"locations,omitempty"` - Properties ResultsProperties `json:"properties,omitempty"` - RuleID string `json:"ruleId,omitempty"` - RuleIndex int `json:"ruleIndex,omitempty"` -} - -type Run struct { - Tool Tool `json:"tool,omitempty"` - Conversion Conversion `json:"conversion,omitempty"` - Invocations []Invocations `json:"invocations,omitempty"` - Properties Properties `json:"properties,omitempty"` - Results []Results `json:"results,omitempty"` -}