Skip to content

Commit

Permalink
Fill out results struct
Browse files Browse the repository at this point in the history
  • Loading branch information
kiwiz committed Mar 3, 2021
1 parent 80b8c53 commit fda5757
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 56 deletions.
169 changes: 143 additions & 26 deletions models/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,69 +2,186 @@ package models

// Result represents the results block in the sarif report
type Result struct {
Level string `json:"level"`
Message *textBlock `json:"message"`
RuleID string `json:"ruleId"`
RuleIndex int `json:"ruleIndex"`
Locations []*resultLocation `json:"locations,omitempty"`
Guid *string `json:"guid,omitempty"`
CorrelationGuid *string `json:"correlationGuid,omitempty"`
RuleID *string `json:"ruleId,omitempty"`
RuleIndex *uint `json:"ruleIndex,omitempty"`
Rule *reportingDescriptorReference `json:"rule,omitempty"`
Taxa []*reportingDescriptorReference `json:"taxa,omitempty"`
Kind *string `json:"kind,omitempty"`
Level *string `json:"level,omitempty"`
Message Message `json:"message"`
Locations []*location `json:"locations,omitempty"`
AnalysisTarget *artifactLocation `json:"analysisTarget,omitempty"`
// WebRequest *webRequest `json:"webRequest,omitempty"`
// WebResponse *webResponse `json:"webResponse,omitempty"`
Fingerprints map[string]interface{} `json:"fingerprints,omitempty"`
PartialFingerprints map[string]interface{} `json:"partialFingerprints,omitempty"`
// CodeFlows []*codeFlows `json:"codeFlows,omitempty"`
// Graphs []*graphs `json:"graphs,omitempty"`
// GraphTraversals []*graphTraversals `json:"graphTraversals,omitempty"`
// Stacks []*stack `json:"stacks,omitempty"`
RelatedLocations []*location `json:"relatedLocations,omitempty"`
Suppressions []*suppression `json:"suppressions,omitempty"`
BaselineState *string `json:"baselineState,omitempty"`
Rank *float32 `json:"rank,omitempty"`
// Attachments []*attachment `json:"attachments,omitempty"`
WorkItemUris []string `json:"workItemUris,omitempty"` // can be null
HostedViewerUri *string `json:"hostedViewerUri,omitempty"`
// Provenance *resultProvenance `json:"provenance,omitempty"`
Fixes []*fix `json:"fixes,omitempty"`
OccurrenceCount *uint `json:"occurrenceCount,omitempty"`
}

