Skip to content

Commit

Permalink
refactor: refactor the converter to use types from code-client-go [ID…
Browse files Browse the repository at this point in the history
…E-175]
  • Loading branch information
teodora-sandu committed Mar 8, 2024
1 parent c02c8ef commit af3e57b
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 275 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ require (
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/snyk/code-client-go v0.0.0-20240307112310-c7f3dbe6e197 // indirect
github.com/snyk/go-httpauth v0.0.0-20231117135515-eb445fea7530 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snyk/code-client-go v0.0.0-20240307112310-c7f3dbe6e197 h1:OkEvk6W5nu1nmNDGpzvIeNtB6WRWdkcWw+TuCVQkM84=
github.com/snyk/code-client-go v0.0.0-20240307112310-c7f3dbe6e197/go.mod h1:rQsizM39PmM9IVS+sYFdiky7qlreczjfwJLWcQZOU5w=
github.com/snyk/go-application-framework v0.0.0-20240111143643-fa847b8a9a3b h1:8fFjcaUZpjLV06AtIqtB7QRMYBH/5dxv2CJp319q2Gs=
github.com/snyk/go-application-framework v0.0.0-20240111143643-fa847b8a9a3b/go.mod h1:Yz/qxFyfhf0xbA+z8Vzr5IM9IDG+BS+2PiGaP1yAsEw=
github.com/snyk/go-httpauth v0.0.0-20231117135515-eb445fea7530 h1:s9PHNkL6ueYRiAKNfd8OVxlUOqU3qY0VDbgCD1f6WQY=
Expand Down
6 changes: 4 additions & 2 deletions infrastructure/code/backend_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"time"

"github.com/rs/zerolog/log"
codeClient "github.com/snyk/code-client-go"

"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/domain/observability/error_reporting"
Expand Down Expand Up @@ -370,7 +371,7 @@ func (s *SnykCodeHTTPClient) RunAnalysis(
return nil, failed, err
}

var response SarifResponse
var response codeClient.SarifResponse
err = json.Unmarshal(responseBody, &response)
if err != nil {
log.Err(err).Str("method", method).Str("responseBody", string(responseBody)).Msg("error unmarshalling")
Expand All @@ -396,7 +397,8 @@ func (s *SnykCodeHTTPClient) RunAnalysis(
return nil, status, nil
}

issues, err := response.toIssues(baseDir)
converter := SarifConverter{sarif: response}
issues, err := converter.toIssues(baseDir)
return issues, status, err
}

Expand Down
3 changes: 2 additions & 1 deletion infrastructure/code/backend_service_pact_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"

"github.com/pact-foundation/pact-go/dsl"
codeClient "github.com/snyk/code-client-go"
"github.com/stretchr/testify/assert"

"github.com/snyk/snyk-ls/application/config"
Expand Down Expand Up @@ -189,7 +190,7 @@ func TestSnykCodeBackendServicePact(t *testing.T) { // nolint:gocognit // this i
Headers: dsl.MapMatcher{
"Content-Type": dsl.String("application/json"),
},
Body: dsl.Match(SarifResponse{}),
Body: dsl.Match(codeClient.SarifResponse{}),
})

