Skip to content

Commit

Permalink
Support Sarif output (#4723)
Browse files Browse the repository at this point in the history
Co-authored-by: Fernandez Ludovic <[email protected]>
  • Loading branch information
SophisticaSean and ldez committed May 19, 2024
1 parent 73110df commit 4f5251d
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 1 deletion.
1 change: 1 addition & 0 deletions .golangci.next.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ output:
# - `junit-xml`
# - `github-actions`
# - `teamcity`
# - `sarif`
# Output path can be either `stdout`, `stderr` or path to the file to write to.
#
# For the CLI flag (`--out-format`), multiple formats can be specified by separating them by comma.
Expand Down
3 changes: 2 additions & 1 deletion jsonschema/golangci.next.jsonschema.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@
"code-climate",
"junit-xml",
"github-actions",
"teamcity"
"teamcity",
"sarif"
]
}
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/config/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
OutFormatJunitXML = "junit-xml"
OutFormatGithubActions = "github-actions"
OutFormatTeamCity = "teamcity"
OutFormatSarif = "sarif"
)

var AllOutputFormats = []string{
Expand All @@ -33,6 +34,7 @@ var AllOutputFormats = []string{
OutFormatJunitXML,
OutFormatGithubActions,
OutFormatTeamCity,
OutFormatSarif,
}

type Output struct {
Expand Down
2 changes: 2 additions & 0 deletions pkg/printers/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ func (c *Printer) createPrinter(format string, w io.Writer) (issuePrinter, error
p = NewGitHubAction(w)
case config.OutFormatTeamCity:
p = NewTeamCity(w)
case config.OutFormatSarif:
p = NewSarif(w)
default:
return nil, fmt.Errorf("unknown output format %q", format)
}
Expand Down
109 changes: 109 additions & 0 deletions pkg/printers/sarif.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package printers

import (
"encoding/json"
"io"

"github.com/golangci/golangci-lint/pkg/result"
)

const (
sarifVersion = "2.1.0"
sarifSchemaURI = "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json"
)

type SarifOutput struct {
Version string `json:"version"`
Schema string `json:"$schema"`
Runs []sarifRun `json:"runs"`
}

type sarifRun struct {
Tool sarifTool `json:"tool"`
Results []sarifResult `json:"results"`
}

type sarifTool struct {
Driver struct {
Name string `json:"name"`
} `json:"driver"`
}

type sarifResult struct {
RuleID string `json:"ruleId"`
Level string `json:"level"`
Message sarifMessage `json:"message"`
Locations []sarifLocation `json:"locations"`
}

type sarifMessage struct {
Text string `json:"text"`
}

type sarifLocation struct {
PhysicalLocation sarifPhysicalLocation `json:"physicalLocation"`
}

type sarifPhysicalLocation struct {
ArtifactLocation sarifArtifactLocation `json:"artifactLocation"`
Region sarifRegion `json:"region"`
}

type sarifArtifactLocation struct {
URI string `json:"uri"`
Index int `json:"index"`
}

type sarifRegion struct {
StartLine int `json:"startLine"`
StartColumn int `json:"startColumn"`
}

type Sarif struct {
w io.Writer
}

func NewSarif(w io.Writer) *Sarif {
return &Sarif{w: w}
}

func (p Sarif) Print(issues []result.Issue) error {
run := sarifRun{}
run.Tool.Driver.Name = "golangci-lint"

for i := range issues {
issue := issues[i]

severity := issue.Severity
if severity == "" {
severity = "error"
}

sr := sarifResult{
RuleID: issue.FromLinter,
Level: severity,
Message: sarifMessage{Text: issue.Text},
Locations: []sarifLocation{
{
PhysicalLocation: sarifPhysicalLocation{
ArtifactLocation: sarifArtifactLocation{URI: issue.FilePath()},
Region: sarifRegion{
StartLine: issue.Line(),
StartColumn: issue.Column(),
},
},
},
},
}

run.Results = append(run.Results, sr)
}

output := SarifOutput{
Version: sarifVersion,
Schema: sarifSchemaURI,
Runs: []sarifRun{run},
}

return json.NewEncoder(p.w).Encode(output)
}
67 changes: 67 additions & 0 deletions pkg/printers/sarif_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package printers

import (
"bytes"
"go/token"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/golangci/golangci-lint/pkg/result"
)

func TestSarif_Print(t *testing.T) {
issues := []result.Issue{
{
FromLinter: "linter-a",
Severity: "warning",
Text: "some issue",
Pos: token.Position{
Filename: "path/to/filea.go",
Offset: 2,
Line: 10,
Column: 4,
},
},
{
FromLinter: "linter-b",
Severity: "error",
Text: "another issue",
SourceLines: []string{
"func foo() {",
"\tfmt.Println(\"bar\")",
"}",
},
Pos: token.Position{
Filename: "path/to/fileb.go",
Offset: 5,
Line: 300,
Column: 9,
},
},
{
FromLinter: "linter-a",
Severity: "error",
Text: "some issue 2",
Pos: token.Position{
Filename: "path/to/filec.go",
Offset: 3,
Line: 11,
Column: 5,
},
},
}

buf := new(bytes.Buffer)

printer := NewSarif(buf)

err := printer.Print(issues)
require.NoError(t, err)

expected := `{"version":"2.1.0","$schema":"https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json","runs":[{"tool":{"driver":{"name":"golangci-lint"}},"results":[{"ruleId":"linter-a","level":"warning","message":{"text":"some issue"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"path/to/filea.go","index":0},"region":{"startLine":10,"startColumn":4}}}]},{"ruleId":"linter-b","level":"error","message":{"text":"another issue"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"path/to/fileb.go","index":0},"region":{"startLine":300,"startColumn":9}}}]},{"ruleId":"linter-a","level":"error","message":{"text":"some issue 2"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"path/to/filec.go","index":0},"region":{"startLine":11,"startColumn":5}}}]}]}]}
`

assert.Equal(t, expected, buf.String())
}

0 comments on commit 4f5251d

Please sign in to comment.