type resultLocation struct {
PhysicalLocation *physicalLocation `json:"physicalLocation,omitempty"`
type reportingDescriptorReference struct {
Id *string `json:"id,omitempty"`
Index *uint `json:"index,omitempty"`
Guid *string `json:"guid,omitempty"`
ToolComponent *toolComponentReference `json:"toolComponent,omitempty"`
}

type toolComponentReference struct {
Name *string `json:"name"`
Index *uint `json:"index"`
Guid *string `json:"guid"`
}

type Message struct {
Text *string `json:"text,omitempty"`
Markdown *string `json:"markdown,omitempty"`
Id *string `json:"id,omitempty"`
Arguments []string `json:"arguments,omitempty"`
}

type location struct {
Id *uint `json:"id,omitempty"`
PhysicalLocation *physicalLocation `json:"physicalLocation,omitempty"`
LogicalLocations []*logicalLocation `json:"logicalLocations,omitempty"`
Message *Message `json:"message,omitempty"`
Annotations []*region `json:"annotations,omitempty"`
Relationships []*locationRelationship `json:"relationships,omitempty"`
}

type physicalLocation struct {
ArtifactLocation *artifactLocation `json:"artifactLocation"`
Region *region `json:"region"`
ArtifactLocation *artifactLocation `json:"artifactLocation,omitempty"`
Region *region `json:"region,omitempty"`
ContextRegion *region `json:"contextRegion,omitempty"`
Address *address `json:"address,omitempty"`
}

type logicalLocation struct {
Index *uint `json:"index,omitempty"`
Name *string `json:"name,omitempty"`
FullyQualifiedName *string `json:"fullyQualifiedName,omitempty"`
DecoratedName *string `json:"decoratedName,omitempty"`
Kind *string `json:"kind,omitempty"`
ParentIndex *uint `json:"parentIndex,omitempty"`
}

type locationRelationship struct {
Target uint `json:"target"`
Kinds []string `json:"kinds,omitempty"`
Description *Message `json:"description,omitempty"`
}

type region struct {
StartLine int `json:"startLine"`
StartColumn int `json:"startColumn"`
StartLine *int `json:"startLine,omitempty"`
StartColumn *int `json:"startColumn,omitempty"`
EndLine *int `json:"endLine,omitempty"`
EndColumn *int `json:"endColumn,omitempty"`
CharOffset *int `json:"charOffset,omitempty"`
CharLength *int `json:"charLength,omitempty"`
ByteOffset *int `json:"byteOffset,omitempty"`
ByteLength *int `json:"byteLength,omitempty"`
Snippet *artifactContent `json:"snippet,omitempty"`
Message *Message `json:"message,omitempty"`
SourceLanguage *string `json:"sourceLanguage,omitempty"`
}

type artifactContent struct {
Text *string `json:"text,omitempty"`
Binary *string `json:"binary,omitempty"`
Rendered *multiformatMessageString `json:"rendered,omitempty"`
}

type multiformatMessageString struct {
Text string `json:"text"`
Markdown *string `json:"markdown,omitempty"`
}

type address struct {
Index *uint `json:"index,omitempty"`
AbsoluteAddress *uint `json:"absoluteAddress,omitempty"`
RelativeAddress *int `json:"relativeAddress,omitempty"`
OffsetFromParent *int `json:"offsetFromParent,omitempty"`
Length *int `json:"length,omitempty"`
Name *string `json:"name,omitempty"`
FullyQualifiedName *string `json:"fullyQualifiedName,omitempty"`
Kind *string `json:"kind,omitempty"`
ParentIndex *uint `json:"parentIndex,omitempty"`
}

type artifactLocation struct {
URI string `json:"uri"`
Index int `json:"index"`
URI *string `json:"uri,omitempty"`
URIBaseId *string `json:"uriBaseId,omitempty"`
Index *uint `json:"index,omitempty"`
Description *Message `json:"description,omitempty"`
}

type location struct {
URI string `json:"uri"`
type suppression struct {
Kind string `json:"kind"`
Status *string `json:"status"`
Location *location `json:"location"`
Guid *string `json:"guid"`
Justification *string `json:"justification"`
}

type fix struct {
Description *Message `json:"description,omitempty"`
ArtifactChanges []*artifactChange `json:"artifactChanges"` // required
}

type artifactChange struct {
ArtifactLocation artifactLocation `json:"artifactLocation"`
Replacements []*replacement `json:"replacements"` //required
}

type replacement struct {
DeletedRegion region `json:"deletedRegion"`
InsertedContent *artifactContent `json:"insertedContent,omitempty"`
}

func newRuleResult(ruleID string) *Result {
return &Result{
RuleID: ruleID,
RuleID: &ruleID,
}
}

// WithLevel specifies the level of the finding, error, warning for a result and returns the updated result
func (result *Result) WithLevel(level string) *Result {
result.Level = level
result.Level = &level
return result
}

// WithMessage specifies the message for a result and returns the updated result
func (result *Result) WithMessage(message string) *Result {
result.Message = &textBlock{
Text: message,
}
result.Message.Text = &message
return result
}

// WithLocationDetails specifies the location details of the Result and returns the update result
func (result *Result) WithLocationDetails(path string, startLine, startColumn int) *Result {
location := &physicalLocation{
physicalLocation := &physicalLocation{
ArtifactLocation: &artifactLocation{
URI: path,
URI: &path,
},
Region: &region{
StartLine: startLine,
StartColumn: startColumn,
StartLine: &startLine,
StartColumn: &startColumn,
},
}
result.Locations = append(result.Locations, &resultLocation{
PhysicalLocation: location,
result.Locations = append(result.Locations, &location{
PhysicalLocation: physicalLocation,
})
return result
}
61 changes: 35 additions & 26 deletions models/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,52 @@ import (

// Run type represents a run of a tool
type Run struct {
Tool *tool `json:"tool"`
Artifacts []*LocationWrapper `json:"artifacts,omitempty"`
Results []*Result `json:"results,omitempty"`
Tool tool `json:"tool"`
Artifacts []*artifact `json:"artifacts,omitempty"`
Results []*Result `json:"results"` // can be null
}

// LocationWrapper reprents the location details of a run
type LocationWrapper struct {
Location *location `json:"location,omitempty"`
type artifact struct {
Location *artifactLocation `json:"location,omitempty"`
ParentIndex *uint `json:"parentIndex,omitempty"`
Offset *uint `json:"offset"`
Length *uint `json:"length"`
Roles []string `json:"roles"`
MimeType *string `json:"mimeType"`
Contents *artifactContent `json:"contents"`
Encoding *string `json:"encoding"`
SourceLanguage *string `json:"sourceLanguage"`
Hashes map[string]string `json:"hashes"`
LastModifiedTimeUtc *string `json:"lastModifiedTimeUtc"`
Description *Message `json:"description"`
}

// NewRun allows the creation of a new Run
func NewRun(toolName, informationURI string) *Run {
tool := &tool{
Driver: &driver{
Name: toolName,
InformationURI: informationURI,
},
}
run := &Run{
Tool: tool,
Tool: tool{
Driver: &driver{
Name: toolName,
InformationURI: informationURI,
},
},
}
return run
}

// AddArtifact returns the index of an existing artefact, the newly added artifactLocation
func (run *Run) AddArtifact(artifactLocation string) int {
func (run *Run) AddArtifact(uri string) uint {
for i, l := range run.Artifacts {
if l.Location.URI == artifactLocation {
return i
if *l.Location.URI == uri {
return uint(i)
}
}
run.Artifacts = append(run.Artifacts, &LocationWrapper{
Location: &location{
URI: artifactLocation,
run.Artifacts = append(run.Artifacts, &artifact{
Location: &artifactLocation{
URI: &uri,
},
})
return len(run.Artifacts) - 1
return uint(len(run.Artifacts) - 1)
}

// AddRule returns an existing Rule for the ruleID or creates a new Rule and returns it
Expand All @@ -60,7 +69,7 @@ func (run *Run) AddRule(ruleID string) *Rule {
// AddResult returns an existing Result or creates a new one and returns it
func (run *Run) AddResult(ruleID string) *Result {
for _, result := range run.Results {
if result.RuleID == ruleID {
if *result.RuleID == ruleID {
return result
}
}
Expand All @@ -72,22 +81,22 @@ func (run *Run) AddResult(ruleID string) *Result {
// AddResultDetails adds rules to the driver and artifact locations if they are missing. It adds the result to the result block as well
func (run *Run) AddResultDetails(rule *Rule, result *Result, location string) {
ruleIndex := run.Tool.Driver.getOrCreateRule(rule)
result.RuleIndex = ruleIndex
result.RuleIndex = &ruleIndex
locationIndex := run.AddArtifact(location)
updateResultLocationIndex(result, location, locationIndex)
}

func updateResultLocationIndex(result *Result, location string, index int) {
func updateResultLocationIndex(result *Result, location string, index uint) {
for _, resultLocation := range result.Locations {
if resultLocation.PhysicalLocation.ArtifactLocation.URI == location {
resultLocation.PhysicalLocation.ArtifactLocation.Index = index
if *resultLocation.PhysicalLocation.ArtifactLocation.URI == location {
resultLocation.PhysicalLocation.ArtifactLocation.Index = &index
break
}
}
}

func (run *Run) GetRuleById(ruleId string) (*Rule, error) {
if run.Tool != nil || run.Tool.Driver != nil {
if run.Tool.Driver != nil {
for _, rule := range run.Tool.Driver.Rules {
if rule.ID == ruleId {
return rule, nil
Expand Down
6 changes: 3 additions & 3 deletions models/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ type Rule struct {
Properties map[string]string `json:"properties,omitempty"`
}

func (driver *driver) getOrCreateRule(rule *Rule) int {
func (driver *driver) getOrCreateRule(rule *Rule) uint {
for i, r := range driver.Rules {
if r.ID == rule.ID {
return i
return uint(i)
}
}
driver.Rules = append(driver.Rules, rule)
return len(driver.Rules) - 1
return uint(len(driver.Rules) - 1)
}

func newRule(ruleID string) *Rule {
Expand Down
3 changes: 2 additions & 1 deletion test/result_stage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ func createNewResultTest(t *testing.T) (*resultTest, *resultTest, *resultTest) {
}

func (rt *resultTest) aNewResult() {
id := "test-rule"
rt.result = &models.Result{
RuleID: "test-rule",
RuleID: &id,
}

rt.result.WithLevel("error").
Expand Down

0 comments on commit fda5757

Please sign in to comment.