test := func() error {
Expand Down
135 changes: 70 additions & 65 deletions infrastructure/code/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"strings"

"github.com/rs/zerolog/log"
codeClient "github.com/snyk/code-client-go"
"golang.org/x/exp/slices"

"github.com/snyk/snyk-ls/domain/snyk"
Expand All @@ -45,14 +46,50 @@ func createRuleLink() (u *url.URL) {
return u
}

func (r *rule) getReferences() (references []snyk.Reference) {
for _, commit := range r.getExampleCommits() {
func issueSeverityToMarkdown(severity snyk.Severity) string {
switch severity {
case snyk.Critical:
return "🔥 Critical Severity"
case snyk.High:
return "🚨 High Severity"
case snyk.Medium:
return "⚠️ Medium Severity"
case snyk.Low:
return "⬇️ Low Severity"
default:
return "❔️ Unknown Severity"
}
}

func (c *exampleCommit) toReference() (reference snyk.Reference) {
commitURLString := c.fix.CommitURL
commitURL, err := url.Parse(commitURLString)
if err != nil {
log.Err(err).
Str("method", "code.toReference").
Str("commitURL", commitURLString).
Msgf("cannot parse commit url")
}
return snyk.Reference{Title: c.description, Url: commitURL}
}

func getIssueKey(ruleId string, path string, startLine int, endLine int, startCol int, endCol int) string {
id := sha256.Sum256([]byte(ruleId + path + strconv.Itoa(startLine) + strconv.Itoa(endLine) + strconv.Itoa(startCol) + strconv.Itoa(endCol)))
return hex.EncodeToString(id[:16])
}

type SarifConverter struct {
sarif codeClient.SarifResponse
}

func (s *SarifConverter) getReferences(r codeClient.Rule) (references []snyk.Reference) {
for _, commit := range s.getExampleCommits(r) {
references = append(references, commit.toReference())
}
return references
}

func (r *rule) getCodeIssueType() snyk.Type {
func (s *SarifConverter) getCodeIssueType(r codeClient.Rule) snyk.Type {
isSecurity := slices.ContainsFunc(r.Properties.Categories, func(category string) bool {
return strings.ToLower(category) == "security"
})
Expand All @@ -64,7 +101,7 @@ func (r *rule) getCodeIssueType() snyk.Type {
return snyk.CodeQualityIssue
}

func (r *rule) cwe() string {
func (s *SarifConverter) cwe(r codeClient.Rule) string {
count := len(r.Properties.Cwe)
if count == 0 {
return ""
Expand All @@ -89,19 +126,7 @@ func (r *rule) cwe() string {
return builder.String()
}

func (c *exampleCommit) toReference() (reference snyk.Reference) {
commitURLString := c.fix.CommitURL
commitURL, err := url.Parse(commitURLString)
if err != nil {
log.Err(err).
Str("method", "code.toReference").
Str("commitURL", commitURLString).
Msgf("cannot parse commit url")
}
return snyk.Reference{Title: c.description, Url: commitURL}
}

func (r *result) getCodeFlow(baseDir string) (dataflow []snyk.DataFlowElement) {
func (s *SarifConverter) getCodeFlow(r codeClient.Result, baseDir string) (dataflow []snyk.DataFlowElement) {
flows := r.CodeFlows
dedupMap := map[string]bool{}
for _, cFlow := range flows {
Expand Down Expand Up @@ -147,7 +172,7 @@ func (r *result) getCodeFlow(baseDir string) (dataflow []snyk.DataFlowElement) {
return dataflow
}

func (r *result) priorityScore() string {
func (s *SarifConverter) priorityScore(r codeClient.Result) string {
priorityScore := r.Properties.PriorityScore
if priorityScore == 0 {
return ""
Expand All @@ -158,67 +183,52 @@ func (r *result) priorityScore() string {
return builder.String()
}

func (r *rule) titleWithLeadingPipeOrEmpty() string {
func (s *SarifConverter) titleWithLeadingPipeOrEmpty(r codeClient.Rule) string {
if r.ShortDescription.Text != "" {
return fmt.Sprintf(" | %s", r.ShortDescription.Text)
}
return ""
}

func (r *rule) detailsOrEmpty() string {
func (s *SarifConverter) detailsOrEmpty(r codeClient.Rule) string {
details := r.Help.Markdown
if details != "" {
return regexp.MustCompile(`##\sDetails`).ReplaceAllString(details, "### Details")
}
return ""
}

func (r *result) formattedMessage(rule rule, baseDir string) string {
func (s *SarifConverter) formattedMessage(r codeClient.Result, rule codeClient.Rule, baseDir string) string {
const separator = "\n\n\n\n"
var builder strings.Builder
builder.Grow(500)
builder.WriteString(fmt.Sprintf("### %s", issueSeverityToMarkdown(issueSeverity(r.Level))))
builder.WriteString(rule.titleWithLeadingPipeOrEmpty())
builder.WriteString(r.priorityScore())
cwe := rule.cwe()
builder.WriteString(s.titleWithLeadingPipeOrEmpty(rule))
builder.WriteString(s.priorityScore(r))
cwe := s.cwe(rule)
if cwe != "" {
builder.WriteString(" | ")
}
builder.WriteString(cwe)
builder.WriteString(separator)
builder.WriteString(r.Message.Text)
builder.WriteString(separator)
builder.WriteString(rule.detailsOrEmpty())
builder.WriteString(s.detailsOrEmpty(rule))
builder.WriteString(separator)
builder.WriteString("### Data Flow\n\n")
for _, elem := range r.getCodeFlow(baseDir) {
for _, elem := range s.getCodeFlow(r, baseDir) {
builder.WriteString(elem.ToMarkDown())
}
builder.WriteString(separator)
builder.WriteString("### Example Commit Fixes\n\n")
for _, fix := range rule.getExampleCommits() {
for _, fix := range s.getExampleCommits(rule) {
builder.WriteString(fix.toMarkdown())
}
builder.WriteString(separator)
return builder.String()
}

func issueSeverityToMarkdown(severity snyk.Severity) string {
switch severity {
case snyk.Critical:
return "🔥 Critical Severity"
case snyk.High:
return "🚨 High Severity"
case snyk.Medium:
return "⚠️ Medium Severity"
case snyk.Low:
return "⬇️ Low Severity"
default:
return "❔️ Unknown Severity"
}
}

func (r *result) getMessage(rule rule) string {
func (s *SarifConverter) getMessage(r codeClient.Result, rule codeClient.Rule) string {
text := r.Message.Text
if rule.ShortDescription.Text != "" {
text = fmt.Sprintf("%s: %s", rule.ShortDescription.Text, text)
Expand All @@ -230,23 +240,23 @@ func (r *result) getMessage(rule rule) string {
return text
}

func (r *rule) getFixDescriptionsForRule(commitFixIndex int) string {
func (s *SarifConverter) getFixDescriptionsForRule(r codeClient.Rule, commitFixIndex int) string {
fixDescriptions := r.Properties.ExampleCommitDescriptions
if len(fixDescriptions) > commitFixIndex {
return fixDescriptions[commitFixIndex]
}
return ""
}

func (r *rule) getExampleCommits() (exampleCommits []exampleCommit) {
func (s *SarifConverter) getExampleCommits(r codeClient.Rule) (exampleCommits []exampleCommit) {
if len(r.Properties.ExampleCommitFixes) == 0 {
return exampleCommits
}
for i, fix := range r.Properties.ExampleCommitFixes {
exampleCommits = append(exampleCommits, exampleCommit{
index: i,
description: r.getFixDescriptionsForRule(i),
fix: exampleCommitFix{
description: s.getFixDescriptionsForRule(r, i),
fix: codeClient.ExampleCommitFix{
CommitURL: fix.CommitURL,
Lines: fix.Lines,
},
Expand All @@ -255,17 +265,17 @@ func (r *rule) getExampleCommits() (exampleCommits []exampleCommit) {
return exampleCommits
}

func (r *run) getRule(id string) rule {
func (s *SarifConverter) getRule(r codeClient.Run, id string) codeClient.Rule {
for _, r := range r.Tool.Driver.Rules {
if r.ID == id {
return r
}
}
return rule{}
return codeClient.Rule{}
}

func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error) {
runs := s.Sarif.Runs
func (s *SarifConverter) toIssues(baseDir string) (issues []snyk.Issue, err error) {
runs := s.sarif.Sarif.Runs
if len(runs) == 0 {
return issues, nil
}
Expand Down Expand Up @@ -306,11 +316,11 @@ func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error
},
}

rule := r.getRule(result.RuleID)
message := result.getMessage(rule)
formattedMessage := result.formattedMessage(rule, baseDir)
testRule := s.getRule(r, result.RuleID)
message := s.getMessage(result, testRule)
formattedMessage := s.formattedMessage(result, testRule, baseDir)

exampleCommits := rule.getExampleCommits()
exampleCommits := s.getExampleCommits(testRule)
exampleFixes := make([]snyk.ExampleCommitFix, 0, len(exampleCommits))
for _, commit := range exampleCommits {
commitURL := commit.fix.CommitURL
Expand All @@ -328,13 +338,13 @@ func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error
})
}

issueType := rule.getCodeIssueType()
issueType := s.getCodeIssueType(testRule)
isSecurityType := true
if issueType == snyk.CodeQualityIssue {
isSecurityType = false
}

markers, err := result.getMarkers(baseDir)
markers, err := s.getMarkers(result, baseDir)
errs = errors.Join(errs, err)

key := getIssueKey(result.RuleID, absPath, startLine, endLine, startCol, endCol)
Expand All @@ -359,7 +369,7 @@ func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error
IsSecurityType: isSecurityType,
IsAutofixable: result.Properties.IsAutofixable,
PriorityScore: result.Properties.PriorityScore,
DataFlow: result.getCodeFlow(baseDir),
DataFlow: s.getCodeFlow(result, baseDir),
}

d := snyk.Issue{
Expand All @@ -372,7 +382,7 @@ func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error
AffectedFilePath: absPath,
Product: product.ProductCode,
IssueDescriptionURL: ruleLink,
References: rule.getReferences(),
References: s.getReferences(testRule),
AdditionalData: additionalData,
CWEs: rule.Properties.Cwe,
}
Expand All @@ -383,12 +393,7 @@ func (s *SarifResponse) toIssues(baseDir string) (issues []snyk.Issue, err error
return issues, errs
}

func getIssueKey(ruleId string, path string, startLine int, endLine int, startCol int, endCol int) string {
id := sha256.Sum256([]byte(ruleId + path + strconv.Itoa(startLine) + strconv.Itoa(endLine) + strconv.Itoa(startCol) + strconv.Itoa(endCol)))
return hex.EncodeToString(id[:16])
}

func (r *result) getMarkers(baseDir string) ([]snyk.Marker, error) {
func (s *SarifConverter) getMarkers(r codeClient.Result, baseDir string) ([]snyk.Marker, error) {
markers := make([]snyk.Marker, 0)

// Example markdown string:
Expand Down
Loading

0 comments on commit af3e57b

Please sign in to comment.